unity-lighting-vfx
Installation
SKILL.md
Unity Lighting and Visual Effects
Lighting Modes
Unity provides three light modes controlling how illumination is calculated.
Realtime Lights
- Calculate lighting every frame at runtime
- Allow dynamic changes to intensity, color, position
- Cast shadows up to Shadow Distance
- Contribute only direct lighting by default (no bounced light)
- Higher runtime cost, especially in complex scenes or low-end hardware
- Best for: dynamic objects, flickering effects, moving light sources
Baked Lights
- Calculations performed in the Unity Editor and saved as lighting data to disk
- At runtime, Unity loads pre-computed data instead of calculating dynamically
- Bake both direct and indirect lighting into lightmaps
- Store information in Light Probes for moving objects
- Cannot modify light properties at runtime; do not illuminate dynamic GameObjects
- No specular contributions
- Best for: static scenery, complex indirect lighting, performance-critical scenarios
Mixed Lights
- Combine baked indirect lighting with real-time direct lighting
- Behavior depends on the Lighting Mode setting in the Lighting window
- Cast real-time shadows (not baked soft shadows)
- Can change properties at runtime (affects real-time component only)
- Always more expensive than fully baked lighting
- Best for: dynamic shadows with baked background lighting
Important: All baked/mixed modes require Baked Global Illumination enabled. Without it, Mixed and Baked lights behave as Realtime.
Light Types
Directional Light
- Located infinitely far away, emits light in one direction
- Parallel rays, no distance-based intensity falloff
- Simulates sun/moon; every new scene includes one by default
- Links to procedural sky system; rotate to create time-of-day effects
Point Light
- Located at a point, emits in all directions equally
- Intensity follows inverse square law (diminishes with distance squared)
- Use for lamps, explosions, local illumination
Spot Light
- Located at a point, emits in a cone shape
- Adjustable cone angle; light diminishes at edges (penumbra)
- Wider angles create larger fade areas
- Use for flashlights, headlights, searchlights
Area Light
- Defined by a rectangle or disc; emits uniformly across surface
- Follows inverse square law; produces soft, subtle shading
- Bake-only -- not available at runtime
- Use for street lights, realistic interior lighting
Global Illumination
Global illumination (GI) simulates how light bounces between surfaces, producing realistic indirect lighting.
Baked GI
- Pre-computes indirect lighting into lightmaps using the Progressive Lightmapper (CPU or GPU)
- Results stored in lightmap textures and Light Probes
- Configure in the Lighting window under Bake settings
- GPU Progressive Lightmapper offers faster bake times with configurable tile sizes
Environment Lighting
Three ambient light sources configured in the Lighting window Environment tab:
- Skybox: Uses skybox material colors for ambient light from different angles
- Gradient: Separate sky, horizon, and ground colors with smooth blending
- Color: Uniform ambient light across the scene
Intensity Multiplier (0-8, default 1) controls ambient brightness.
Environment Reflections
- Source: Skybox or custom Cubemap/RenderTexture
- Configurable resolution, compression, intensity multiplier
- Bounces setting controls reflection evaluation iterations between objects
Light Probes and Adaptive Probe Volumes
Light Probes
- Capture lighting information in empty space throughout a scene
- At runtime, indirect lighting for dynamic GameObjects is approximated using nearest probes
- Provide indirect bounced light for moving objects and LOD system support
- Must be manually placed using Light Probe Groups
- Store baked lighting information; work with both direct and indirect lighting
Adaptive Probe Volumes (APV)
APV is the modern replacement for manual Light Probe placement in URP:
- Automated probe placement -- eliminates manual Light Probe Group positioning
- Per-pixel lighting -- superior quality compared to per-object approaches
- Scene baking -- bake multiple scenes together using Baking Sets
- Runtime adjustments -- Lighting Scenarios and sky occlusion for dynamic changes
- Large-world support -- streaming data for expansive open-world environments
- Data flexibility -- loading from AssetBundles or Addressables
- Configurable probe density and volume size with visualization tools
Reflection Probes
Capture a spherical view of surroundings as a cubemap for reflective materials.
Types
| Type | Description |
|---|---|
| Baked | Captures static GameObjects only; best performance |
| Custom | Allows dynamic object capture with custom textures |
| Realtime | Updates during gameplay; configurable refresh mode |
Key Properties
- Importance: Rendering priority when multiple probes overlap
- Intensity: Texture brightness in shader calculations
- Box Projection: Enables projection mapping for interiors (requires URP config)
- Box Size/Offset: World-space bounding box for reflection contribution
- Blend Distance: Blending distance for deferred probes
Realtime Options
- Refresh Mode: On Awake, Every Frame, or Via Scripting
- Time Slicing: All Faces At Once, Individual Faces, No Time Slicing
Particle System vs VFX Graph
| Feature | Particle System | VFX Graph |
|---|---|---|
| Simulation | CPU-based | GPU-based |
| Particle count | Thousands | Millions |
| Render pipeline | All pipelines | URP/HDRP only |
| Authoring | Inspector modules | Node-based graph editor |
| Physics | Built-in collision | Custom collision blocks |
| Scripting | Full C# API | Event-based C# API |
| Sub-emitters | Native support | GPU Event contexts |
| Best for | Small/medium effects, mobile | Large-scale effects, high-end |
Decision Guide:
- Use Particle System for mobile targets, simple effects, when you need full CPU-side scripting control, or when targeting the Built-in Render Pipeline
- Use VFX Graph for massive particle counts, GPU-driven simulations, complex node-based authoring, or high-end platforms with URP/HDRP
Particle System Modules
| Module | Purpose |
|---|---|
| Main | Initial state: lifetime, speed, size, gravity, simulation space |
| Emission | Rate and timing of particle spawns |
| Shape | Volume/surface for emission and start velocity direction |
| Velocity over Lifetime | Modify movement over particle age |
| Noise | Turbulence for organic, chaotic motion |
| Limit Velocity over Lifetime | Natural deceleration |
| Force over Lifetime | Simulated physics forces |
| Inherit Velocity | Sub-emitter particles match parent velocity |
| Lifetime by Emitter Speed | Adjust lifespan based on emitter velocity |
| Color over Lifetime / by Speed | Color changes based on age or velocity |
| Size over Lifetime / by Speed | Dimension changes based on time or speed |
| Rotation over Lifetime / by Speed | Orientation changes |
| Collision | Particle collisions with scene geometry |
| Triggers | Designate particles as collision triggers |
| Sub Emitters | Particles that emit other particles |
| Texture Sheet Animation | Texture grid animation frames |
| Trails | Motion trail rendering |
| Lights | Real-time lights on particles |
| External Forces | Wind zones and force fields |
| Renderer | Image/mesh transform, shading, overdraw |
| Custom Data | Attach custom data to particles |
VFX Graph Basics
Systems
- Spawn System: Single Spawn Context managing emission
- Particle System: Initialize -> Update -> Output succession
- Mesh Output System: Single Mesh Output Context
Contexts
- Spawn: Executes each frame to calculate spawn amounts. States: Running, Idle, Waiting. Configurable loop duration, count, and delays
- Initialize: Runs at particle birth, sets initial state. Processes Blocks for newly spawned particles. Configurable bounds and capacity
- Update: Per-frame for all living particles. Automatic: position integration, rotation integration, aging, reaping
- Output: Renders particles (Quad, Mesh, etc.). No output ports. Customizable rendering blocks
Graph Elements
- Blocks: Stackable nodes within Contexts; each handles one operation; top-to-bottom execution
- Operators: Low-level property workflow nodes connecting to Block/Context ports
- Properties: Connectable via property workflow
- Settings: Non-connectable editable values per Context
GPU Events
Experimental feature where GPU computes events (vs CPU for normal events). Cannot be customized with Blocks.
Common Patterns (C#)
Create and Configure a Light
using UnityEngine;
public class LightSetup : MonoBehaviour
{
void Start()
{
GameObject lightObj = new GameObject("Dynamic Light");
Light light = lightObj.AddComponent<Light>();
light.type = LightType.Point;
light.color = Color.yellow;
light.intensity = 2.0f;
light.range = 15f;
light.shadows = LightShadows.Soft;
light.shadowResolution = UnityEngine.Rendering.LightShadowResolution.Medium;
}
}
Create a Realtime Reflection Probe
using UnityEngine;
using UnityEngine.Rendering;
public class ProbeSetup : MonoBehaviour
{
void Start()
{
GameObject probeObj = new GameObject("Realtime Reflection Probe");
ReflectionProbe probe = probeObj.AddComponent<ReflectionProbe>();
probe.size = new Vector3(10, 10, 10);
probe.mode = ReflectionProbeMode.Realtime;
probe.refreshMode = ReflectionProbeRefreshMode.EveryFrame;
probe.resolution = 256;
probe.hdr = true;
}
}
Control Particle System at Runtime
using UnityEngine;
public class ParticleController : MonoBehaviour
{
ParticleSystem ps;
void Start()
{
ps = GetComponent<ParticleSystem>();
// Modify emission rate -- cache module in local variable first
var emission = ps.emission;
emission.rateOverTimeMultiplier = 50f;
// Modify main module
var main = ps.main;
main.startLifetime = 3f;
main.startSpeed = 5f;
main.simulationSpace = ParticleSystemSimulationSpace.World;
}
void OnTriggerEnter(Collider other)
{
// Burst emit particles
ps.Emit(100);
}
void OnDisable()
{
ps.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear);
}
}
VFX Graph Runtime Control
using UnityEngine;
using UnityEngine.VFX;
public class VFXController : MonoBehaviour
{
VisualEffect vfx;
VFXEventAttribute eventAttr;
void Start()
{
vfx = GetComponent<VisualEffect>();
eventAttr = vfx.CreateVFXEventAttribute();
// Set exposed properties
vfx.SetFloat("SpawnRate", 100f);
vfx.SetVector3("Direction", Vector3.up);
vfx.playRate = 1.5f;
}
void OnTriggerEnter(Collider other)
{
// Send custom event with attributes
eventAttr.SetVector3("position", other.transform.position);
vfx.SendEvent("OnHit", eventAttr);
}
public void StopEffect()
{
vfx.Stop();
}
}
Refresh Reflection Probe on Demand
using UnityEngine;
public class ProbeRefresher : MonoBehaviour
{
ReflectionProbe probe;
void Start()
{
probe = GetComponent<ReflectionProbe>();
probe.refreshMode = UnityEngine.Rendering.ReflectionProbeRefreshMode.ViaScripting;
}
public void RefreshReflections()
{
probe.RenderProbe();
}
public bool IsReady()
{
return probe.IsFinishedRendering(probe.RenderProbe());
}
}
Anti-Patterns
Lighting Anti-Patterns
- Too many Realtime lights: Each realtime light adds per-frame cost. Use Baked or Mixed for static lights
- Forgetting to enable Baked Global Illumination: Mixed/Baked lights silently fall back to Realtime without it
- Overlapping Reflection Probes without Importance values: Causes flickering; always set Importance to establish priority
- Using Area Lights expecting runtime behavior: Area lights are bake-only; they produce no light at runtime
- Ignoring Indirect Multiplier: Leaving at default can cause over-bright or too-dark bounced light; tune per light
- Not setting Shadow Bias correctly: Too low causes self-shadowing artifacts (shadow acne); too high causes peter-panning (shadows detach from objects)
- Manual Light Probe placement in large scenes: Use Adaptive Probe Volumes (APV) in URP instead for automated, per-pixel quality
Particle System Anti-Patterns
- Not caching module references: Each property access on a module struct immediately writes to native code; cache the module variable
- Using World simulation space for attached effects: Particles drift away from moving parents; use Local space for attached FX
- Excessive particle counts on CPU: Particle System is CPU-bound; for >10K particles, consider VFX Graph
- Forgetting to Stop/Clear: Leaked particle systems consume CPU even when invisible
VFX Graph Anti-Patterns
- Using VFX Graph for simple effects on mobile: GPU overhead and URP/HDRP requirement make it overkill for simple mobile effects
- Not setting Capacity in Initialize: Default capacity may allocate too much or too little GPU memory
- Ignoring Bounds: Incorrect bounds cause effects to be culled when visible; always configure bounds in Initialize context
- Sending events every frame without throttling: SendEvent has CPU-GPU sync cost; batch or throttle event dispatch
Key API Quick Reference
Light (UnityEngine.Light)
| Member | Type | Description |
|---|---|---|
type |
Property | LightType (Directional, Point, Spot, Area) |
color |
Property | Emitted light color |
intensity |
Property | Brightness multiplier |
range |
Property | Max distance (Point/Spot) |
spotAngle / innerSpotAngle |
Property | Outer/inner cone angles |
shadows |
Property | LightShadows (None, Hard, Soft) |
shadowResolution |
Property | Shadow map quality |
shadowBias / shadowNormalBias |
Property | Shadow artifact reduction |
bounceIntensity |
Property | GI bounce strength |
cookie |
Property | Projected texture mask |
cullingMask |
Property | Layer-based filtering |
colorTemperature |
Property | CCT in Kelvin |
lightmapBakeType |
Property | Baking configuration |
bakingOutput |
Property | Last bake contribution details |
AddCommandBuffer() |
Method | Execute GPU commands at specified points |
ParticleSystem (UnityEngine.ParticleSystem)
| Member | Type | Description |
|---|---|---|
main / emission / shape |
Property | Module access structs |
particleCount |
Property | Current active particles |
isPlaying / isPaused / isStopped |
Property | Playback state |
Play() / Pause() / Stop() |
Method | Playback control |
Emit(count) |
Method | Immediate particle spawn |
Simulate(time) |
Method | Fast-forward simulation |
GetParticles() / SetParticles() |
Method | Direct particle data access |
Clear() |
Method | Remove all particles |
TriggerSubEmitter() |
Method | Activate sub-emitters |
VisualEffect (UnityEngine.VFX.VisualEffect)
| Member | Type | Description |
|---|---|---|
visualEffectAsset |
Property | Assign/change effect graph |
playRate |
Property | Simulation speed |
aliveParticleCount |
Property | Active particle count |
Play() / Stop() / Reinit() |
Method | Playback control |
SendEvent(name, attr) |
Method | Trigger graph events |
CreateVFXEventAttribute() |
Method | Create event payload |
SetFloat() / SetVector3() / etc. |
Method | Set exposed properties |
GetFloat() / GetVector3() / etc. |
Method | Read exposed properties |
HasFloat() / HasVector3() / etc. |
Method | Check property existence |
ResetOverride(property) |
Method | Restore original values |
ReflectionProbe (UnityEngine.ReflectionProbe)
| Member | Type | Description |
|---|---|---|
mode |
Property | Baked/Custom/Realtime |
size / center |
Property | Bounding box config |
intensity / importance |
Property | Brightness and priority |
boxProjection |
Property | Enable box projection |
refreshMode / timeSlicingMode |
Property | Realtime update config |
RenderProbe() |
Method | Force cubemap refresh |
IsFinishedRendering() |
Method | Check time-sliced completion |
BlendCubemap() |
Method | Blend two cubemaps |
Related Skills
unity-graphics-- Render pipelines (URP/HDRP/Built-in), shaders, materials, camerasunity-2d-- 2D lighting (URP 2D Renderer), sprite renderingunity-platforms-- Platform-specific lighting quality tiers, mobile optimization
Additional Resources
Weekly Installs
7
Repository
nice-wolf-studiā¦e-skillsGitHub Stars
8
First Seen
Mar 19, 2026
Security Audits
Installed on
amp6
cline6
opencode6
cursor6
kimi-cli6
warp6