今回は、Unityでビルボードシェーダを実装し、カメラに常に正面を向くようにする方法について解説します。
ビルボードとは
ビルボードは、オブジェクト(通常は平面)が常にカメラを向くように描画するシェーダです。これにより、2Dのテクスチャを3D空間で立体的に見せることができます。ゲーム開発では、パーティクルエフェクトなどによく使用されます。
Shader
このシェーダでは、カメラの位置とワールドの上方向ベクトルを使用して、ビルボードが常にカメラを正面に向くようにしています。
Shader "Custom/Billboard_Full_NoCameraUp"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "Queue"="Transparent" "RenderType"="Transparent" }
Blend SrcAlpha OneMinusSrcAlpha
Cull Off
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
float4 _MainTex_ST;
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
v2f vert (appdata v)
{
v2f o;
// オブジェクトのスケールを取得
float3 scale = float3(
length(unity_ObjectToWorld._m00_m10_m20),
length(unity_ObjectToWorld._m01_m11_m21),
length(unity_ObjectToWorld._m02_m12_m22)
);
// オブジェクトの中心位置を取得
float3 worldPos = mul(unity_ObjectToWorld, float4(0, 0, 0, 1)).xyz;
float3 cameraPos = _WorldSpaceCameraPos;
float3 toCamera = normalize(cameraPos - worldPos);
float3 up = float3(0, 1, 0);
if (abs(dot(toCamera, up)) > 0.9999)
{
// カメラが真上または真下にある場合の右方向ベクトル
up = float3(1, 0, 0);
}
float3 right = normalize(cross(up, toCamera)) * scale.x;
up = normalize(cross(toCamera, right)) * scale.y;
float3 pos = worldPos + right * v.vertex.x + up * v.vertex.y;
o.vertex = UnityWorldToClipPos(pos);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
return col;
}
ENDCG
}
}
}
シェーダの解説
右方向ベクトルと上方向ベクトルの再計算
// up と toCamera の外積から右方向ベクトルを計算します。 float3 right = normalize(cross(up, toCamera)) * scale.x; // 新しい right と toCamera の外積から上方向ベクトルを再計算します。 up = normalize(cross(toCamera, right)) * scale.y;
ビルボードの頂点位置を計算
// オブジェクトの中心位置に、頂点のローカル座標を right と up でスケーリングして加算します。 float3 pos = worldPos + right * v.vertex.x + up * v.vertex.y; o.vertex = UnityWorldToClipPos(pos);
動作確認
このシェーダを適用して、カメラを様々な位置や角度に動かしてみました。その結果、ビルボードは常にカメラを正面に向きました
