摘自冯乐乐的《unity shader 入门精要》
由于之前看《Unity shader 入门精要》看到太过粗略了,只关注书中的shader代码,导致好多代码都是不是很懂,所以就往回看,
找找对于shader的一些基础知识
还是先直接上代码,注释有较为详细的一些解释,部分注释代码是由于看的内容比较多,然后就懒的分几篇博客来写了了:
1,一个简单的着色器(SimpleShader)
Shader "Custom/SimpleShader" {
SubShader
{
Pass
{
CGPROGRAM
//包含顶点着色器代码和包含片元着色器的代码的编译指令
#pragma vertex vert
#pragma fragment frag
//vert函数的输入v包含了这个顶点的位置,它是通过POSITION语义定义的
//并返回一个float4类型的变量,它是该顶点在剪裁空间中的位置,
//POSITION和SV_POSITION都是CG/HLSL的语义,它们不可省略,
//这些语义告诉用户需要哪些输入值,以及输出的是什么
//在这里POSITION告诉unity把模型顶点坐标填充到参数v中,
//SV_POSITION告诉unity顶点着色器输出的是裁剪空间的坐标
float4 vert(float4 v : POSITION) : SV_POSITION
{
//使用v.vertex来访问模型空间的顶点坐标
return mul (UNITY_MATRIX_MVP,v);
}
//在这里,frag没有任何输入,它输出了一个fixed4的类型变量,并使用了SV_Target
//进行限定
fixed4 frag() : SV_Target
{
return fixed4 (1.0, 1.0, 1.0, 1.0);
}
fixed4 frag(v2f i) : SV_Target
{
//将插值后的i.color显示到屏幕上
return fixed4(i.color, 1.0);
}
ENDCG
}
}
FallBack "Diffuse"
}
我们必须使用如下指令来声明结构体
struct StructName
{
Type Name : Semantic;
Type Name : Semantic;
<span style="white-space:pre"> </span>......
}
Shader "Custom/SimplerShader" {
SubShader
{
Pass
{
CGPROGRAM
//包含顶点着色器代码和包含片元着色器的代码的编译指令
#pragma vertex vert
#pragma fragment frag
struct a2v
{
//POSITION告诉unity,用模型空间的顶点坐标填充vertex变量
float4 vertex : POSITION;
//NORMAL告诉unity,用模型空间的法线方向填充normal变量
float3 normal : NORMAL;
//TEXCOORD0告诉unity,用模型的第一套纹理坐标填充texcrood变量
float4 texcoord : TEXCOORD0;
};
float4 vertex(a2v v) : SV_POSITION
{
//使用v.vertex来访问模型空间的顶点坐标
return mul(UNITY_MATRIX_MVP, v.vertex);
}
fixed4 frag() :SV_Target
{
return fixed4(1.0, 1.0, 1.0,1.0);
}
ENDCG
}
}
}
unity支持的语义有:POSITION,TANGENT,NORMAL,TEXCOORD0,TEXCOORD1,TEXCOORD2,TEXCOORD3,COLOR等
3.顶点着色器与片元着色器之间的通信
Shader "Custom/SimpleShader" {
SubShader
{
Pass
{
CGPROGRAM
//包含顶点着色器代码和包含片元着色器的代码的编译指令
#pragma vertex vert
#pragma fragment frag
//在CG代码中,我们需要定义一个与属性名称和类型都匹配的变量
fixed4 _Color;
struct a2v
{
//POSITION告诉unity,用模型空间的顶点坐标填充vertex变量
float4 vertex : POSITION;
//NORMAL告诉unity,用模型空间的法线方向填充normal变量
float3 normal : NORMAL;
//TEXCOORD0告诉unity,用模型的第一套纹理坐标填充texcrood变量
float4 texcoord : TEXCOORD0;
};
struct v2f
{
//SV_POSITION告诉unity,pos包含了顶点在剪裁空间中的位置信息
float4 pos : SV_POSITION;
//COLOR语义可以用于存储颜色信息
fixed3 color : COLOR0;
};
v2f vert(a2v v) : SV_POSITION
{
//声明输出结构
v2f o;
o.pos = mul (UNITY_MATRIX_MVP,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
{
//将插值后的i.color显示到屏幕上
return fixed4(i.color, 1.0);
}
ENDCG
}
}
FallBack "Diffuse"
}
4,使用属性
Shader "Custom/SimpleShader" {
Properties
{
//声明一个Color类型的属性
_Color ("Color Tint", Color) = (1, 1, 1, 1)
}
SubShader
{
Pass
{
CGPROGRAM
//包含顶点着色器代码和包含片元着色器的代码的编译指令
#pragma vertex vert
#pragma fragment frag
//在CG代码中,我们需要定义一个与属性名称和类型都匹配的变量
fixed4 _Color;
struct a2v
{
//POSITION告诉unity,用模型空间的顶点坐标填充vertex变量
float4 vertex : POSITION;
//NORMAL告诉unity,用模型空间的法线方向填充normal变量
float3 normal : NORMAL;
//TEXCOORD0告诉unity,用模型的第一套纹理坐标填充texcrood变量
float4 texcoord : TEXCOORD0;
};
struct v2f
{
//SV_POSITION告诉unity,pos包含了顶点在剪裁空间中的位置信息
float4 pos : SV_POSITION;
//COLOR语义可以用于存储颜色信息
fixed3 color : COLOR0;
};
v2f vert(a2v v) : SV_POSITION
{
//声明输出结构
v2f o;
o.pos = mul (UNITY_MATRIX_MVP,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;
//使用_Color属性来控制输出的颜色
c *= _Color.rgb;
return fixed4(c, 1.0);
}
ENDCG
}
}
FallBack "Diffuse"
}
最后给出一些ShaderLab属性类型与CG变量类型的匹配关系