自底向上的SRP教程 II

Draw Call

对 Catlike Coding 教程的解析与补充

点击传送——>CustomRenderPipeline

1.防止重复声明

1
2
3
4
5
6
#ifndef CUSTOM_UNLIT_PASS_INCLUDE
#define CUSTOM_UNLIT_PASS_INCLUDE

...

#endif

#include引入HLSL时会将所有内容插入,且允许多次或循环引用,这会导致编译错误,可以通过这种方式对着色器代码进行保护。在定义宏之前先判断时候定义过该标示符,如果定义过,直接调到#endif段后。这样就可以保证只有第一次#include时有效

2.SRP Batcher

  1. SRP批处理
    目的是减少Set Pass Call,他将模型的坐标信息、材质信息、光源阴影等参数保存到不同的常量缓冲区(CBUFFER),只有CBUFFER发生变化时才会重新提交到GPU并保存
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    CBUFFER_START(UnityPerMaterial)
    float4 _BaseColor;
    CBUFFER_END

    CBUFFER_START(UnityPerDraw)
    float4x4 unity_ObjectToWorld;
    float4x4 unity_WorldToObject;
    float4 unity_LODFade;
    real4 unity_WorldTransformParams;
    CBUFFER_END
  • UnityPerMaterial:所有材质相关的数据都应该在名为 UnityPerMaterial 的 CBUFFER 中声明,通常是指在着色器属性块声明的变量
  • UnityPerDraw:该 CBUFFER 应当包含所有 Unity 的内置引擎变量
  1. 开启SRP合批
    1
    2
    3
    4
    public CustomRenderPipeline()
    {
    GraphicsSettings.useScriptableRenderPipelineBatching = true;
    }
    一般写在构造函数中

Tips: real4只是个别名,具体可能是float4或half4,这取决于目标平台

3.同材质设置不同颜色

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[DisallowMultipleComponent]
public class PerObjectMaterialProperties : MonoBehaviour
{
static int baseColorId = Shader.PropertyToID("_BaseColor");

[SerializeField]
Color baseColor = Color.white;
static MaterialPropertyBlock block;

private void OnValidate()
{
if(block == null)
{
block = new MaterialPropertyBlock();
}

block.SetColor(baseColorId, baseColor);
GetComponent<Renderer>().SetPropertyBlock(block);
}
private void Awake()
{
OnValidate();
}
}
  • DisallowMultipleComponent防止脚本被多次添加
  • Shader.PropertyToID 获取着色器属性名称的唯一标示符(Unity为着色器的每个属性都分配唯一整数)
  • MaterialPropertyBlock 绘制相同材质但属性不同的对象可以用该类 Renderer组件下有SetPropertyBlock方法来设置block
  • OnValidate 在以下两种情况下被调用:
    • 脚本被加载时
    • Inspector中有值被修改时

4.GPU Instancing

  1. GPU多例化
    能够在一个绘制调用中渲染多个具有相同网格的物体,CPU收集每个物体的材质属性和变换放入数组发送到GPU,GPU拿到数组后顺序遍历渲染
  2. 开启
    1
    #pragma multi_compile_instancing
    添加指令后材质面板就可以看到开关
  3. 应用
    绘制许多网格小球(无需生成多个对象,只填充变换)
    1
    2
    3
    4
    5
    6
    7
    Matrix4x4[] matrices = new Matrix4x4[1023];

    for(int i = 0; i < matrices.Length; i++)
    {
    matrices[i] = Matrix4x4.TRS(Random.insideUnitSphere * 10f, Quaternion.Euler(Random.value * 360f, Random.value * 360f, Random.value * 360f), Vector3.one * Random.Range(0.5f, 1.5f));
    baseColors[i] = new Vector4(Random.value, Random.value, Random.value);
    }
  • Matrix4x4.TRS(Vector3 translation, Quaternion rotation, Vector3 scaling)创建平移、旋转、缩放矩阵
    1
    2
    3
    4
    5
    6
    7
    8
    9
    private void Update()
    {
    if (block == null)
    {
    block = new MaterialPropertyBlock();
    block.SetVectorArray(baseColorId, baseColors);
    }
    Graphics.DrawMeshInstanced(mesh, 0, material, matrices, 1023, block);
    }
  • SetVectorArray 设置向量数组属性
  • Graphics.DrawMeshInstanced(Mesh mesh, int submeshIndex, Material material, Matrix4x4[] matrices, int count= matrices.Length, MaterialPropertyBlock properties = null) submeshIndex适用于若干材质构成的网格,选择要绘制网格的哪个子集。

5.混合模式

  • Src 当前需要渲染的像素(上层图像)
  • Dst 已在栈中的像素(已有图像)
    1
    2
    3
    4
    5
    6
    // 设置混合模式
    [Enum(UnityEngine.Rendering.BlendMode)] _SrcBlend ("Src Blend", Float) = 1
    [Enum(UnityEngine.Rendering.BlendMode)] _DstBlend ("Dst Blend", Float) = 0

    // 定义混合模式
    Blend[_SrcBlend][_DstBlend]
    常用混合模式:
  • BlendOp Min Blend One One(变暗)
  • BlendOp Max Blend One One(变亮)
  • Blend SrcAlpha OneMinusSrcAlpha(正常/透明度混合)
  • Blend OneMinusDstAlpha One(滤色/柔和相加)
  • Blend One OneMinusSrcAlpha(同上)
  • Blend DstColor Zero(相乘/正片叠加)
  • Blend DstColor SrcColor(两倍相乘)
  • Blend One One(线性减淡)
(下接 自底向上的SRP教程 III)

自底向上的SRP教程 II
https://baifabaiquan.cn/2023/04/14/自底向上的SRP教程II/
作者
白发败犬
发布于
2023年4月14日
许可协议