Cg 编程/Unity/置换贴图
外观
本教程介绍了置换贴图,作为顶点着色器中纹理查找应用的示例。
本教程需要一些关于纹理映射的知识,如“纹理球体”部分中所述。
本维基教科书中的大多数教程仅在片段着色器中使用纹理查找,因为顶点着色器中的纹理查找是 Shader Model 3.0 特性,即,并非所有 GPU 都支持它(参见Unity 对平台特定渲染差异的描述)。
然而,置换映射需要对每个顶点进行纹理值的查找,该值用于位移,即移动每个顶点到新的位置。出于技术原因,我们不能使用标准的tex2d
命令。相反,我们必须使用命令tex2dlod
,使用一个四维向量来指定纹理坐标,其中第四个分量为 0。(这确保我们始终从最精细的mipmap级别读取值,并且我们不会请求 mipmap 级别自动计算,这在顶点着色器中是不可能的。)该命令可能如下所示
float4 dispTexColor = tex2Dlod(_DisplacementTex, float4(i.texcoord.xy, 0.0, 0.0));
其中i.texcoord.xy
是两个纹理坐标。
下面的示例将得到的颜色dispTexColor
转换为灰度值,并将其缩放为用户指定的统一_MaxDisplacement
float displacement = dot(float3(0.21, 0.72, 0.07), dispTexColor.rgb) * _MaxDisplacement;
然后,此位移值用于沿其表面法线向量移动每个顶点,即,我们将对象坐标中的顶点位置(示例中的i.vertex
)添加到与位移值相乘的表面法线向量(i.normal
)。
float4 newVertexPos = i.vertex + float4(i.normal * displacement, 0.0);
请注意,i.normal
是一个三维向量;因此,我们必须附加一个 0.0 坐标以形成一个四维向量,然后才能将其添加到顶点位置。
其余代码应用标准顶点变换,并使用无光照纹理贴图对表面进行着色。请确保将其用于具有相对较多顶点的网格上 - 否则位移表面将显得相当“块状”。
Shader "Vertex Displacement" {
Properties {
_MainTex ("Main Texture", 2D) = "white" {}
_DisplacementTex ("Displacement Texture", 2D) = "white" {}
_MaxDisplacement ("Max Displacement", Float) = 1.0
}
SubShader {
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
uniform sampler2D _MainTex;
uniform sampler2D _DisplacementTex;
uniform float _MaxDisplacement;
struct vertexInput {
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
};
struct vertexOutput {
float4 position : SV_POSITION;
float4 texcoord : TEXCOORD0;
};
vertexOutput vert(vertexInput i) {
vertexOutput o;
// get color from displacement map, and convert to float from 0 to _MaxDisplacement
float4 dispTexColor = tex2Dlod(_DisplacementTex, float4(i.texcoord.xy, 0.0, 0.0));
float displacement = dot(float3(0.21, 0.72, 0.07), dispTexColor.rgb) * _MaxDisplacement;
// displace vertices along surface normal vector
float4 newVertexPos = i.vertex + float4(i.normal * displacement, 0.0);
// output data
o.position = UnityObjectToClipPos(newVertexPos);
o.texcoord = i.texcoord;
return o;
}
float4 frag(vertexOutput i) : COLOR
{
return tex2D(_MainTex, i.texcoord.xy);
}
ENDCG
}
}
}
请注意,如果纹理图像边缘的颜色不匹配,或者对应顶点的表面法线向量不匹配,则表面网格的边缘可能无法对齐。
恭喜你,你已经完成了本教程。你看到了
- 如何在顶点着色器中使用纹理映射。
- 如何沿表面法线向量移动顶点位置。
如果你还想了解更多
- 关于纹理映射,你应该阅读“纹理球体”部分中的描述。
- 关于
tex2dlod
,你可以阅读Unity 对平台特定渲染差异的描述和Microsoft 对 tex2dlod 的描述。
除非另有说明,否则本页上的所有示例源代码均授予公有领域。