我们在此篇正式开始学习如何编写Unity Shader,更准确地说,是学习如何利用Cg语言编写顶点/片元着色器。
1. 基本骨架
一个基本的顶点/片元着色器的代码骨架如下:
Shader "002/MyShader"
{
SubShader
{
pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
void vert()
{
}
void frag()
{
}
ENDCG
}
}
FallBack "Diffuse"
}
实际上,真正顶点/片元着色器的代码定义在 CGPROGRAM 和 ENDCG 之间,里面包含了两行非常重要的编译指令:
#pragma vertex vert // 声明顶点着色器函数vert
#pragma fragment frag // 声明片元着色器函数frag
它们的作用是告诉Unity,哪个函数包含了顶点着色器的代码,哪个函数包含了片元着色器的代码,这两个函数名不一定是vert和frag,可以是任意一个自定义的合法函数名,但一般都使用vert和frag来定义这两个函数。
2. 顶点/片元着色器函数定义
一般情况下,顶点着色器函数vert的形参列表都需要返回一个语义为POSITION且是float4类型的变量:
void vert(in float2 inPos: POSITION, out float4 outPos: POSITION)
{
outPos = float4(inPos, 0, 1);
}
而片元着色器函数frag需要返回一个语义为COLOR且fixed4类型的变量:
void frag(out fixed4 outCol: COLOR)
{
outCol =fixed4(1, 0, 0, 1);
}
以上两端代码都是在形参类型之前添加out关键字来指定返回变量,事实上,我们完全可以使用像C#一样的返回方式:
float4 vert(float2 inPos: POSITION): SV_POSITION
{
return float4(inPos, 0, 1);
}
fixed4 frag(): SV_TARGET
{
return fixed4(1, 0, 0, 1);
}
POSITION和SV_POSITION等都是Cg/HLSL中的语义,它们是不可省略的,这些语义告诉Unity需要哪些输入值,以及输出的是什么。
3. 完整文件模板
Shader "MyShader"
{
Properties
{
}
SubShader
{
pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
float4 vert(float4 v: POSITION): SV_POSITION
{
return UnityObjectToClipPos(v);
}
fixed4 frag(): SV_Target
{
return fixed4(0, 0, 0, 1);
}
ENDCG
}
}
FallBack "Diffuse"
}