1.一个最简单的顶点/片元着色器
1.1 顶点/片元着色器的基本结构
//定义Shader的位置和名称 Shader " Unity Shaders Book/Chapter 5/ Simple Shader" { //可以不定义Properties,但是必须有至少一个SubShader SubShader { Pass { //使用CGPROGRAM和ENDCG包裹CG代码片段 CGPROGRAM //编译指令,指明顶点着色器代码是vert函数 #pragma vertex vert //编译指令,指明片元着色器代码是frag函数 #pragma fragment frag //顶点着色器函数,v为形参名称,POSITION为CG/HLSL的语义,代表将模型的顶点坐标输入,SV_POSITION也是CG/HLSL的语义,代表输出为裁剪空间中的顶点坐标 float4 vert(float4 v : POSITION) : SV_POSITION { return UnityObjectToClipPos(v); } //片元着色器函数,SV_Target语义代表将输出颜色存储到一个渲染目标中 fixed4 frag() : SV_Target { return fixed4(1.0, 0.0, 0.0, 1.0); } ENDCG } } }
1.2 模型数据从哪里来
在着色器中使用语义(semantics)定义数据的来源,想得到更多的数据,我们可以定义一个结构体参数获取这些数据:
Shader " Unity Shaders Book/Chapter 5/ Simple Shader" { SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag //使用结构体定义参数 struct a2v { //POSITION语义,代表使用模型空间的顶点坐标填充这个变量 float4 vertex : POSITION; //NORMAL语义,代表使用模型空间的法线方向填充这个变量 float3 normal : NORMAL; //TEXCOORD0语义,代表使用模型的第一套纹理坐标填充这个变量 float4 texcoord : TEXCOORD0; }; //顶点着色器函数 float4 vert(a2v v) : SV_POSITION { return UnityObjectToClipPos(v.vertex); } fixed4 frag() : SV_Target { return fixed4(1.0, 0.0, 0.0, 1.0); } ENDCG } } }
1.3 顶点着色器和片元着色器之间的通信
Shader " Unity Shaders Book/Chapter 5/ Simple Shader" { SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag struct a2v { float4 vertex : POSITION; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; }; //在结构体中存储顶点着色器的输出 struct v2f { //SV_POSITION语义代表这里存储了裁剪空间的位置信息 float4 pos : SV_POSITION; //COLOR0语义用于存储颜色信息 fixed3 color : COLOR0; }; v2f vert(a2v v) { //声明一个结构体 v2f o; o.pos = UnityObjectToClipPos(v.vertex); //根据发现方向计算一个颜色并存储 o.color = v.normal * 0.5 + fixed3(0.5, 0.5, 0.5); return o; } fixed4 frag(v2f i) : SV_Target { //将插值后的颜色显示到屏幕上 return fixed4(i.color, 1.0); } ENDCG } } }
注意:
1)在结构体v2f中,必须包含语义为SV_POSITION的float4类型变量,否则片元着色器无法得到片元的位置信息;
2)顶点着色器输出的v2f结构体中存储的信息和片元着色器中输入的v2f结构体中的信息并不一致,片元着色器得到的点可能是三角片元内的点,它的信息是经过三角形顶点的插值得到的.
1.4 如何使用属性
Shader " Unity Shaders Book/Chapter 5/ Simple Shader" { Properties { //声明一个color类型的属性 //属性名_Color, 在Shader属性面板中显示名称Color Tint,属性类型Color, 属性默认值(1.0, 1.0, 1.0, 1.0) _Color("Color Tint", Color) = (1.0, 1.0, 1.0, 1.0) } SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag //在CG代码中,需要定义一个与属性名称相同,类型匹配的变量,才能使用这个变量 fixed4 _Color; struct a2v { float4 vertex : POSITION; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; }; struct v2f { float4 pos : SV_POSITION; fixed3 color : COLOR0; }; v2f vert(a2v v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); 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; //使用_Color属性控制颜色输出 c *= _Color.rgb; return fixed4(c, 1.0); } ENDCG } } }
ShaderLab的属性类型和Cg的变量类型匹配关系如下:
2.Unity提供的内置文件
在Unity中,包含文件的后缀是.cginc.在编写Shader是,可以使用#include指令将这些文件包含进来,类似于C#包含其他命名空间.#include指令在CGPROGRAM和ENDCG中间的代码块中定义.
3.Unity提供的Cg/HLSL语义
3.1 语义的概念
语义(semantics)是一个赋给Shader输入和输出的字符串,这个字符串表达了这个参数的含义.通常情况下,语义可以让我们指定Shader从哪里读取数据,或者指定Shader将数据输出到哪里.
一些语义有特殊的含义规定,如TEXCOORD0,但是其他语义则没有这样的含义,如COLOR0,这些语义修饰的变量Shader并不关心它是用来做什么的,我们可以自己决定这些变量的用途.
在DirecX 10以后,出现了一种新的语义类型:系统数值语义(system-value semantics).系统数值语义都是以SV(system value)开头的,如SV_POSITION.在Unity中有时系统数值语义和普通语义是可以替换的,但是最好使用系统数值语义,因为某些平台上必须使用系统数值语义.
3.2 Unity支持的语义
3.3 CG的数据类型
Cg支持7种基础数据类型:
1)float, 32位浮点数据
2)half, 16位浮点数据
3)fixed, 12位定点数据
4)int, 32位整形数据
5)bool, 布尔数据
6)sampler*, 纹理对象的句柄,分为6类:sampler, sampler1D, sampler2D, sampler3D, samplerCUBE, samplerRECT
7)string, 字符类型(几乎不会用到)
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/279378.html