Cg Programming/Unity/Billboards广告牌

时间:2022-05-10 04:20:56

本教程介绍了广告牌技术
它是基于章节“纹理球体”以及章节“顶点变换”。

广告牌

Cg Programming/Unity/Billboards广告牌
在计算机图形学中,广告牌是变换着的有纹理的矩形,这样它们可以总是跟视平面平行。因此,它们跟高速公路上的广告牌很相似,它们被旋转以达到最佳的可见性。但是,它们跟高速公路上的广告牌又不一样,因为它们会动态旋转以便可以提供最佳的可见性。

广告牌主要的用处在于用二维图像来替换复杂的三维模型。实际上,Unity也会使用广告牌来渲染草。此外,广告牌也通常被用来渲染二维精灵。在以上这两种应用中,至关重要的是广告牌总是跟视平面平行以维持一个三维形状的错觉,虽然只是一个二维的图像被渲染。

广告牌的顶点变换

跟章节“天空盒”类似,我们可以使用默认的立方体物对象来渲染一个广告牌。(要使用默认的四边形(GameObject–>3D Objects–>Quad),你应该在代码中把减号改为加号。对于默认的平面(GameObject– > 3D Objects– > Plane),你应该用z坐标替换y坐标。)基本的想法是用标准模型视图变换UNITY_MATRIX_MV把模型空间的原点(0, 0, 0, 1)变换到观察空间中去。(在齐次坐标系中所有点的第四个坐标都是1;参考章节“顶点变换”中的讨论。)观察空间只是一个世界空间的旋转版本,它的xy平面平行于章节“顶点变换”中讨论的观察平面。于是,我们就有了正确的空间来构造一个适当的旋转广告牌。我们从观察坐标中变换的原点减去x和y对象坐标(vertex.xvertex.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的批处理操作。