SRP中的shader
在Unity中使用SRP时,我们需要使用HLSL来编写shader。HLSL语法与GLSL类似,在使用HLSL的地方我们需要用HLSLPROGRAM
和ENDHLSL
来包裹:
Shader "My Pipeline/Unlit" {
Properties {}
SubShader {
Pass
{
HLSLPROGRAM
#pragma vertex UnlitPassVertex
#pragma fragment UnlitPassFragment
#include "Unlit.hlsl"
ENDHLSL
}
}
}
此时,unity_MatrixVP
和unity_ObjectToWorld
这两个矩阵也不能直接使用,需要我们自行声明:
float4x4 unity_MatrixVP;
float4x4 unity_ObjectToWorld;
struct VertexInput {
float4 pos : POSITION;
};
struct VertexOutput {
float4 clipPos : SV_POSITION;
};
VertexOutput UnlitPassVertex (VertexInput input) {
VertexOutput output;
float4 worldPos = mul(unity_ObjectToWorld, input.pos);
output.clipPos = mul(unity_MatrixVP, worldPos);
return output;
}
float4 UnlitPassFragment (VertexOutput input) : SV_TARGET {
return 1;
}
另外,这两个矩阵的更新频率实际上是不同的,unity_MatrixVP
矩阵绘制每一帧画面时只需更新一次,而unity_ObjectToWorld
跟绘制的物体还有关系,因此它需要每次绘制时都要更新一次。这样的话,我们可以利用unity提供的cbuffer,使得这两个矩阵可以按照自身需要的频率更新:
CBUFFER_START(UnityPerFrame)
float4x4 unity_MatrixVP;
CBUFFER_END
CBUFFER_START(UnityPerDraw)
float4x4 unity_ObjectToWorld;
CBUFFER_END
现在使用该shader的材质,来绘制一些gameobject试试:
接下来,我们希望这些gameobject拥有不同的颜色,显然颜色这个是跟随材质变化的,因此我们要把它放到UnityPerMaterial
中:
CBUFFER_START(UnityPerMaterial)
float4 _Color;
CBUFFER_END
这下gameobject就可以五彩斑斓了:
最后,我们希望在SRP中使用gpu instancing的方式来绘制这些gameobjects。首先在C#中把开关打开:
drawSettings.enableInstancing = true;
然后还要在shader中引入INSTANCING_ON
关键字:
#pragma multi_compile_instancing
为了支持instancing,原先放在UnityPerMaterial
buffer中的_Color需要挪到UNITY_INSTANCING_BUFFER
中:
UNITY_INSTANCING_BUFFER_START(PerInstance)
UNITY_DEFINE_INSTANCED_PROP(float4, _Color)
UNITY_INSTANCING_BUFFER_END(PerInstance)
同时vertex shader和frag shader也要相应地改动:
struct VertexInput {
float4 pos : POSITION;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct VertexOutput {
float4 clipPos : SV_POSITION;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
VertexOutput UnlitPassVertex (VertexInput input) {
VertexOutput output;
UNITY_SETUP_INSTANCE_ID(input);
UNITY_TRANSFER_INSTANCE_ID(input, output);
float4 worldPos = mul(UNITY_MATRIX_M, float4(input.pos.xyz, 1.0));
output.clipPos = mul(unity_MatrixVP, worldPos);
return output;
}
float4 UnlitPassFragment (VertexOutput input) : SV_TARGET {
UNITY_SETUP_INSTANCE_ID(input);
return UNITY_ACCESS_INSTANCED_PROP(PerInstance, _Color);
}
这时我们再用frame debug看一下,可以发现draw call大大降低了:
如果你觉得我的文章有帮助,欢迎关注我的微信公众号 我是真的想做游戏啊
Reference
[1] Custom Shaders