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

こんかいはメッシュの本来の法線を取得します。
〇メッシュ本来の法線とは
3Dモデルはシェーディングという補正を使用できます。
例えば次の画像の2つの球は全く同じ球ですが、シェーディングをかけているかそうではないかという違いがあります。

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

こんかいは保管されていない本来のメッシュの法線を取得します。
〇処理
シェーディングを考慮しないメッシュ本来の法線を取得するには次の処理を使用します。
float3 ddxPosition = ddx(i.worldPos);
float3 ddyPosition = ddy(i.worldPos);
float3 albedo = normalize(cross(ddxPosition, ddyPosition));
ddx,ddyはhlslで提供される関数です。座標の微分に使用されます。
こんかいはオブジェクトのワールド座標を微分し、内積をとることで向きを取得しています。
これを実行するとメッシュの本来の法線を可視化できます。

〇コード
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
}
}
}