Billboarding
原理
Billboarding通常会根据需求来旋转一个被纹理着色的多边形,本质上是构建一个旋转矩阵,通常是基于法线或者基于向上的方向,还需要设定锚点来确定多边形在空间中的位置。
难点在于法线和向上的方向常常不是垂直的,需要构建的矩阵由法线方向(normal),向上的方向(up)和向右的方向(right)组成
- right = normal x up
- up’ = normal x right
如图,通过视线作为一个轴,获取设定好的向上方向之后,获取向右的方向,因为向上的向量恒定不变,因此叉乘出来的向右向量由视线决定,在更新了向右向量之后再反过来影响向上的向量。(图片来自shader入门精要)
实现
参考《Unity Shader入门精要》
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| v2f vert (appdata v){ v2f o; float3 center = float3(0,0,0); half3 view_model = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos, 1)); half3 normal_dir = view_model - center; normal_dir.y = normal_dir.y * _VerticalBillboarding; normal_dir = normalize(normal_dir); half3 up_dir = abs(normal_dir.y)>0.999?half3(0,0,1):half3(0,1,0); half3 right_dir = normalize(cross(up_dir, normal_dir)); up_dir = normalize(cross(normal_dir, right_dir));
half3 centerOffs = v.vertex.xyz - center; float3 localPos = center + right_dir * centerOffs.x + up_dir * centerOffs.y + normal_dir * centerOffs.z; o.pos = UnityObjectToClipPos(float4(localPos, 1)); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); return o; }
fixed4 frag (v2f i) : SV_Target{ fixed4 col = tex2D(_MainTex, i.uv); col.rgb = _Color.rgb * col.rgb; return col; }
|
图中是向上向量和视线向量分别来作为恒定轴时候的效果(图片来自shader入门精要)
优化
如果单纯只是想实现一直朝向的效果,那么可以进行如下优化,因为本质上是通过构建旋转矩阵追踪视角变换的朝向,并将朝向的变换应用到物体上,那么反过来想,抵消掉物体朝向的变换也是可以的,因此通过mv矩阵的逆可以实现同样的保存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| v2f vert (appdata v) { v2f o; float3 localPos = mul(UNITY_MATRIX_T_MV, v.vertex.xyz); o.pos = UnityObjectToClipPos(float4(localPos, 1)); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); return o; } fixed4 frag (v2f i) : SV_Target { fixed4 col = tex2D(_MainTex, i.uv); col.rgb = _Color.rgb * col.rgb * _Intensity; return col; }
|
效果