UnityShader结构
一、顶点/片元着色器的基本结构
Shader "Unlit/MyFirstShader"{ //Shader的路径跟名字
SubShader{
pass{
CGPROGRAM
#pragma vertex vert //这里是定义vert为顶点着色器的函数
#pragma fragment frag //这里是定义frag为片元着色器的函数
//下面的POSITION和SV_POSITION都是CG/HLSL中的语义。
//它们是不可忽略的,这些语义将告诉系统用户,需要哪些输入值,以及输出是什么
//以下说明:POSITION告诉Unity,把模型的顶点坐标填充到输入参数v中,SV_POSITION告诉Unity顶点着色器的输出是裁剪空间中的顶点坐标
float4 vert(float4 v : POSITION):SV_POSITION{
return mul(UNITY_MATRIX_MVP,v)
//unity中有函数:UnityObjectToClipPos(v)跟上述公式有一样的效果;
}
//片元着色器输出的颜色的每个分量范围在[0,1]中
fixed4 frag() :SV_TARGET{
return fixed4(1.0,1.0,1.0,1.0)
}
ENDCG
}
}
}
二、增加顶点着色器的输入
Shader "Unlit/MyFirstShader"
{
SubShader{
pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
//使用一个结构体来定义顶点着色器的输入
struct a2v{
//POSITION语义,用模型空间的顶点坐标填充vertex变量
float4 vertex : POSITION;
//NORMAL语义,用模型空间的法线方向填充normal变量
float3 normal : NORMAL;
//TEXCOORD0语义,用模型的第一套纹理坐标填充texcoord变量
float4 texcoord:TEXCOORD0;
};
float4 vert(a2v v):SV_POSITION{
return UnityObjectToClipPos(v.vertex);
}
fixed4 frag() :SV_TARGET{
return fixed4(1.0,1.0,1.0,1.0);
}
ENDCG
}
}
}
顶点着色器的输入格式
struct StrictName{
Type Name : Semantic;
Type Name : Semantic;
}
对于顶点着色器的输出,Unity支持的语义
- POSITION:顶点数据;
- TANGENT:切线数据
- NORMAL:法线数据
- TEXCOORD0:第一套纹理数据
- TEXCOORD1:第二套纹理数据
- COLOR:颜色
三、顶点着色器和片元着色器之间的通信
Shader "Unlit/MyFirstShader"
{
SubShader{
pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
struct a2v{
float4 vertex : POSITION;
float3 normal : NORMAL;
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{
//将插值后的i.color显示到屏幕中
return fixed4(i.color,1.0);
}
ENDCG
}
}
}
需要注意的地方:
- 顶点着色器是逐顶点调用的,片元着色器是逐片元调用的。
- 片元着色器的输入实际上是把顶点着色器的输出进行插值后得到的结果
四、使用属性
Shader "Unlit/MyFirstShader"
{
//通过定义Properties模块的增加可以在材质面板中控制的属性
Properties{
//声明一个Color类型的属性
_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中变量的类型之间的匹配的关系
ShaderLab属性类型 |
CG变量类型 |
Color,Vector |
float4,half4,fixed4 |
Range,Float |
float,half,fixed |
2D |
sampler2D |
Cube |
samplerCube |
3D |
sampler3D |
|
|
uniform 关键字
- 有时候CG变量前会有一个uniform关键字,例如:uniform fixed4 _Color;
- uniform关键字是CG中修饰变量和参数的一种修饰词,仅仅用于提供一些关于该变量的初始值是如何指定和存储的相关信息。
- 在UnityShader中,uniforme关键字可以省略。
五、Unity内置的包含文件
Unity中一些常用的包含文件
文件名 |
描述 |
UnityCG.cginc |
包含了最常用的帮助函数、宏和结构体等 |
UnityShaderVariables.cgnic |
在编译Unity Shader时,会被自动包含进来。包含了许多内置的全局变量,如UNITY_MATRIX_MVP等 |
Lighting.cgnic |
包含了各种内置的光照模型,如果编写的是Surface Shader的话,会自动包含进来 |
HLSL.Support.cginc |
在编译Unity Shader时,会被自动包含进来。声明了很多用于跨平台编译的宏和定义 |
|
|
UnityCG.cgnic中一些常用的结构体
名称 |
描述 |
包含的变量 |
appdata_base |
可用于顶点着色器的输入 |
顶点位置、顶点法线、第一组纹理坐标 |
appdata_tan |
可用于顶点着色器的输入 |
顶点位置、顶点切线、顶点法线、第一组纹理坐标 |
appdata_full |
可用于顶点着色器的输入 |
顶点位置、顶点切线、顶点法线、四组(或更多)纹理坐标 |
appdata_img |
可用于顶点着色器的输入 |
顶点位置、第一组纹理坐标 |
v2f_img |
可用于顶点着色器的输出 |
裁剪空间中的位置、纹理坐标 |
|
|
|
UnityCG.cgnic中一些常用的帮助函数
函数名 |
描述 |
float3 WorldSpaceViewDir(float4 v) |
输入一个模型空间的点,返回世界空间中从该点到摄像机的观察方向 |
float3 ObjSpaceViewDir(float4 v) |
输入一个模型空间的点,返回模型空间中从该点到摄像机的观察方向 |
float3 WorldSpaceLightDir(float4 v) |
仅可用于前向渲染。输入一个模型空间的顶点位置,返回模型空间中从该点到光源的光照方向。没有被归一化 |
float3 ObjSpaceLightDir(float4 v)` |
仅用于前向渲染。输入一个模型空间的顶点位置,返回模型空间中从该点到光源的光照方向。没有被归一化 |
float3 UnityObjectToWorldNormal(float3 norm) |
把法线方向从模型空间转换到世界空间中 |
float3 UnityObjectToWorldDir(in float3 dir) |
把方向矢量从模型空间变换到世界空间中 |
float3 UnityWorldToObjectDir(float3 dir) |
把方向矢量从世界空间变换到模型空间中 |
float3 UnityWorldSpaceViewDir(float4 v) |
输入一个世界空间的顶点位置,返回世界空间中从该点到摄像机的观察方向 |
float3 UnityWorldSpaceLightDir(float4) |
仅可用于前向渲染中。输入一个世界空间的顶点位置,返回世界空间中从该点到光源的光照方向。没有被归一化 |
|
|
从应用阶段传递模型数据给顶点着色器时Unity支持的常用语义
语义 |
描述 |
POSITION |
模型空间中的顶点位置,通常是float4类型 |
NORMAL |
顶点法线,通常是float3类型 |
TANGENT |
顶点切线,通常是float4类型 |
TEXCOORDn |
该顶点的纹理坐标,通常是float2或float4类型 |
COLOR |
顶点颜色,通常是fixed4或float4类型 |
|
|
片元着色器输出时Unity支持的常用语义
语义 |
描述 |
SV_Target |
输出值将会存储到渲染目标(render target)中。等同于DirectX9中的语义,但最好使用。 |
|
|
CG/HLSL中的3种精度的数值类型
类型 |
精度 |
float |
最高精度的浮点值。通常使用32位来存储 |
half |
中等精度的浮点值。通常使用16位来存储,精度范围是-60000~+60000 |
fixed |
最低精度的浮点数。通常使用11位来存储,精度范围是-2.0~+2.0 |
|
|
注意事项
- SV代表的含义是系统数值。
- 一个语义可以使用的寄存器只能处理4个浮点值(float)。
- 使用SV_POSITION来描述顶点着色器输出的顶点位置。
- 使用SV_Tartet来描述片元着色器的输出颜色。