Universal Render Pipeline (URP)
URP Pipeline Asset Configuration
The URP Pipeline Asset controls global rendering settings. Create via Assets > Create > Rendering > URP Asset (with Universal Renderer).
Key Pipeline Asset Settings
| Setting | Recommended | Notes | |---------|-------------|-------| | HDR | Enabled | Required for Bloom and color grading | | Anti-Aliasing | MSAA 4x or FXAA | MSAA on mobile, FXAA on desktop | | Shadow Resolution | 2048 (desktop) / 1024 (mobile) | Balance quality vs performance | | Shadow Cascade Count | 4 (desktop) / 2 (mobile) | More cascades = better shadow distribution | | Shadow Distance | 50-150 | Depends on game scale | | SRP Batcher | Enabled | Major draw call optimization | | Dynamic Batching | Disabled when SRP Batcher is on | They conflict; SRP Batcher is superior |
Configuring Pipeline Asset via Script
using UnityEngine;
using UnityEngine.Rendering.Universal;
public class URPQualityManager : MonoBehaviour
{
[SerializeField] private UniversalRenderPipelineAsset[] qualityLevels;
public void SetQualityLevel(int level)
{
if (level >= 0 && level < qualityLevels.Length)
{
QualitySettings.renderPipeline = qualityLevels[level];
}
}
public void AdjustShadowDistance(float distance)
{
var urpAsset = (UniversalRenderPipelineAsset)QualitySettings.renderPipeline;
urpAsset.shadowDistance = distance;
}
}
Renderer Features (Custom Render Passes)
Renderer Features let you inject custom rendering logic into URP's render pipeline.
Creating a Custom Renderer Feature
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
public class OutlineRendererFeature : ScriptableRendererFeature
{
[System.Serializable]
public class OutlineSettings
{
public RenderPassEvent renderPassEvent = RenderPassEvent.AfterRenderingOpaques;
public Material outlineMaterial;
public LayerMask layerMask;
[Range(1, 4)] public int downSample = 1;
}
public OutlineSettings settings = new OutlineSettings();
private OutlineRenderPass _outlinePass;
public override void Create()
{
_outlinePass = new OutlineRenderPass(settings);
_outlinePass.renderPassEvent = settings.renderPassEvent;
}
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
if (settings.outlineMaterial == null) return;
renderer.EnqueuePass(_outlinePass);
}
}
Custom Render Pass
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
public class OutlineRenderPass : ScriptableRenderPass
{
private readonly OutlineRendererFeature.OutlineSettings _settings;
private RTHandle _tempTexture;
public OutlineRenderPass(OutlineRendererFeature.OutlineSettings settings)
{
_settings = settings;
profilingSampler = new ProfilingSampler("OutlinePass");
}
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
{
var desc = renderingData.cameraData.cameraTargetDescriptor;
desc.depthBufferBits = 0;
RenderingUtils.ReAllocateIfNeeded(ref _tempTexture, desc, name: "_TempOutline");
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
CommandBuffer cmd = CommandBufferPool.Get();
using (new ProfilingScope(cmd, profilingSampler))
{
var source = renderingData.cameraData.renderer.cameraColorTargetHandle;
Blitter.BlitCameraTexture(cmd, source, _tempTexture, _settings.outlineMaterial, 0);
Blitter.BlitCameraTexture(cmd, _tempTexture, source);
}
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
public override void OnCameraCleanup(CommandBuffer cmd)
{
_tempTexture?.Release();
}
}
Forward vs Forward+ Renderer
- Forward: Traditional forward rendering. Good for mobile, limited additional lights per object.
- Forward+: Uses clustered lighting. Removes per-object light limit. Better for scenes with many lights. Requires Unity 2022.2+.
Set in the Universal Renderer Data asset under Rendering Path.
2D Renderer Setup
For 2D games, use the 2D Renderer:
- Create URP Asset with 2D Renderer (Assets > Create > Rendering > URP Asset with 2D Renderer)
- 2D Renderer supports: Light2D, ShadowCaster2D, Sprite-Lit-Default shader
- Use Light2D components: Global, Freeform, Sprite, Point, Spot
using UnityEngine;
using UnityEngine.Rendering.Universal;
public class DynamicLight2DController : MonoBehaviour
{
private Light2D _light2D;
private void Awake()
{
_light2D = GetComponent<Light2D>();
}
public void SetIntensity(float intensity)
{
_light2D.intensity = intensity;
}
public void FlickerLight(float minIntensity, float maxIntensity)
{
_light2D.intensity = Random.Range(minIntensity, maxIntensity);
}
}
URP Lighting Configuration
Main Light (Directional)
- Shadow type: Soft Shadows for quality, Hard for performance
- Shadow resolution: Set per-light or globally in Pipeline Asset
- Shadow bias: Normal Bias 0.4, Depth Bias 1.0 (starting values)
Additional Lights
- Per-object limit in Pipeline Asset (default 4 for Forward)
- Forward+ removes this limit via clustered lighting
- Shadow support for additional lights must be enabled in Pipeline Asset
Shadow Settings
Pipeline Asset:
Shadow Distance: 100
Cascade Count: 4
Cascade Ratios: 0.067, 0.2, 0.467 (default)
Depth Bias: 1
Normal Bias: 1
Soft Shadows: Enabled
Post-Processing (Volume Framework)
URP uses the Volume framework for post-processing. No separate post-processing package needed.
Setting Up Post-Processing
- Enable Post Processing on the Camera component
- Create a Global Volume (or local with collider)
- Add Volume overrides (Bloom, Color Grading, etc.)
Common Volume Profile Script
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
public class PostProcessController : MonoBehaviour
{
[SerializeField] private Volume globalVolume;
private Bloom _bloom;
private ColorAdjustments _colorAdjustments;
private Vignette _vignette;
private ChromaticAberration _chromaticAberration;
private void Awake()
{
var profile = globalVolume.profile;
profile.TryGet(out _bloom);
profile.TryGet(out _colorAdjustments);
profile.TryGet(out _vignette);
profile.TryGet(out _chromaticAberration);
}
public void SetDamageEffect(float intensity)
{
if (_vignette != null)
{
_vignette.intensity.Override(Mathf.Lerp(0.2f, 0.6f, intensity));
_vignette.color.Override(Color.Lerp(Color.black, Color.red, intensity));
}
if (_chromaticAberration != null)
{
_chromaticAberration.intensity.Override(intensity * 0.5f);
}
}
public void SetBloomIntensity(float intensity)
{
if (_bloom != null)
{
_bloom.intensity.Override(intensity);
}
}
public void SetExposure(float exposure)
{
if (_colorAdjustments != null)
{
_colorAdjustments.postExposure.Override(exposure);
}
}
}
Tonemapping Modes
- None: Raw HDR values clamped. Not recommended.
- Neutral: Minimal color shift. Good default.
- ACES: Film-like look, saturated. Industry standard.
SRP Batcher Compatibility
The SRP Batcher groups draw calls by shader variant. To make a shader compatible:
Shader Must Use CBUFFER
CBUFFER_START(UnityPerMaterial)
float4 _BaseColor;
float _Smoothness;
float4 _BaseMap_ST;
CBUFFER_END
**Rules for SRP Batcher co