【Unity】ShaderLabでビルボードを実装する #1

投稿者: | 2024-03-09

ShaderLabで、オブジェクトが常にカメラの方を向くシェーダーを作ってみました。すべての方向に自由に回転します。

概要

頂点シェーダーで、モデル変換での平行移動と、ビュー変換をスキップします。カメラの移動や回転によるオブジェクトの姿勢変更が適用されないので、オブジェクトが常にカメラに同じ方向を向けます。シーンでオブジェクトの正面を-Z方向に向けておくことで、オブジェクトの正面が常にカメラの方を向きます。

スクリプト

このセクションに記載されたコードは参考文献に基づいています。
参考文献:[Unity] Y軸ビルボードシェーダーの実装と解説 | gam0022.net (https://gam0022.net/blog/2019/07/23/unity-y-axis-billboard-shader/#%E3%82%B7%E3%82%A7%E3%83%BC%E3%83%80%E3%83%BC%E3%81%A7%E5%AE%9F%E8%A3%85%E3%81%99%E3%82%8B%E3%83%A1%E3%83%AA%E3%83%83%E3%83%88)
// Meshの原点をModelView変換
float3 viewPos = UnityObjectToViewPos(float3(0, 0, 0));

// スケールと回転(平行移動なし)だけModel変換して、View変換はスキップ
float3 scaleRotatePos = mul((float3x3)unity_ObjectToWorld, v.vertex);

// scaleRotatePosを右手系に変換して、viewPosに加算
// 本来はView変換で暗黙的にZが反転されているので、
// View変換をスキップする場合は明示的にZを反転する必要がある
viewPos += float3(scaleRotatePos.xy, -scaleRotatePos.z);

o.vertex = mul(UNITY_MATRIX_P, float4(viewPos, 1));

原点のみモデルビュー変換します。後で頂点を平行移動するときに使います。

            float3 viewPos = UnityObjectToViewPos(float3(0, 0, 0));

頂点をモデル変換します。平行移動の値が4*4行列の4つ目の列に含まれるので、3*3行列にキャストすることで、回転とスケールだけを適用します。

            float3 scaleRotatePos = mul((float3x3)unity_ObjectToWorld, v.vertex);

ビュー空間の原点と足して平行移動します。

viewPos += float3(scaleRotatePos.xy, -scaleRotatePos.z);

使ってみる

シーンにPlaneを置きました。回転は0です。

ビルボード用のシェーダーを適用すると、Planeがカメラといっしょに回転します。

Planeを回転して、表面が-Z方向を向くようにします。

これでPlaneが常にカメラの方を向くようになりました。

スケールのみを適用

モデル変換するときにスケールのみを適用してみました。回転が0のときに表面に-Zを向けるPlaneをBlenderで作りました。

モデル変換でスケールのみを適用します。モデル変換後の基底ベクトルの長さで各軸に沿ったスケールを計算しています。行列の対角成分に値を配置します。

                float scaleX = length(float3(unity_ObjectToWorld[0].x, unity_ObjectToWorld[1].x, unity_ObjectToWorld[2].x));
                float scaleY = length(float3(unity_ObjectToWorld[0].y, unity_ObjectToWorld[1].y, unity_ObjectToWorld[2].y));
                float scaleZ = length(float3(unity_ObjectToWorld[0].z, unity_ObjectToWorld[1].z, unity_ObjectToWorld[2].z));

                float3x3 ObjectScaleMatrix = float3x3(
                    scaleX, 0, 0,
                    0, scaleY, 0,
                    0, 0, scaleZ
                    );

                // 頂点位置を変換

これで、カメラに表面を向けました。

シーンのオブジェクトの向きに関係なく、カメラに表面を向けています。

参考:
https://gam0022.net/blog/2019/07/23/unity-y-axis-billboard-shader/#%E3%82%B7%E3%82%A7%E3%83%BC%E3%83%80%E3%83%BC%E3%81%A7%E5%AE%9F%E8%A3%85%E3%81%99%E3%82%8B%E3%83%A1%E3%83%AA%E3%83%83%E3%83%88
https://zenn.dev/mebiusbox/articles/8e765148576919
https://sleepygamersmemo.blogspot.com/2019/02/unity-get-object-scale-in-shader.html

コメントを残す

メールアドレスが公開されることはありません。