8 フレネル反射をつくる
このシェーダー入門は、おもに数式に焦点をあてる。なぜかって?筆者が数学なんもわからんの民だからだ。まちがっていたらおしえてほしい。
ウユニ塩湖のような反射する床をつくる。
視差ベクトル
- カメラ位置と現在のピクセル位置の差を計算する
- 正規化する
- 視線の方向が求まる
float3 viewDir = normalize(_WorldSpaceCameraPos - i.worldPos);
i.worldPos
は mul
関数で求めている。
v2f vert(appdata v)
{
v2f o;
o.worldPos = mul(unity_ObjectToWorld, v.vertex);
...
return o;
}
反射
法線ベクトルは appdata
から渡されたままだとローカル座標系なので、ワールド座標系に変換する。 UnityObjectToWorldNormal
関数で求めている。
struct appdata
{
float4 normal: NORMAL;
...
};
v2f vert(appdata v)
{
v2f o;
o.normal = UnityObjectToWorldNormal(v.normal);
...
return o;
}
視線ベクトルと法線ベクトルを使って、反射ベクトルを計算する。reflect
関数をつかう。
half3 reflDir = reflect(-viewDir, i.normal);
得られた反射ベクトルと反射キューブマップを使って、反射光の色をサンプリングする。
fixed4 reflectionColor = UNITY_SAMPLE_TEXCUBE_LOD(unity_SpecCube0, reflDir, 0);
フレネル反射
視線ベクトルと法線ベクトルの内積を計算する。内積は、同じ角度のとき 1 で、反対の角度の時 -1 だ。その絶対値を取る(0 以上の値にする)。
half vdotn = max(0, dot(viewDir, i.normal));
Schlick の近似式を使って、フレネル反射の強さを計算する( はベースの反射率、 は反射の強さ)。
_F0
はベースの反射率、_Fresnel
は反射の強さ。
half3 fresnel = (_F0 + (1.0h - _F0) * pow(1.0h - vdotn, 5)) * _Fresnel;
スペキュラー反射(鏡面反射)の変数をつくる。負にならないようにする。
half3 specular = fresnel;
specular = max(0, specular);
元の色に、反射色とスペキュラー反射の値をかけた色を加えて、最終的な色を返す。
return _MainColor + reflectionColor * half4(specular, 1);