Skip to content

SRP Culling

zilch edited this page Feb 9, 2021 · 3 revisions

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 Light

    int 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进行渲染就可以了。

Clone this wiki locally