法線マップをオブジェクト空間へ変換しシェーディング

法線マップをオブジェクト空間へ変換しシェーディング

 視差マッピングシェーダを作成する際に、反射光等の計算を行いました。このとき、法線マップは接空間のベクトルを示しているので、vertex shaderでライトベクトル等を接空間へ変換した後に、fragment Shaderで法線マップと変換したライトベクトル等で反射を計算しました。ここでふと、全てのベクトルをオブジェクト空間に変換して計算しても当然同じ結果が得られるはず、と考え新たにシェーダを作成しました。

接空間で計算

shader

 vertex shader内でライトベクトルと視線ベクトルを接空間へ変換し、それらをもとにハーフベクトルを求めています。この計算結果をfragment shader内で使用し、陰影や反射光を計算しています。

実行結果

 ランバート反射とBlinng-Phongの反射が合わさった結果となっています。

オブジェクト空間で計算

shader

 vertex shader内で法線マップをオブジェクト空間へ変換するために必要な接ベクトル及び従法線ベクトルを取得しています。また、ライトベクトルと視線ベクトルをオブジェクト空間へ変換しています。そして、fragment shader内でこれらのベクトルから法線マップより得られる法線ベクトルを接空間からオブジェクト空間へ変換し、計算を行っています。

実行結果

 接空間で計算した場合と逆の結果となってしまいました。

原因と解決方法

 右手座標系と左手座標系の違いによるものでした。この座標系の違いにより従法線ベクトルの向きが反対方向となるようです。この座標系の違いを処理するにはどうしたらよいかというと、接ベクトルの四番目の要素(tangent.w)に右手座標系か左手座標系か(1か-1)が入っています。これを、従法線ベクトルに乗算すれば正しいベクトルが得られるようです。つまり、上記シェーダの

と変更すれば良いようです。

実行結果

 接空間で計算した場合と同様の結果が得られました。

参考サイト

土屋つかさのテクノロジーは今か無しか:UnityのシェーダーでBINORMAL入力セマンティクスが機能しない話と回避する方法の話