廣告版
今天講一下廣告板的實現。來來來,先砸效果圖。
廣告版的意思是,雖然我只是一塊板(一個平面),但是我始終對着觀察者(打廣告)。這個對着也有兩種方式。
- 整個平面垂直於觀察者的視線向量。常用於一些閃光特效。
- y向量始終垂直於地面。常用於像草這一類需要紮根在地面上的。
所以,理一下思路。我們要做的,其實就是把平面所有點基於平面的一個錨點做一個旋轉變換。使得旋轉後的平面符合我們預期的朝向。
介紹完概念,直接開始製作。
首先我們把我們的星星資源拖拽到場景中。然後將它的位置放在屋頂,並且進行一定的縮放。
創建一個Unlit着色器,刪除全部內容。然後實現一個簡單的顯示一個2D精靈的Shader,沒什麼特別的。命名爲4_BillBorad。
Shader "Unity Shader/C4/4_BillBoard"
{
Properties {
_MainTex ("Main Tex", 2D) = "white" {}
_Color ("Main Color", COLOR) = (1, 1, 1, 1)
}
SubShader
{
Tags {
"Queue" = "Transparent"
"RenderType" = "Transparent"
"DisableBatching" = "True"
}
Blend SrcAlpha OneMinusSrcAlpha
ZWrite Off
Cull Off
Pass {
Tags {
"LightMode" = "ForwardBase"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
struct a2v {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
};
sampler2D _MainTex;
float4 _Color;
v2f vert(a2v i) {
v2f o;
o.pos = UnityObjectToClipPos(i.vertex);
o.uv = i.uv;
return o;
}
fixed4 frag(v2f i) : SV_Target {
fixed4 c = tex2D(_MainTex, i.uv);
c.rgb *= _Color.rgb;
return c;
}
ENDCG
}
}
}
創建一個材質4_Billboard_up, 並且應用上對應shader。再把這個材質拖到我們的屋頂星星上。現在的效果圖如下。
因爲我們需要所以頂點做一個相同變換,使得最終朝向滿足我們的要求。
所以第一步,構造變換矩陣的向量基。
我們能得到的第一個向量是攝像機指向物體的向量。在頂點着色器中,定義一個物體的中心點,然後把攝像機位置轉換到物體空間座標系,利用座標相減得到forward向量(頂點的朝向向量)。
v2f o;
float3 centerPos = float3(0, 0, 0);
float3 objectSpaceCameraPos = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos, 1.0));;
float3 forward = objectSpaceCameraPos - centerPos;
接着我們先定義頭頂向量爲(0, 1, 0), 然後根據叉乘得到右向量,再根據叉乘重新計算頭頂向量。讀者一定要自己搞清楚這裏面的原理,很簡單的。
forward = normalize(forward);
float3 upDir = float3(0, 1, 0);
float3 rightDir = normalize(cross(upDir, forward));
upDir = normalize(cross(forward, rightDir));
有了這個變換矩陣,我們就可以用它去左乘當前每個頂點與中心點的偏移向量。然後根據結果重新對當前頂點計算經過變換後的偏移位置。
float3 centerOffset = i.vertex.xyz - centerPos;
float3 localPos = centerPos + rightDir * centerOffset.x + upDir * centerOffset.y + forward * centerOffset.z;
o.pos = UnityObjectToClipPos(float4(localPos, 1.0));
// o.pos = UnityObjectToClipPos(i.vertex);
o.uv = i.uv;
return o;
然後現在再看下結果,就會發現我們屋頂的星星能朝着我們攝像機動了。
上面的實現屬於我們說到的,頭頂向量永遠垂直於地面。廣告版還有一種就是forward向量永遠平行於實現向量。讀者應該已經發現,如果我們把normalize.y = 0這一段代碼刪掉,那麼星星就會永遠朝向攝像機。
我們先在天空上在擺上幾個星星。
然後添加一個開關變量控制是否永遠朝向攝像機。
_MainTex ("Main Tex", 2D) = "white" {}
_Color ("Main Color", COLOR) = (1, 1, 1, 1)
[MaterialToggle] _FaceCamera ("Face Camera", FLOAT) = 0
如果朝向攝像機,那麼我們就保持forward向量的y分量。這裏我們再加個保險設置,避免forward向量和upDir向量重合。
float3 forward = objectSpaceCameraPos - centerPos;
forward.y *= _FaceCamera;
forward = normalize(forward);
// float3 upDir = float3(0, 1, 0);
float3 upDir = abs(forward.y) < 0.999 ? float3(0, 1, 0) : float3(0, 0, 1);
float3 rightDir = normalize(cross(upDir, forward));
upDir = normalize(cross(forward, rightDir));
然後我們再創建一個材質"4_Billboard_forward", 把勾選框勾選上,再把材質拖到天空中的星星上。然後我們就會發現天上的星星也在一直對着我們的攝像機拉!
結語
在本次筆者自己動手的時候遇到了幾個坑,總結一下幾個問題,大家一起去試一下吧!
- 試下用下面的代碼去求攝像機物體空間位置,會有什麼不同。
float3 objectSpaceCameraPos = mul(unity_WorldToObject, _WorldSpaceCameraPos);
- 試下把星星的縮放改成 5,5,1這種非均勻縮放,嘗試一下去解釋現象吧!
- 刪掉"Queue" = "Transparent"看看。
好啦,這次分享就到這了。支持作者專屬二維碼走起來。