以下の内容はhttps://hacchi-man.hatenablog.com/entry/2024/11/11/220000より取得しました。


【Unity】ビルボードシェーダーの実装方法

今回は、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);

動作確認

このシェーダを適用して、カメラを様々な位置や角度に動かしてみました。その結果、ビルボードは常にカメラを正面に向きました




以上の内容はhttps://hacchi-man.hatenablog.com/entry/2024/11/11/220000より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14