夜風のMixedReality

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

ゼロから始めるUnityShader開発  メッシュ本来の法線を取得する

本日はShader枠です。

先日はNormalVectorを使用して法線を描画するシェーダーを記述しました。

redhologerbera.hatenablog.com

こんかいはメッシュの本来の法線を取得します。

〇メッシュ本来の法線とは

3Dモデルはシェーディングという補正を使用できます。

例えば次の画像の2つの球は全く同じ球ですが、シェーディングをかけているかそうではないかという違いがあります。

昨日行った法線はシェーディング済みの状態での補完された法線の見た目でした。

こんかいは保管されていない本来のメッシュの法線を取得します。

〇処理

シェーディングを考慮しないメッシュ本来の法線を取得するには次の処理を使用します。

                float3 ddxPosition = ddx(i.worldPos);
                float3 ddyPosition = ddy(i.worldPos);
                 float3 albedo = normalize(cross(ddxPosition, ddyPosition));

ddx,ddyはhlslで提供される関数です。座標の微分に使用されます。

learn.microsoft.com

こんかいはオブジェクトのワールド座標を微分し、内積をとることで向きを取得しています。

これを実行するとメッシュの本来の法線を可視化できます。

〇コード

Shader "Unlit/TrueNormal"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
   #pragma vertex vert
        #pragma fragment frag
        #include "UnityCG.cginc"

        struct appdata
        {
            float4 vertex : POSITION;
        };

        struct v2f
        {
            float4 vertex : SV_POSITION;
            float3 worldPos: TEXCOORD1;
        };

        v2f vert(appdata v)
        {
            v2f o;
            o.vertex = UnityObjectToClipPos(v.vertex);
            
               o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;

            return o;
        }

        fixed4 frag(v2f i) : SV_Target
        {
                float3 ddxPosition = ddx(i.worldPos);
                float3 ddyPosition = ddy(i.worldPos);
                 float3 albedo = normalize(cross(ddxPosition, ddyPosition));

            // Output color
            return fixed4(albedo, 1.0);
        }
            ENDCG
        }
    }
}