顶点数据必须以一个结构的形式提交给 Cg/HLSL 顶点程序。几个常用的顶点结构定义在UnityCG.cginc 包含文件,大多数情况下只使用它们就足够了。这些结构是:
例如,该着色器基于网格的法线来着色网格,且只使用 appdata_base 作为顶点程序输入:
Shader "VertexInputSimple" { SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct v2f { float4 pos : SV_POSITION; fixed4 color : COLOR; }; v2f vert (appdata_base v) { v2f o; o.pos = mul (UNITY_MATRIX_MVP, v.vertex); o.color.xyz = v.normal * 0.5 + 0.5; o.color.w = 1.0; return o; } fixed4 frag (v2f i) : COLOR0 { return i.color; } ENDCG } } }
如果您想访问不同的顶点数据,您就必须自己声明顶点结构。结构成员必须是下面列出的成员:
以下着色器示例使用顶点位置和第一个纹理坐标作为顶点着色器输入(定义在结构 appdata 中)。调试网格的 UV 坐标是非常有用的。UV 坐标被可视化为红色和绿色,0..1 范围外的坐标额外应用蓝色色调。
Shader "!Debug/UV 1" { SubShader { Pass { Fog { Mode Off } CGPROGRAM #pragma vertex vert #pragma fragment frag // 顶点输入:位置、UV struct appdata { float4 vertex : POSITION; float4 texcoord : TEXCOORD0; }; struct v2f { float4 pos : SV_POSITION; float4 uv : TEXCOORD0; }; v2f vert (appdata v) { v2f o; o.pos = mul( UNITY_MATRIX_MVP, v.vertex ); o.uv = float4( v.texcoord.xy, 0, 0 ); return o; } half4 frag( v2f i ) : COLOR { half4 c = frac( i.uv ); if (any(saturate(i.uv) - i.uv)) c.b = 0.5; return c; } ENDCG } } }
类似地,这个着色器使模型的第二个 UV 集可视化:
Shader "!Debug/UV 2" { SubShader { Pass { Fog { Mode Off } CGPROGRAM #pragma vertex vert #pragma fragment frag // 顶点输入:位置、第二个 UV struct appdata { float4 vertex : POSITION; float4 texcoord1 : TEXCOORD1; }; struct v2f { float4 pos : SV_POSITION; float4 uv : TEXCOORD0; }; v2f vert (appdata v) { v2f o; o.pos = mul( UNITY_MATRIX_MVP, v.vertex ); o.uv = float4( v.texcoord1.xy, 0, 0 ); return o; } half4 frag( v2f i ) : COLOR { half4 c = frac( i.uv ); if (any(saturate(i.uv) - i.uv)) c.b = 0.5; return c; } ENDCG } } }
以下着色器使用顶点位置和逐顶点颜色作为顶点着色器输入(定义在结构 appdata 中)。
Shader "!Debug/Vertex color" { SubShader { Pass { Fog { Mode Off } CGPROGRAM #pragma vertex vert #pragma fragment frag // 顶点输入:位置、颜色 struct appdata { float4 vertex : POSITION; fixed4 color : COLOR; }; struct v2f { float4 pos : SV_POSITION; fixed4 color : COLOR; }; v2f vert (appdata v) { v2f o; o.pos = mul( UNITY_MATRIX_MVP, v.vertex ); o.color = v.color; return o; } fixed4 frag (v2f i) : COLOR0 { return i.color; } ENDCG } } }
以下着色器使用顶点位置和法线作为顶点着色器输入(定义在结构 appdata 中)。法线的 X、Y、Z 组件被可视化为 R、G、B 颜色。因为法线组件在 -1..1 范围内,所以我们对其进行缩放和偏移,使得输出颜色在可显示的 0..1 范围内。
Shader "!Debug/Normals" { SubShader { Pass { Fog { Mode Off } CGPROGRAM #pragma vertex vert #pragma fragment frag // 顶点输入:位置、法线 struct appdata { float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f { float4 pos : SV_POSITION; fixed4 color : COLOR; }; v2f vert (appdata v) { v2f o; o.pos = mul( UNITY_MATRIX_MVP, v.vertex ); o.color.xyz = v.normal * 0.5 + 0.5; o.color.w = 1.0; return o; } fixed4 frag (v2f i) : COLOR0 { return i.color; } ENDCG } } }
切线和副法线向量用于法线贴图。在 Unity 中,只有切线向量储存在顶点中,副法线衍生自法线和切线。
以下着色器使用顶点位置和切线作为顶点着色器输入(定义在结构 appdata 中)。切线的 X、Y、Z 组件被可视化为 R、G、B 颜色。因为法线组件在 -1..1 范围内,所以我们对其进行缩放和偏移,使得输出颜色在可显示的 0..1 范围内。
Shader "!Debug/Tangents" { SubShader { Pass { Fog { Mode Off } CGPROGRAM #pragma vertex vert #pragma fragment frag // 顶点输入:位置、切线 struct appdata { float4 vertex : POSITION; float4 tangent : TANGENT; }; struct v2f { float4 pos : SV_POSITION; fixed4 color : COLOR; }; v2f vert (appdata v) { v2f o; o.pos = mul( UNITY_MATRIX_MVP, v.vertex ); o.color = v.tangent * 0.5 + 0.5; return o; } fixed4 frag (v2f i) : COLOR0 { return i.color; } ENDCG } } }
以下着色器使副法线可视化。它使用顶点位置、法线和切线作为顶点输入。副法线是从法线和切线计算出的。就像法线和切线一样,需要将其缩放并偏移到可显示的 0..1 范围内。
Shader "!Debug/Binormals" { SubShader { Pass { Fog { Mode Off } CGPROGRAM #pragma vertex vert #pragma fragment frag // 顶点输入:位置、法线、切线 struct appdata { float4 vertex : POSITION; float3 normal : NORMAL; float4 tangent : TANGENT; }; struct v2f { float4 pos : SV_POSITION; float4 color : COLOR; }; v2f vert (appdata v) { v2f o; o.pos = mul( UNITY_MATRIX_MVP, v.vertex ); // 计算副法线 float3 binormal = cross( v.normal, v.tangent.xyz ) * v.tangent.w; o.color.xyz = binormal * 0.5 + 0.5; o.color.w = 1.0; return o; } fixed4 frag (v2f i) : COLOR0 { return i.color; } ENDCG } } }
Page last updated: 2013-06-26