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"
}
发布了31 篇原创文章 · 获赞 4 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43813453/article/details/101039775