最简Shader框架
unity的shader基础的一些知识可以从阅读笔记一中获得。
这里讲一些最简框架,之后的shader其实都可以从最简框架中来扩展。
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader"Custom/1.1.1"{
//lowest level shader
Subshader{
Pass{
//渲染通道,用来完整描述一个渲染流水线
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
//定义基本的顶点着色器的编程函数,以及片元着色器的编程函数。
float4 vert(float4 v:SV_POSITIO):SV_POSITION {
return UnityObjectToClipPos(v);
//矩阵乘法,将模型空间中的点,转到齐次剪裁空间中。
}
float4 frag() :SV_Target {//SVTarget是着色器的语义
return fixed4(1.0,1.0,1.0,1.0);
//定义所有的片元光栅化的颜色为白色。
}
ENDCG
}
}
}
这里可以看到,这个可以称之为最简框架,虽然很小,但是包含有基本的一些内容。
这里有些地方需要做一些笔记:
- shader脚本在unity里面其实已经简化了很多。这脚本里面主要有Unity的shaderLab脚本以及CG脚本组成。
- shaderLab脚本主要是出unity用来标记的一些部分
- CG脚本主要是CGPROGRAM 到 ENDCG部分的脚本。
- SV_POSITION,SV_POSITIO,这些都是语义,用来描述类型和属性,告诉GPU,这些是什么类型。
- 函数中float4 vert(float4 v:SV_POSITIO):SV_POSITION,括号中冒号后的SV_POSITIO的语义是对输入参数进行描述,而括号外的SV_POSITION是对输出参数进行描述。
- 函数的命名可以通过宏来自定义,通过#pragma语句来。
- Pass里面其实使用CG语言去定义了一个完整的渲染流程。
在最简Shader框架增加结构体1
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader"Custom/1.1.2"{
Subshader{
Pass{
//渲染通道,用来完整描述一个渲染流水线
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
//应用2顶点着色器
struct a2v {//名称不能自定义
//这里面定义顶点着色器的输入
//每个输入都需要填写类型,名称,语义
float4 ve:POSITION;//每一个定义以分号结尾
float4 tex:TEXCOORD0;//输入一个纹理信息
float3 normal:NORMAL;
};//这里需要注意,需要有个分号
//定义基本的顶点着色器的编程函数,以及片元着色器的编程函数。
float4 vert(a2v v) : SV_POSITION {//SV_POSITION在这里用来描述输出的语义
return UnityObjectToClipPos(v.ve);
//矩阵乘法,将模型空间中的点,转到齐次剪裁空间中。
}
float4 frag() :SV_Target {//SVTarget是着色器的语义
return fixed4(1.0,1.0,1.0,1.0);
//定义所有的片元光栅化的颜色为白色。
}
ENDCG
}
}
}
这里面相对与之前的最简框架进行了一些添加,主要添加了一个结构体:
- 结构体的使用与传统的C语言的结构体相似,但是命名上面需要按照一定规则:a代表应用,v代表顶点。这里其实就对应渲染管线中的一些内容:顶点着色器的输入内容其实是应用阶段(application)经过处理传来的值。
- 结构体重定义了几个变量,变量的名称可以自定义,但是语义不能。语义就是告诉GPU,这个变量的具体用处,不然同样是float4,ve和tex就没区别了。
- float4可以看成是行向量或者是列向量,具体怎么看要看和矩阵的乘法是左边还是右边。
- 由于输入的时候传入的是结构体,所以在输入参数是不用写语义的。
在最简Shader框架增加结构体2
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader"Custom/1.1.3"{
Subshader{
Pass{
//渲染通道,用来完整描述一个渲染流水线
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
//应用2顶点着色器
struct a2v {//名称不能自定义
//这里面定义顶点着色器的输入
//每个输入都需要填写类型,名称,语义
float4 v:POSITION;//每一个定义以分号结尾
float4 tex:TEXCOORD0;//输入一个纹理信息
float3 normal:NORMAL;
};//这里需要注意,需要有个分号
struct v2f {//顶点着色器与片元着色器之间传值的结构体
float4 v:SV_POSITION;//不可缺少,传递剪裁空间的顶点
float3 color:COLOR0;//输入颜色
};
//定义基本的顶点着色器的编程函数,以及片元着色器的编程函数。
v2f vert(a2v v) {//当有自定义结构体的时候,取消语义描述,因为语义已经在结构体中了
v2f o;
o.v = UnityObjectToClipPos(v.v);
o.color = v.normal *0.5 + fixed3(0.5,0.5,0.5);//先缩小1/2,然后再+0.5,将范围定在0-1,现实效果就是表现出法线的方向
return o;
//矩阵乘法,将模型空间中的点,转到齐次剪裁空间中。
}
float4 frag(v2f i) :SV_Target {//SVTarget是着色器的语义
return fixed4(i.color,1.0);
//定义所有的片元光栅化的颜色为白色。
}
ENDCG
}
}
}
这里面多了一个v2f的结构体:
- v代表顶点,f代表片元着色器。
- 这里frag函数传入函数为v2f的实例,实际这个就是vert的输入参数。
- v2f中必须要定义一个SV_POSITION的参数。
连接shaderlab语言
之前所有的代码编写工作都是在顶点着色器以及片元着色器中,写成,与shaderlab语言基本上没有什么交集。
shaderlab语言是与unity项目对接的一个窗口,在这里将shaderlab与CG语言部分进行联合。
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader"Custom/1.1.4"{
Properties{
_Color("color",Color) = (1.0,1.0,1.0,1.0)//定义了一个颜色属性,并给了一个初值
}
Subshader{
Pass{
//渲染通道,用来完整描述一个渲染流水线
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
float4 _Color;//需要定义一个名称相同的变量。与properties中的相同
//应用2顶点着色器
struct a2v {//名称不能自定义
//这里面定义顶点着色器的输入
//每个输入都需要填写类型,名称,语义
float4 v:POSITION;//每一个定义以分号结尾
float4 tex:TEXCOORD0;//输入一个纹理信息
float3 normal:NORMAL;
};//这里需要注意,需要有个分号
struct v2f {//顶点着色器与片元着色器之间传值的结构体
float4 v:SV_POSITION;//不可缺少,传递剪裁空间的顶点
float3 color:COLOR0;//输入颜色
};
//定义基本的顶点着色器的编程函数,以及片元着色器的编程函数。
v2f vert(a2v v) {//当有自定义结构体的时候,取消语义描述,因为语义已经在结构体中了
v2f o;
o.v = UnityObjectToClipPos(v.v);//模型空间到剪裁空间。中间需要经历模型空间到世界空间,世界空间到齐次剪裁空间
o.color = v.normal *0.5 + fixed3(0.5,0.5,0.5);//先缩小1/2,然后再+0.5,将范围定在0-1,现实效果就是表现出法线的方向
return o;
//矩阵乘法,将模型空间中的点,转到齐次剪裁空间中。
}
float4 frag(v2f i) :SV_Target {//SVTarget是着色器的语义
fixed3 c = i.color;
c *= _Color;
return fixed4(c,1.0);
//定义所有的片元光栅化的颜色为白色。
}
ENDCG
}
}
}
这里面添加了一个Properties的模块,所有的unity窗口都在这里进行定义。
- 这里定义了一个_Color变量,这个变量名也就是我们与CG语言进行对接的一个名称,那么定义了一个color属性的变量 Color是shaderlab中的一个属性。等号后面就是初值。
- 除了Properties中的值,还需要在CG中定义一个与Properties相同的类型:float4 _Color
- 之后就能在CG语言中应用我们在unity中定义的值。