-
Notifications
You must be signed in to change notification settings - Fork 86
SRP Culling
SRP内置了裁剪API。 通过对每个摄像机执行ScriptableRenderContext.Cull,可以得到一个CullingResults对象。
CullingResults包含了经相机视锥裁剪后,可见的场景物体、灯光,反射探针等数据。 这些数据可以提供给管线中后续的渲染任务。
参考CullingResults的字段,可以有更详细的了解 - Api文档
下面挑几个说以下:
-
visibleLights - Array of visible lights.
SRP将摄像机范围可见的灯光信息,都保存在了这个数组中。
-
GetLightIndexMap()
Array of indices that map from VisibleLight indices to internal per-object light list indices.
SRP在进行每个(Per-Object) Draw操作时,会将影响该对象的灯光信息传递到Shader中。查看
ShaderLibrary/UnityInput.hlsl
中的定义:CBUFFER_START(UnityPerDraw) .... // Light Indices block feature // These are set internally by the engine upon request by RendererConfiguration. real4 unity_LightData; real4 unity_LightIndices[2]; CBUFFER_END
unity_LightIndices是size为2的real4数组,最多可以保存8个灯光索引。
那么这个索引是如何生成的呢?
假设场景中有100盏灯光保存在数组
Light[]
中,我们将其按顺序编号1~100,依次写入到数组LightIndexMap(int[])
中。引擎内部unity_LightIndices
数据生成方法如下(猜测):- 渲染单个对象时,根据一定策略,计算灯光权重,得到优先级最高的8个灯光。
- 根据这8个灯光在
Light[]
中的下表索引i,经过LightIndexMap[i]
映射后得到j,然后将j写入到unity_LightIndices中。 - 初始默认情况下,
LightIndexMap[i] = i
。 但是如果需要自定义灯光顺序/或者过滤什么的,就可以通过修改LightIndexMap的方式。
URP的ForwardLights里,实际上对
LightIndexMap
做了修改,在AdditionalLights计算阶段,过滤掉了Directional Lightint SetupPerObjectLightIndices(CullingResults cullResults, ref LightData lightData) { if (lightData.additionalLightsCount == 0) return lightData.additionalLightsCount; var visibleLights = lightData.visibleLights; var perObjectLightIndexMap = cullResults.GetLightIndexMap(Allocator.Temp); int globalDirectionalLightsCount = 0; int additionalLightsCount = 0; // Disable all directional lights from the perobject light indices // Pipeline handles main light globally and there's no support for additional directional lights atm. for (int i = 0; i < visibleLights.Length; ++i) { if (additionalLightsCount >= UniversalRenderPipeline.maxVisibleAdditionalLights) break; VisibleLight light = visibleLights[i]; if (i == lightData.mainLightIndex) { perObjectLightIndexMap[i] = -1; ++globalDirectionalLightsCount; } else { perObjectLightIndexMap[i] -= globalDirectionalLightsCount; ++additionalLightsCount; } } // Disable all remaining lights we cannot fit into the global light buffer. for (int i = globalDirectionalLightsCount + additionalLightsCount; i < perObjectLightIndexMap.Length; ++i) perObjectLightIndexMap[i] = -1; cullResults.SetLightIndexMap(perObjectLightIndexMap); ///.......... }
物件裁剪并没有暴露出相关的字段。 按照文档的意思,我们拿到CullingResults之后,直接用在ScriptableRenderContext.DrawRenderers进行渲染就可以了。