unity billboard效果

這種效果是讓一個平面能跟着視角進行旋轉,從而使得該平面一直朝向着攝像機,形成一種立體的感覺.
billboard主要有兩種,第一種是固定向上方向的billboard,比如說草地,一個草地貼圖向上的方向一定是(0,1,0),unity自帶的草地就是用的這種方法的,這種固定向上方向的billboard最後形成的結果就是圖片繞着y軸進行旋轉,畢竟俯視的時候如果看到草地法線朝着視角肯定會露餡的。
第二種billboard就是固定法線的billboard,這種就是讓法線無時無刻都朝着攝像機,對於一般的例子效果是可以直接這樣做的。
這個shader最關鍵的部分就是旋轉,只要我們能構建出來一個旋轉之後的座標軸,就能得到旋轉後的座標。如下圖所示,可以假定一個上的方向,然後法線方向可以通過攝像機和頂點座標之差獲得,兩者叉乘,就可以獲得朝右的方向,然後把right和normal再進一步叉乘,就可以得到真正的UP方向了,這樣一來,我們就能得到最後的三個軸的方向。
在這裏插入圖片描述
具體實現的時候還要注意幾個點,
1.normalDir.y =normalDir.y * _VerticalBillboarding;
我們直接通過兩個極端情況來理解這個,_VerticalBillboarding爲1的時候,就是固定法線,因爲法線始終會是指向攝像機的。當_VerticalBillboarding爲0的時候,就是固定了向上的方向,這時候y是0,想象一下(x,0,z)作爲法線的平面,是不是就是繞着y軸旋轉的垂直的平面,向上的方向已經固定了。
2.假定的向上的方向的選取
float3 upDir = abs(normalDir.y) > 0.999 ? float3(0, 0, 1) : float3(0, 1, 0);
實際上,並不是一定要選取(0,0,1)作爲假定的向上的方向的,我們只是把它作爲一個過程來計算三個軸的座標,當法線就是(0,0,1)的時候,叉乘就會出現錯誤,這時候需要重新選取假定的向上的方向了。
3.旋轉過程
這個旋轉過程並不是傳統的構造旋轉矩陣進行旋轉的過程,因爲旋轉只是旋轉,並沒有進行縮放,因此,遠來座標軸上的x,y,z值可以依然保留,直接乘以新的三個座標軸的方向向量就可以旋轉了。
參考圖片如下:
在這裏插入圖片描述
無論攝像機如何移動,那些星星都會始終面朝着攝像機。
完整代碼如下:

Shader "Unity Shaders Book/Chapter 11/Billboard" {
       Properties {
              _MainTex ("Main Tex", 2D) = "white" {}
              _Color ("Color Tint", Color) = (1, 1, 1, 1)
              _VerticalBillboarding ("Vertical Restraints", Range(0, 1)) = 1
       }
       SubShader {
              // Need to disable batching because of the vertex animation
              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 "Lighting.cginc"
                     
                     sampler2D _MainTex;
                     float4 _MainTex_ST;
                     fixed4 _Color;
                     fixed _VerticalBillboarding;
                     
                     struct a2v {
                           float4 vertex : POSITION;
                           float4 texcoord : TEXCOORD0;
                     };
                     
                     struct v2f {
                           float4 pos : SV_POSITION;
                           float2 uv : TEXCOORD0;
                     };
                     
                     v2f vert (a2v v) {
                           v2f o;
                           
                           // Suppose the center in object space is fixed
                           float3 center = float3(0, 0, 0);
                           float3 viewer =  mul(unity_WorldToObject,float4(_WorldSpaceCameraPos, 1));
                           
                           float3 normalDir = viewer - center;
                           // If _VerticalBillboarding equals 1, we use the  desired view dir as the normal dir
                           // Which means the normal dir is fixed
                           // Or if _VerticalBillboarding equals 0, the y of  normal is 0
                           // Which means the up dir is fixed
                           normalDir.y =normalDir.y * _VerticalBillboarding;
                           normalDir = normalize(normalDir);
                           // Get the approximate up dir
                           // If normal dir is already towards up, then the up  dir is towards front
                           float3 upDir = abs(normalDir.y) > 0.999 ? float3(0, 0,  1) : float3(0, 1, 0);
                           float3 rightDir = normalize(cross(upDir, normalDir));
                           upDir = normalize(cross(normalDir, rightDir));
                           
                           // Use the three vectors to rotate the quad
                           float3 centerOffs = v.vertex.xyz - center;
                           float3 localPos = center + rightDir * centerOffs.x +  upDir * centerOffs.y + normalDir * centerOffs.z;              
                           o.pos = mul(UNITY_MATRIX_MVP, float4(localPos, 1));
                           o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);
                           return o;
                     }
                     fixed4 frag (v2f i) : SV_Target {
                           fixed4 c = tex2D (_MainTex, i.uv);
                           c.rgb *= _Color.rgb;
                           
                           return c;
                     }
                     
                     ENDCG
              }
       }
       FallBack "Transparent/VertexLit"
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章