Quick answer: Lit particles in URP and HDRP flicker because the particle quad position is slightly different in the depth priming pass than in the color pass, causing the EQUAL depth test to fail intermittently. Disable depth priming on transparents, set Receive Shadows Off on the particle material, fix the render queue to 3000, and turn off motion vectors on the renderer.
Your explosion particles sparkle beautifully in the Scene view, but in Game view they pop in and out like a broken fluorescent tube. Move the camera and the flicker gets worse. Switch to the same particle with Unlit and it looks perfect. The bug is not in your particle curves or your texture — it is in the render pipeline’s assumption that lit geometry is mostly opaque, and transparent billboards violate three of those assumptions at once.
Why Lit Particles Flicker
URP’s Particles Lit and HDRP’s equivalent shader are complex — they sample the depth buffer, the shadow cascade, and optionally motion vectors. Each of those inputs was designed for stable opaque geometry and reacts badly to camera-facing billboards that reposition every frame. The three most common root causes:
- Depth priming mismatch. URP 12+ can pre-pass-write depth for opaques, then use
ZTest Equalin the forward pass. Particles that accidentally land in the priming pass write a depth that is a hair different from the forward pass, and the equality test fails on half the pixels. - Shadow receive jitter. A lit particle samples the shadow cascade at its world position, but the cascade shifts by a texel as the camera moves. A particle on the boundary flips between lit and shadowed on alternating frames.
- TAA history corruption. If motion vectors are enabled, each billboard writes a motion vector based on its last-frame camera-relative quad position, which is noise. TAA then blends stale history into current frames and the particle shimmers.
Step 1: Disable Depth Priming for Transparents
Open your URP Renderer Asset (Universal Renderer Data). Find Rendering → Depth Priming Mode and set it to Disabled or Auto. Auto is safer if you rely on it for opaque overdraw reduction, but if particles are the only victims, Disabled is the fastest fix to verify.
// Verify depth priming state at runtime
using UnityEngine.Rendering.Universal;
var urp = (UniversalRenderPipelineAsset)GraphicsSettings.defaultRenderPipeline;
var rendererData = urp.GetRendererDataFromAsset(0) as UniversalRendererData;
Debug.Log($"Depth priming: {rendererData.depthPrimingMode}");
If the flicker persists, it is not depth priming. Move on.
Step 2: Turn Off Shadow Receive on the Particle Material
On the particle material, find the Surface Options → Receive Shadows toggle and disable it. Transparent particles rarely look better with shadow maps sampled on them — shadow maps are designed for opaque, stable surfaces, and a particle billboard receiving a cascade sample on its edge is exactly the worst case. Turning receive off also saves a cascade sample per particle pixel.
// Shader keywords that should be DISABLED on particle materials
material.DisableKeyword("_MAIN_LIGHT_SHADOWS");
material.DisableKeyword("_MAIN_LIGHT_SHADOWS_CASCADE");
material.DisableKeyword("_RECEIVE_SHADOWS_OFF"); // actually enabling the off path
material.SetFloat("_ReceiveShadows", 0);
Note the slightly confusing keyword naming — _RECEIVE_SHADOWS_OFF is the path that disables shadow receiving, so it needs to be active (the other two shadow keywords must be inactive).
Step 3: Set the Render Queue Explicitly
The default render queue on Particles Lit is AlphaTest+50 = 2500, which is opaque territory. That puts particles into the depth priming pass (cause #1 above) and causes sort conflicts with real transparents. Override the queue:
material.renderQueue = 3000; // Transparent base
material.SetOverrideTag("RenderType", "Transparent");
material.SetFloat("_Surface", 1); // 0 = opaque, 1 = transparent
material.SetFloat("_Blend", 0); // Alpha blend
material.SetFloat("_ZWrite", 0); // No depth write for transparents
Also set the ParticleSystemRenderer sort mode to By Distance rather than Oldest in Front for billboards that intersect geometry. Oldest in Front produces wrong ordering once particles re-use pooled indices.
Step 4: Kill Motion Vector Writes
On the ParticleSystem component, under Renderer, set Motion Vectors to Force No Motion. Do not leave it on Camera Motion Only for lit particles — the shader may still produce a per-vertex motion vector if the camera motion vector path is enabled. Force No Motion writes zeros and tells TAA to accept the current frame’s particle pixel without blending history.
“Lit transparent shaders are a compromise. Every feature you leave on that was designed for opaques is a potential flicker source.”
Step 5: Consider an Unlit Variant
If your particle does not need real-time shadow reception or multi-light response, use Particles Unlit with a baked lighting color applied via the Color Over Lifetime module. Most VFX artists cannot tell the difference in blind tests, and you skip every category of lit-pass pitfall. Save Lit particles for hero effects that genuinely benefit from scene lighting, like magical auras that need to respond to the player’s torch.
Verifying the Fix
Record gameplay at 30 fps with the Frame Debugger open and step through a flickering frame. Check the draw call for your particle system: it should be in Render Transparents, not Render Opaques or DepthPriming. Its depth test should be LEqual, not Equal. Motion vector buffer for the particle region should be zero. If any of these are wrong, revisit the corresponding step.
Related Issues
If particles render correctly but have wrong shadow cast direction, see Particle Shadow Caster Wrong Direction. For soft-particle seams against geometry, read Soft Particles Depth Buffer Missing.
Disable depth priming, Receive Shadows off, queue 3000, Force No Motion — four toggles and the flicker is gone.