#pragma vertex vert #pragma fragment frat
告诉Unity那个函数包括顶点着色器的代码,哪个函数包括片元着色器的代码。
float4 vert(float4 v : POSITION) SV_POSITION{ return mul(UNITY_MATRIX_MVP,v); }
vert 中包含了这个顶点的位置,这是通过 POSITION 语义定义的。
输出值为裁切空间中的顶点坐标,这是通过 SV_POSITION 语义定义的。
//使用一个结构体来定义顶点着色器的输入 struct a2v { //POSITION 语义告诉 Unity,用模型空间的顶点坐标填充vertex变量 float4 vertex : POSITION; //NORMAL 语义告诉Unity,用模型空间的法线方向填充normal变量 float3 noremal : NORMAL; //TEXCOORD0语义告诉Unity,用模型的第一套纹理坐标填充texcoord变量 float4 texcoord : TEXCOORD0; }; float4 vert(a2v v) : SV_POSITION { return UnityObjectToClipPos(v.vertex); }
需要获取多个顶点信息,需要创建一个结构,并且作为参数传递给顶点着色器代码块。
在顶点着色器代码块中,返回值输出一个与片元着色器参数类型相同的结构体。
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); }
Properties语义块中可以定义一些参数由编辑器的材质面板调节。
ShaderLab属性类型 | CG变量类型 |
---|---|
Color,Vector | float4,half4,fixed4 |
Range,Float | float,half,fixed |
2D | sampler2D |
Cube | samplerCube |
3D | sampler3D |
包含文件,类似c++中的头文件的一种。在Unity中它们的后缀为.cginc。使用#include可以把它们包含进来。
这些文件可以在官方网站上选择下载->内置着色器来直接下载。这些文件是非常好的参考资料,在我们想要学习内置着色器的实现或是寻找内置函数的实现时,都可以在这里找到内部实现。
我们可以直接在Unity的应用程序中找到
Mac:/Application/Unity/Unity.app/Content/CGIncludes
Windows:Unity安装路径/Data/CGIncludes
文件名 | 描述 |
---|---|
UnityCG.cginc | 包含了最常使用的帮助函数、宏和结构体 |
UnityShaderVariables.cginc | 在编译Unity Shader时,会被自动包含进来。包含了许多内置的全局变量,如UNITY_MATRIX_MVP等 |
Lighting.cginc | 包含了各种内置的光照模型,如果编写的是Surface Shader的话,会自动包含进来 |
HLSLSupport.cginc | 在编译Unity Shader时,会自动包含进来。声明了很多用于跨平台编译的宏和定义 |
UnityCG.cginc 是最常接触的一个包含文件。
名称 | 描述 | 包含的变量 |
---|---|---|
appdata_base | 可用于顶点着色器的输入 | 顶点位置、顶点法线、第一组纹理坐标 |
appdata_tan | 可用于顶点着色器的输入 | 顶点位置、顶点切线、顶点法线、第一组纹理坐标 |
appdata_full | 可用于顶点着色器的输入 | 顶点位置、顶点切线、顶点法线、四组(或更多)纹理坐标 |
appdata_img | 可用于顶点着色器的输入 | 顶点位置、第一组纹理坐标 |
v2f_img | 可用于顶点着色器的输出 | 裁剪空间中的位置、纹理坐标 |
函数名 | 描述 |
---|---|
float3 WorldASpaceViewDir(float4 v) | 输入一个模型空间中的顶点位置,返回世界空间中从该点到摄像机的观察方向 |
float3 ObjSpaceViewDir(float4 v) | 输入一个模型空间中的顶点位置,返回模型空间中从该点到摄像机的观察方向 |
float3 WorldSpaceLightDir(float4 v) | 仅可用于前向渲染。输入一个模型空间中的额顶点位置,返回世界空间中从该点到光源的光照方向。没有被归一化。 |
float3 ObjSpaceLightDir(float4 v) | 仅可用于前向渲染中。输入一个模型空间中的顶点位置,返回模型空间中从该点到光源的光照方向。没有被归一化。 |
float3 UnityObjectToWorldNormal(float3 norm) | 把法线方向从模型空间转换到世界空间中 |
float3 UnityObjectToWorldDir(in float3 dir) | 把矢量方向从模型空间变换到世界空间中 |
float3 UnityWorldToObjectDit(float3 dir) | 把矢量方向从世界空间变换到模型空间中 |
语义可以让Shader知道从哪里读取数据,并把数据输出到哪
之前代码中的POSITION NORMAL SV_POSIONT 等就是语义
语义 | 描述 |
---|---|
POSITION | 模型空间中的顶点位置,通常是float4类型 |
NORMAL | 顶点法线,通常是float3类型 |
TANGENT | 顶点切线,通常是float4类型 |
TEXCOORDn,如TEXCOORD0、TEXCOORD1 | 该顶点的纹理坐标,TEXCOORD0表示第一组纹理坐标,以此类推。通常是float2或float4类型 |
COLOR | 顶点颜色,通常是fixed4或float4类型 |
语义 | 描述 |
---|---|
SV_POSITION | 裁剪空间中的坐标顶点,结构体中必须包含一个用该语义修饰的变量。等同于DirectX9中的POSITION,但最好使用SV_POSITION |
COLOR0 | 通常用于输出第一组顶点颜色,但不是必须的 |
COLOR1 | 通常用于输出第二组顶点颜色,但不是必须的 |
TEXCOORD0~TEXCOORD7 | 通常用于输出纹理坐标,但不是必须的 |
语义 | 描述 |
---|---|
SV_Target | 输出值将会存储到渲染目标(render target)中。等同于DirexX 9中的COLOR语义,但最好使用SV_Target |
可以将法线,切线向量值对应到RGB颜色值,然后在画面颜色显示中来判断。
使用Unity中的帧调试器(Window->Frame Debugger)可以更方便进行调试。
Unity的有点之一就是跨平台性很强,写一份代码就可以在多平台上运行。但绝大多数情况下,Unity为我们隐藏了这些细节,但有时候我们还是需要自己处理。
#if UNITY_UV_STARTS_AT_TOP if(_MainTex_TexelSize.y < 0){ uv.y = 1 - uv.y; } #endif
其中UNITY_UV_STARTS_AT_TOP用来判断当前平台是不是DirectX类型的平台。通过判断_MainTex_TexelSize.y是否小于0来判断是否打开了抗锯齿。