Unity URP自定义ScriptableRenderPass渲染GameObject问题排查
两种实现方式的问题分析与解决方案
第一种实现方式(CommandBuffer.DrawRenderer)
存在的问题
- 无光照效果:直接调用
DrawRenderer时,没有触发URP材质中处理光照的Pass,也未向GPU传递URP所需的光照常量数据(比如主光源信息、光照矩阵等),导致材质无法计算光照。 - 黑色方块异常:未配置正确的渲染状态(如深度测试、深度写入),物体渲染时无法正确处理遮挡;同时未指定URP专属的渲染Pass,使用了材质的默认Pass导致渲染异常。
解决代码与说明
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData) { CommandBuffer cmd = CommandBufferPool.Get("EnemyClearDepthPass"); var camera = renderingData.cameraData.camera; // 同步相机的MVP、视口等属性到GPU context.SetupCameraProperties(camera); // 配置深度测试与写入,避免遮挡错误 cmd.SetDepthTest(CompareFunction.LessEqual); cmd.SetDepthWrite(true); // 指定URP正向渲染的Pass int forwardPassIndex = Shader.PropertyToID("UniversalForward"); foreach (var renderer in _associatedObjects) { if (renderer.isVisible) { // 使用URP的正向Pass渲染,确保光照计算生效 cmd.DrawRenderer(renderer, renderer.sharedMaterial, 0, forwardPassIndex); } } context.ExecuteCommandBuffer(cmd); CommandBufferPool.Release(cmd); // 提交渲染上下文,确保命令执行 context.Submit(); }
第二种实现方式(ScriptableRenderContext.DrawRenderers)
存在的问题
- DrawingSettings配置缺失:未指定URP的
ShaderTagId,URP无法识别要渲染的材质Pass;同时SortingSettings未关联相机,导致排序逻辑失效,物体可能被错误剔除。 - RenderStateBlock过度覆盖:设置
RenderStateMask.Everything会清空URP默认的深度、混合等渲染状态,导致物体无法正常渲染。 - Pass执行时机未指定:默认执行时机可能处于渲染流程的错误阶段,无法获取正确的剔除结果与渲染上下文。
解决代码与说明
using System; using UnityEngine.Rendering; using UnityEngine.Rendering.Universal; public class JustDrawSomethingPls : ScriptableRendererFeature { class DrawEverythingPass : ScriptableRenderPass { // 指定URP正向渲染的ShaderTag private readonly ShaderTagId _forwardTag = new ShaderTagId("UniversalForward"); public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData) { // 基于当前相机初始化排序设置,确保渲染顺序正确 SortingSettings sortingSettings = new SortingSettings(renderingData.cameraData.camera) { criteria = SortingCriteria.CommonOpaque }; // 初始化DrawingSettings,绑定URP的ShaderPass与排序规则 DrawingSettings drawingSettings = new DrawingSettings(_forwardTag, sortingSettings) { mainLightIndex = renderingData.lightData.mainLightIndex }; // 配置过滤规则,可替换layerMask为目标Layer的掩码(如1 << LayerMask.NameToLayer("Enemy")) FilteringSettings filteringSettings = new FilteringSettings(RenderQueueRange.opaque) { layerMask = int.MaxValue, renderingLayerMask = uint.MaxValue }; // 使用默认渲染状态,不覆盖URP的默认配置 RenderStateBlock renderStateBlock = new RenderStateBlock(RenderStateMask.None); // 调用DrawRenderers渲染可见物体 context.DrawRenderers(renderingData.cullResults, ref drawingSettings, ref filteringSettings, ref renderStateBlock); // 提交渲染上下文 context.Submit(); } } private DrawEverythingPass _drawEverythingPass; public override void Create() { _drawEverythingPass = new DrawEverythingPass(); // 指定Pass在不透明物体渲染阶段执行,确保获取正确的剔除结果 _drawEverythingPass.renderPassEvent = RenderPassEvent.BeforeRenderingOpaques; } public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) { renderer.EnqueuePass(_drawEverythingPass); } }
额外说明
如果需要渲染特定Layer,只需修改FilteringSettings中的layerMask参数,例如:
filteringSettings.layerMask = 1 << LayerMask.NameToLayer("YourTargetLayer");
内容的提问来源于stack exchange,提问作者danglingPointer
相关产品推荐
相关产品推荐

