一种使得粒子效果、远处作为背景的树、都始终朝向摄像机用面片加透明贴图的方式来节省资源需要始终朝向相机
BillBoard的两种类型:1.旋转范围为球体,水平和垂直都能转,类型为Spherical
2.旋转范围为圆柱体,只能水平转,垂直方向固定
实现逻辑
两种方式:
- 脚本控制:LookAt更改面片朝向
- Shader:修改顶点坐标使顶点偏移最终使面片都整体朝向相机
基于Shader的顶点偏移
原理是计算出新的坐标系下的单位向量 将原xyz值分别乘给单位向量计算出新的顶点位置
关键:计算新的单位向量
- 用摄像机的position减去顶点position获得viewDirection但是顶点position是0,所以摄像机position就是顶点的position
- 用viewDirection叉乘0,1,0计算出右向量(先排除Y轴方向的影响)
此步需要注意不和0,1,0重合使得叉乘失败 - 再用计算出来的右方向与ViewDirection叉乘(计算Y轴影响)算出最终的单位向量
- 最后在Vertex中分别进行对应的相乘
代码实现
/*
* @Author: Tong
* @Date: 2022-05-05 16:50:02
* @LastEditors: Tong
* @LastEditTime: 2022-05-05 19:22:24
* @FilePath: \ShaderLab\Assets\Resoueces\Shader\Billboard.shader
* @Description: 实现Billboard效果,将面片动态朝向摄像头中心
*
*/
Shader "MyShader/Billboard"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
//设置枚举类别筛选球型或者圆柱形
[KeywordEnum(Spherical,Cylindrical)] _Type ("Type", float ) = 0
}
SubShader
{
Tags
{
//改状态为透明态
"RenderType"="Transparent"
//使透明物体在最后再被渲染
"Queue" = "Transparent"
//禁止批处理
"DisableBatching"="True"
}
//让雪花本身变透明
Blend OneMinusDstColor One
//将深度写入关闭保证透明物体深度正常保存
ZWrite Off
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
//声明枚举关键词
#pragma shader_feature _TYPE_SPHERICAL _TYPE_CYLINDRICAL
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
v2f vert (appdata v)
{
v2f o;
//取得相机前方向量
float3 forward = mul(unity_WorldToObject,float4(_WorldSpaceCameraPos,1)).xyz;
//判断变换类型若为圆柱则将y值设置为0
#if _TYPE_CYLINDRICAL
forward.y=0
#endif
//对viewDirection进行normalize
forward = normalize(forward);
//判断是否与y轴平行,平行则设为001,不平行则设为010,排除平行情况的影响
float3 up = abs(forward.y)>0.999 ? float3(0,0,1) : float3(0,1,0);
//首先略过Y轴高度先计算出向右的方向向量
float3 right =normalize(cross(forward,up));
//用视方向和右方向计算真实的上方向
float3 top =normalize(cross(right,forward));
//用原本的坐标在新的坐标轴下进行表示
float3 vertex=v.vertex.x*right+v.vertex.y*up;
o.vertex = UnityObjectToClipPos(vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
UNITY_TRANSFER_FOG(o,vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// sample the texture
fixed4 col = tex2D(_MainTex, i.uv);
// apply fog
UNITY_APPLY_FOG(i.fogCoord, col);
return col;
}
ENDCG
}
}
}