Unity Shader之广告牌

广告牌在实际游戏开发中使用非常广泛,可以用于草丛,云朵等,其实现的具体效果就是让摄像机在任意角度时,使用广告牌的物体都会面向摄像机,广告牌属于经典的顶点变换。

1. 创建相关场景,shader,材质球,和一个Quad,为了方便观察,我们将Quad沿x轴翻转50度并设置后位置,完成后效果如下:
2. 我们都知道如果想让一个物体面向摄像机的时候,需要表面法线和向上方向的垂直,但往往因物体角度的旋转导致两者并不垂直,此时我们需要固定一个方向来更正另一个方向
3. 打开shader文件,首先简单定义一下shder内属性和方法,其中_VerticalBillboarding字段用来固定一个视角
Shader "Youcai/test/BillBoard" {
    Properties{
        _MainTex("Main Tex", 2D) = "white"{}
        _Color("Main Color", Color) = (1,1,1,1)
        _VerticalBillboarding("Vertical Restraints", Range(0,1)) = 1
    }
    SubShader{
        Tags {"Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" "DisableBatching" = "True"}
        Pass
        {
            Tags {"LightMode" = "ForwardBase"}
            ZWrite off
            Blend SrcAlpha OneMinusSrcAlpha
            Cull off
            CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
            sampler2D _MainTex;
            float4 _MainTex_ST;
            fixed4 _Color;
            float _VerticalBillboarding;

            struct a2v
            {
                float4 vertex: POSITION;
                float4 texcoord : TEXCOORD0;
            };
            struct v2f
            {
                float4 pos: SV_POSITION;
                float2 uv: TEXCOORD0;
            };

            void vert(in a2v v, out v2f f)
            {
            }

            fixed4 frag(v2f f) : SV_Target
            {
            }
            ENDCG
        }

    }
    FallBack "Transparent/VertexLit"
}
4. 定义顶点着色器和片元着色器内容,其中顶点着色器内为核心部分
void vert(in a2v v, out v2f f)
{
     //计算以模型空间下原点为锚点,根据顶点位置最后做偏移
     float3 center = float3(0, 0, 0);
     //将摄像机位置转为模型空间位置
     float3 object_viewer = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos, 1));
     /*
     1. 我们首先假定摄像机到锚点位置为表面法线(不理解可以看步骤2)
     2. 通过控制法线的y轴值来确定固定的视角为法线还是向上方向
     3. _VerticalBillboarding越接近1,normalDir值y值不偏移,则越强制偏向摄像机
     */
     float3 normalDir = object_viewer - center;
     normalDir.y = (normalDir.y * _VerticalBillboarding);
     normalDir = normalize(normalDir);
     //法线应与向上方向垂直,我们通过三元表达式获取一个向上方向的大致方向
     float3 upDir = abs(normalDir.y) > 0.999 ? float3(0, 0, 1) : float3(0, 1, 0);
     //通过向上方向和法线的叉乘获得向右方向
     float3 rightDir = normalize(cross(normalDir, upDir));
     //通过向右方向在求取正确的向上方向
     upDir = normalize(cross(normalDir, rightDir));
     //获取当前顶点距锚点偏移值
     float3 centerOffs = v.vertex.xyz - center;
     //求取正确顶点位置 向右对应x轴,向上对应y轴,法线对应z轴进行偏移
     float3 localPos = center + rightDir * centerOffs.x + upDir * centerOffs.y + normalDir * centerOffs.z;
     //片元传递正确uv和坐标
     f.pos = UnityObjectToClipPos(float4(localPos, v.vertex.w));
     f.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
}

fixed4 frag(v2f f) : SV_Target
{
     fixed4 c = tex2D(_MainTex, f.uv);
     c.rgb *= _Color.rgb;
     return c;
}
5. 赋予Quad材质球,通过更改Vertical Restraints属性来查看效果吧!

你可能感兴趣的:(Unity Shader之广告牌)