夜風のMixedReality

xRと出会って変わった人生と出会った技術を書き残すためのGeekなHoloRangerの居場所

ゼロから始めるUnityShader開発 第五章 オブジェクトを回転させるシェーダー

本日はShader学習枠です。

今回は頂点シェーダーを利用してオブジェクトを回転させます。

頂点シェーダーステージでは3Dデータから頂点をスクリーン座標に直した計算が行われています。

つまり座標変換に際してバイアスをかけることでメッシュの形状を変えることができます。

例えば以前は拡大縮小のアニメーション表現を行いました。

redhologerbera.hatenablog.com

今回はこれを使用して次のような回転表現を行います。

〇頂点シェーダーでの回転行列

頂点シェーダーでは一般的にUnityObjectToClipPos(v.vertex)でクリップ座標(カメラの座標)に変換しています。

今回はこの変換の前に回転行列を作成します。

float3×3というのは3次元の行列を意味します。

回転行列は次のように定義されます。

 \displaystyle
R_z(\theta) = 
\begin{pmatrix}
\cos(\theta) & -\sin(\theta) & 0 \\
\sin(\theta) & \cos(\theta) & 0 \\
0 & 0 & 1
\end{pmatrix}  \

回転を行う際に座標系の変換が必要になりますが回転行列はベクトルの成分を新しい座標系に変換するために使用されます。

これを頂点シェーダー内のコードで示すと次のようになります。

                float angle = _Time.y * 0.3;//0.3は回転速度 
                float3x3 rotationMatrix = float3x3(
                    cos(angle), 0, sin(angle),
                    0, 1, 0,
                    -sin(angle), 0, cos(angle)
                );

_Time.yは時間でシェーダー内で使用することで回転し続けるアニメーションを作成できます。

これをΘとして使用して回転角に使用しています。

これを使用した頂点シェーダーは次のようになります。

  v2f vert(appdata v)
            {
                v2f o;
                // 回転行列を作成
                float angle = _Time.y * 0.3;//0.3は回転速度 
                float3x3 rotationMatrix = float3x3(
                    cos(angle), 0, sin(angle),
                    0, 1, 0,
                    -sin(angle), 0, cos(angle)
                );

                // 頂点を回転
                o.pos = UnityObjectToClipPos(mul(rotationMatrix, v.vertex));

                return o;
            }

これによって冒頭で紹介したようなY軸に回転し続ける表現ができます。

〇シェーダー全文

Shader "Custom/RotatingObjectShader"
{
    Properties
    {

    }
    
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };

            struct v2f
            {
                float4 pos : SV_POSITION;
            };

            float4 _Rotation; // 回転角度を指定するためのプロパティ

            v2f vert(appdata v)
            {
                v2f o;
                // 回転行列を作成
                float angle = _Time.y * 0.3;//0.3は回転速度 
                float3x3 rotationMatrix = float3x3(
                    cos(angle), 0, sin(angle),
                    0, 1, 0,
                    -sin(angle), 0, cos(angle)
                );

                // 頂点を回転
                o.pos = UnityObjectToClipPos(mul(rotationMatrix, v.vertex));

                return o;
            }

            half4 frag(v2f i) : SV_Target
            {
                return half4(1, 1, 1, 1); 
            }
            ENDCG
        }
    }
}