Unity Shader入门精要读书笔记(5)
- Unity Shader基本的结构
- 这两行代码告诉Unity谁包含了顶点着色器的代码,谁包含了片元着色器的代码。
#pragma vertex vert
#pragma fragment frag
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader "Assets/Chapter5_SimpleShader"
{
Properties{
//声明一个Color类型的属性
_Color("Color Tint",Color) = (1.0,1.0,1.0,1.0)
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
fixed4 _Color;
//使用一个结构体来定义顶点着色器的输入
struct a2v {
//POSITION 语义告诉Unity,用模型空间的顶点坐标填充vertex变量
float4 vertex:POSITION;
//NORMAL语义告诉Unity,用模型空间的法线方向填充normal变量
float3 normal:NORMAL;
//TEXCOORD0语义告诉Unity,用模型的第一套纹理坐标填充texcoord变量
float4 texcoord:TEXCOORD0;
};
struct v2f{
//SV_POSITION语义告诉Unity,pos里包含了顶点在裁剪空间中的位置信息
float4 pos:SV_POSITION;
//COLOR0语义可以用于存储颜色信息
fixed3 color : COLOR0;
};
v2f vert(a2v v){
//声明输出结构
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
//v.normal包含了顶点的法线方向,其分量范围在[-1.0,1.0]
//下面代码吧分量范围映射到[0.0,1.0]
//存储到o.color中传递给片元着色器
o.color = v.normal * 0.5 + fixed3(0.5, 0.5, 0.5);
return o;
}
fixed4 frag(v2f i) : SV_Target{
fixed3 c = i.color;
c *= _Color.rgb;
//将插值后的i.color显示到屏幕上
return fixed4(c,1.0);
}
ENDCG
}
}
}
- a2v的意思就是把数据从应用阶段传递到顶点着色器上
我们知道,一个模型通常包含了一组三角面片,每个三角面片由3个顶点构成,而每个顶点又包含了一些数据,例如顶点位置、法线、切线、纹理坐标、顶点颜色等。通过上面的方法,我们就可以在顶点着色器中访问顶点的这些模型数据。 - 顶点着色器和片元着色器之间的通讯:v2f(示例见上述代码)
顶点着色器的输出结构中,必须包含一个变量,它的语义是SV_POSITION。否则,渲染器将无法得到裁剪空间中的顶点坐标,也就无法把顶点渲染到屏幕上。
-顶点着色器是逐顶点调用的,而片元着色器是逐片元调用的。片元着色器中的输入实际上是把顶点着色器的输出进行插值后得到的结果。(插值的意义类似于按不同权重混合) - 注意在上述代码中,我们在属性块中定义一个属性,那么就需要在CG代码中定义一个属性类型和名称都匹配的变量。
- 语义实际上就是一个赋给Shader输入和输出的字符串,这个字符串表达了这个参数的含义。通俗地讲,这些语义可以让 Shader 知道从哪里读取数据,并把数据输出到哪里,它们在CG/HLSL 的 Shader流水线中是不可或缺的。需要注意的是,Unity并没有支持所有的语义。
- 语义名称一样,若出现位置不同,可能含有不同的含义。
- 系统数值语义(SV开头的),为了让系统有更好的跨平台性,对于有特殊含义的变量,最好使用系统数值语义。
- a2v结构体中
- v2f结构体中
- frag函数后面
- Unity中对于Unity Shader的debug方法:
(1)使用假彩色图像:假彩色图像(false-color image)指的是用假彩色技术生成的一种图像。与假彩色图像对应的是照片这种真彩色图像(true-color image)。一张假彩色图像可以用于可视化一些数据。我们把需要调试的变量映射到[0,1]之间,然后作为颜色输出到屏幕上。
(2)VS(Windows上)
(3)帧调试器 - 帧调试器可以用于查看渲染该帧时进行的各种渲染事件(event),这些事件包含了Draw Call序列,也包括了类似清空帧缓存等操作。帧调试器窗口大致可分为3个部分:最上面的区域可以开启/关闭(单击 Enable按钮)帧调试功能,当开启了帧调试时,通过移动窗口最上方的滑动条(或单击前进和后退按钮),我们可以重放这些渲染事件;左侧的区域显示了所有事件的树状图,在这个树状图中,每个叶子节点就是一个事件,而每个父节点的右侧显示了该节点下的事件数目。我们可以从事件的名字了解这个事件的操作,例如以Draw开头的事件通常就是一个 Draw Call;当单击了某个事件时,在右侧的窗口中就会显示出该事件的细节,例如几何图形的细节以及使用了哪个Shader等。同时在Game视图中我们也可以看到它的效果。如果该事件是一个 Draw Call并且对应了场景中的一个GameObject,那么这个GameObject也会在Hierarchy视图中被高亮显示出来。
- Unity 5提供的帧调试器实际上并没有实现一个真正的帧拾取(frame capture)的功能,而是仅仅使用停止渲染的方法来查看渲染事件的结果。
- 在一种特殊情况下 Unity不会为我们进行这个翻转操作,这种情况就是我们开启了抗锯齿,并在此时使用了渲染到纹理技术(多张图像)。
- 不要在Shader上进行大量运算
- 慎用分支和循环语句
- 不要除0