Unity Shader(实现一个只有颜色属性可调节的简单材质效果)
在一个Shader中,可以有多个SubShader以及一个SubShader中也可以有多个Pass,但是一个Shader中必须要至少有一个SubShader,并且这个SubShader中也必须至少有一个Pass。
Pass的意思就是渲染一次模型,具体怎么渲染就需要我们在Pass中添加Cg/HLSL代码片断来实现了,这段代码片段是由CGPROGRAM开始,由ENDCG结束。我们必须要添加CGPROGRAM和ENDCG,然后在他么中间去写实现效果的代码。
既然是顶点片断着色器,那么就要先定义好顶点着色器和片断着色器,告诉unity分别在哪里去执行它们。
#pragma vertex vert
//定义顶点着色器,通常情况下会起名为vert。
#pragma fragment frag
//定义片断着色器,通常情况下会起名为frag
#pragma是Unity内置的编绎指令用的命令,在Pass中我们就利用此命令来声明所需要的顶点着色器与片断着色器。
所以完整的准备工作就是:
pass
{
CGPROGRAM
//#pragma是Unity内置的编绎指令用的命令,在Pass中我们就利用此命令来声明所需要的顶点着色器与片断着色器。
#pragma vertex vert
//定义顶点着色器,通常情况下会起名为vert。
#pragma fragment frag
//定义片断着色器,通常情况下会起名为frag
ENDCG
}
顶点着色器
float4 vert(float4 vertex : POSITION):SV_POSITION
{
return UnityObjectToClipPos(vertex);
}
- 顶点着色器函数的名称就是我们前面已经定义好的名称
- 其中float4 vertex是我们自己定义的一个四维向量,名字叫vertex(名字可以随便取),仅仅定义一个四维向量并不能使它拥有我们模型的顶点信息,所以这里我们需要为它指定一个语义–POSITION,POSITION就是代表着模型的顶点位置信息,此时变量vertex就表示着我们模型的顶点位置。
- 在顶点着色器中最主要的事情就是将顶点从模型坐标转换到裁剪坐标(说白了就是将模型显示在二维显示器上时需要做的一些矩阵转换)。不会矩阵转换怎么办,没关系,unity已经为我们准备好现成的命令了。只需要调用UnityObjectToClipPos即可,后面括号中加上我们的顶点位置变量就可以了。
- 然后呢,在后面片断着色器中我们需要顶点着色器中的输出结果,所以需要return转换后的顶点,float4就是用来定义我们返回的是四维向量。
- 经过转换后的顶点位置,我们也需要利用语义来标记一下,以便片断着色器可以知道哪个是从顶点着色器输出过来的顶点位置信息。所以我们在函数的后面加上:SV_POSITION。
片断着色器
片断着色器也被称作像素着色器,主要是处理最终显示正在屏幕上的像素结果。经过顶点着色器的处理,我们已经得到了最终显示在屏幕上的顶点矩阵,内部会自动进行插值计算,以获得当前模型的所有片断像素,然后每一个像素都会执行一次片断着色器,得到最终每个像素的颜色值。
fixed4 _Color;
float4 frag():SV_TARGET0
{
return _Color;
}
- 片断着色器的函数名还是前面我们定义好的,但是这个函数暂时是没有参数的。
- 在cg/HLSL中使用Properties中的变量前还需要在cg/hlsl中再重新声明一次,名称要求一致,这是死原则。float、half和fixed这三都是浮点数的代表,只是分别对应的精度不一样,主要用此可以进行更进一步的优化。
- 然后直接返回_Color,也就是直接返回我们在材质面板中定义的颜色,这也是我们预期的效果。
- 同样,返回的值是一个四维向量,我们用float4来表示,如果想优化的话就用fixed4来表示。
- SV_TARGET0是一个语义,表示该函数返回的是用于下一阶段输出的颜色值,也就是我们最终输出到显示器上的值。
最终完整的代码如下:
Shader "Unlit/NewUnlitShader"
{
Properties
{
_Color("I am Color", Color) = (1,1,1,1)//依次为RGBA(0-1)
}
SubShader
{
pass
{
CGPROGRAM
//#pragma是Unity内置的编绎指令用的命令,在Pass中我们就利用此命令来声明所需要的顶点着色器与片断着色器。
#pragma vertex vert
//定义顶点着色器,通常情况下会起名为vert。
#pragma fragment frag
//定义片断着色器,通常情况下会起名为frag
fixed4 _Color;
float4 vert(float4 vertex : POSITION):SV_POSITION
{
return UnityObjectToClipPos(vertex);
}
float4 frag():SV_TARGET0
{
return _Color;
}
ENDCG
}
}
FallBack "DIFFUSE"
}
总结
顶点着色器与片断着色器的执行并不是1:1的,举一个例子,一个三角面片,只有三个顶点,顶点着色器只需执行3次,而片断着色器由最终的像素数来决定,执行几百上千都是正常的。所以从性能的角度来考虑,我们尽量把计算放在顶点着色器中去执行。其次在片断着色器中也要尽量的简化算法,节省开支。