本教程介绍了广告牌技术。
它是基于章节“纹理球体”以及章节“顶点变换”。
广告牌
在计算机图形学中,广告牌是变换着的有纹理的矩形,这样它们可以总是跟视平面平行。因此,它们跟高速公路上的广告牌很相似,它们被旋转以达到最佳的可见性。但是,它们跟高速公路上的广告牌又不一样,因为它们会动态旋转以便可以提供最佳的可见性。
广告牌主要的用处在于用二维图像来替换复杂的三维模型。实际上,Unity也会使用广告牌来渲染草。此外,广告牌也通常被用来渲染二维精灵。在以上这两种应用中,至关重要的是广告牌总是跟视平面平行以维持一个三维形状的错觉,虽然只是一个二维的图像被渲染。
广告牌的顶点变换
跟章节“天空盒”类似,我们可以使用默认的立方体物对象来渲染一个广告牌。(要使用默认的四边形(GameObject–>3D Objects–>Quad),你应该在代码中把减号改为加号。对于默认的平面(GameObject– > 3D Objects– > Plane),你应该用z坐标替换y坐标。)基本的想法是用标准模型视图变换UNITY_MATRIX_MV
把模型空间的原点(0, 0, 0, 1)变换到观察空间中去。(在齐次坐标系中所有点的第四个坐标都是1;参考章节“顶点变换”中的讨论。)观察空间只是一个世界空间的旋转版本,它的xy平面平行于章节“顶点变换”中讨论的观察平面。于是,我们就有了正确的空间来构造一个适当的旋转广告牌。我们从观察坐标中变换的原点减去x和y对象坐标(vertex.x和vertex.y),然后用投影矩阵UNITY_MATRIX_P
变换这个结果:
output.pos = mul(UNITY_MATRIX_P,
mul(UNITY_MATRIX_MV, float4(0.0, 0.0, 0.0, 1.0))
+ float4(input.vertex.x, input.vertex.y, 0.0, 0.0));
为了让广告牌有不同的尺寸,我们添加着色器属性_ScaleX
和_ScaleY
来缩放对象坐标;于是,代码就变成了这样:
output.pos = mul(UNITY_MATRIX_P,
mul(UNITY_MATRIX_MV, float4(0.0, 0.0, 0.0, 1.0))
+ float4(input.vertex.x, input.vertex.y, 0.0, 0.0)
* float4(_ScaleX, _ScaleY, 1.0, 1.0));
除此之外,我们只需要设置纹理坐标:
output.tex = input.tex;
然后片元着色器只在插值纹理坐标中查找颜色。
完整着色器代码
Shader "Cg shader for billboards" {
Properties {
_MainTex ("Texture Image", 2D) = "white" {}
_ScaleX ("Scale X", Float) = 1.0
_ScaleY ("Scale Y", Float) = 1.0
}
SubShader {
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// User-specified uniforms
uniform sampler2D _MainTex;
uniform float _ScaleX;
uniform float _ScaleY;
struct vertexInput {
float4 vertex : POSITION;
float4 tex : TEXCOORD0;
};
struct vertexOutput {
float4 pos : SV_POSITION;
float4 tex : TEXCOORD0;
};
vertexOutput vert(vertexInput input)
{
vertexOutput output;
output.pos = mul(UNITY_MATRIX_P,
mul(UNITY_MATRIX_MV, float4(0.0, 0.0, 0.0, 1.0))
+ float4(input.vertex.x, input.vertex.y, 0.0, 0.0)
* float4(_ScaleX, _ScaleY, 1.0, 1.0));
output.tex = input.tex;
return output;
}
float4 frag(vertexOutput input) : COLOR
{
return tex2D(_MainTex, float2(input.tex.xy));
}
ENDCG
}
}
}
总结
恭喜,你完成了本教程的学习。我们看到了:
- 为了渲染视图对齐的广告牌,如何变换及映射一个立方体。
扩展阅读
备注
为了避免渲染某些广告牌时的“闪烁”,必须要在Subshader中添加如下的标记:
Tags { "DisableBatching" = "True" }
译者注:
一些SubShader在使用批处理功能时会合并所有相关模型,并统一变换到世界空间中去,而这些模型的模型空间就会丢失。所以这里要用DisableBatching
取消对该SubShader的批处理操作。