目录:Unity Shader - 知识点目录(先占位,后续持续更新) 原文:Providing vertex data to vertex programs 版本:2019.1
Providing vertex data to vertex programs给顶点着色器提供顶点数据
对于 Cg/HLSL 的顶点程序来说,网格的顶点数据需要传入到顶点着色器函数。每个输入的数据都需要指定 semantic (语义) :如,POSITION 代表输入顶点的坐标,NORMAL 代表顶点法线。
通常来说,顶点的输入数据定义在一个结构体,而不是一个一个的在函数里头声明定义。一些常用的顶点结构都定义在 UnityCG.cginc include file,大多数情况下这些结构都够用。这些结构体是:
- appdata_base:坐标,法线和一个纹理坐标。
- appdata_tan:坐标,切线,法线和一个纹理坐标。
- appdata_full:坐标,切线,法线,四个纹理坐标和一个颜色。
例如:下面的shader中,网格的颜色是基于法线来定,且使用 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 = UnityObjectToClipPos(v.vertex);
o.color.xyz = v.normal * 0.5 + 0.5;
o.color.w = 1.0;
return o;
}
fixed4 frag (v2f i) : SV_Target { return i.color; }
ENDCG
}
}
}
访问不同的顶点数据,你需要定义顶点数据结构体,或是给顶点着色器函数添加参数的方式。顶点数据都是以 Cg/HLSL semantics(语义)来识别的,必须是一下这些语义:
- POSITION 是顶点的坐标,通常是 float3 或是 float4。
- NORMAL 是顶点的法线,通常是 float3。
- TEXCOORD0 是第一个UV坐标,通常是 float2,float3 或是 float4。
- TEXCOORD1,TEXCOORD2,TEXCOORD3 分别是第二,第三和第四个UV坐标。
- TANGENT 是切向量(用于法线映射),通常是 float4。
- COLOR 是顶点的颜色,通常是 float4。
当网格数据分量数的比顶点着色器输入指定类型的数据分量数少时,那么其余的都用0填充,只有.w分量默认值为1。如,网格的纹理坐标通常是2D向量,有x和y分量。如果顶点着色器定义为一个 float4 类型,并使用 TEXCOORD0 语义,那么在顶点着色器接收该 float4 数据实际值就是:(x,y,0,1)。
Examples例子
Visualizing UVs可视化UV
接下来着色器的例子将使用顶点坐标和第一个纹理坐标作为顶点着色器输入数据结构(定义于 appdata 结构体)。这个 shader 用于调试网格的UV坐标是很有用的。
Shader "Debug/UV 1" {
SubShader {
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
// 顶点输入:坐标,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 = UnityObjectToClipPos(v.vertex );
o.uv = float4( v.texcoord.xy, 0, 0 );
return o;
}
half4 frag( v2f i ) : SV_Target {
half4 c = frac( i.uv );
if (any(saturate(i.uv) - i.uv))
c.b = 0.5;
return c;
}
ENDCG
}
}
}
这里的UV坐标被可视化为红和绿颜色,当UV坐标唱过0-1范围的都显示为蓝色: 调试UV1着色器应用在圆环结(麻花结)的模型上
类似的,着色器可视化模型的第二个UV:
Shader "Debug/UV 2" {
SubShader {
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
// 顶点输入:坐标,第二个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 = UnityObjectToClipPos(v.vertex );
o.uv = float4( v.texcoord1.xy, 0, 0 );
return o;
}
half4 frag( v2f i ) : SV_Target {
half4 c = frac( i.uv );
if (any(saturate(i.uv) - i.uv))
c.b = 0.5;
return c;
}
ENDCG
}
}
}
Visualizing vertex colors
可视化顶点颜色
接下来的shader使用顶点的坐标和顶点颜色作为顶点输入的数据结构(定义在 appdata 结构体)。
Shader "Debug/Vertex color" {
SubShader {
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
// 顶点输入:坐标,颜色
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 = UnityObjectToClipPos(v.vertex );
o.color = v.color;
return o;
}
fixed4 frag (v2f i) : SV_Target { return i.color; }
ENDCG
}
}
}
调试颜色着色器应用于带有烘焙光照颜色的圆环结模型
可视化法线
下面的shader使用顶点坐标和法线作为顶点着色器的输入结构(定义在 appdata 结构体)。法线的 X,Y,Z分量可视化为RGB颜色。因为法线分量的数据范围是-1 ~ 1的,我们需要缩放和偏移它们,以便它们能用于显示颜色的数据范围: 0 ~ 1。
Shader "Debug/Normals" {
SubShader {
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
// 顶点输入:坐标,法线
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 = UnityObjectToClipPos(v.vertex );
o.color.xyz = v.normal * 0.5 + 0.5;
o.color.w = 1.0;
return o;
}
fixed4 frag (v2f i) : SV_Target { return i.color; }
ENDCG
}
}
}
调试法线着色器应用于圆环结模型。你可以看到模型的着色带有硬边缘。
可视化切线与副切线
切线与副切线向量用于法线映射。在Unity仅有切线向量存在顶点在,而副切线是从法线与切线推导出来的。
下面的shader使用顶点的坐标和切线作为顶点着色器的输入(定于在 appdata 结构体)。切线的x,y,z分量可视化为RGB颜色。因为法线的分量都是 -1 ~ 1的范围,我们缩放和偏移它们以便于输出到显示颜色的范围:0 ~ 1。
Shader "Debug/Tangents" {
SubShader {
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
// 顶点输入:坐标,切线
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 = UnityObjectToClipPos(v.vertex );
o.color = v.tangent * 0.5 + 0.5;
return o;
}
fixed4 frag (v2f i) : SV_Target { return i.color; }
ENDCG
}
}
}
调试切线着色器应用于圆环结模型。
下面的shader可视化副切线。使用顶点的坐标,法线和切线作为顶点的输入。副切线(某些情况也叫副法线)是从法线和切线计算得来的。它需要被缩放和偏移到显示颜色的范围:0 ~ 1。
Shader "Debug/Bitangents" {
SubShader {
Pass {
Fog { Mode Off }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
// 顶点输入:坐标,法线,切线
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 = UnityObjectToClipPos(v.vertex );
// 计算副切线
float3 bitangent = cross( v.normal, v.tangent.xyz ) * v.tangent.w;
o.color.xyz = bitangent * 0.5 + 0.5;
o.color.w = 1.0;
return o;
}
fixed4 frag (v2f i) : SV_Target { return i.color; }
ENDCG
}
}
}
调试副切线着色器应用于圆环结模型。
延伸阅读
- Shader Semantics
- Vertex and Fragment Program Examples
- Built-in Shader Include Files