Unityのシェーダーで法線マップを実装したいんです

こんにちは。ヤマヤタケシです。

Unityのシェーダーで法線マップを実装したいんです。

ライト座標をオブジェクト空間に変換するヘルパー関数があるのですが、なんでオブジェクト空間なのかね?
とか思った次第です。

そんな感じでシェーダーを書いているのですが、頭の中がゴチャついてきたので、いったん吐き出します。アウトプット学習法です。

ゴチャつく原因は、空間の種類が多いのと、その変換が空間の組み合わせになるためです。

空間が色々あります。
そもそもCGで言うところの空間というのは、例えば点を(x,y,z)で表現した場合のx軸とy軸とz軸です。
x軸とy軸とz軸が直行していたり、斜めになっていたりします。

今回、法線マップの実装に必要な空間はこいつらです。

1. 接空間(Tangent space):法線マップのベクトルがこの空間にいる。
2. モデル空間(Model space):モデルの頂点、法線がこの空間にいる。
3. ワールド空間(World space):1番外側の空間。基準になる空間。
4. ビュー空間(View space):カメラが基準の空間。カメラの位置が原点で、カメラの向いている方向がZ軸,右がX軸、上がY軸。
5. スクリーン空間(Screen space):最終結果の空間。画面の大きさ、アスペクト比、深度のNear, Farとかで決まる。

いろんな空間があるのは、それぞれ役割があるからです。
空間から、空間へ変換することで、順番に計算していきます。

例えば、法線マップをモデルに張ってレンダリングするため素材と手順を書きます。

素材
1. モデルデータ。(頂点、法線、接線)
モデルデータのベクトルはモデル空間で表現されています。

2. 法線マップ。
法線マップはモデルの詳細な法線を、モデル表面を展開した接空間に書き出したものです。

手順

1. 法線マップの法線をモデルの法線に加算したいので、接空間からモデル空間に変換します。
2. 接空間からモデル空間に変換するためのマトリクスを作ります。(モデルの法線、接線、その2つを外積したベクトル、で作るマトリクス)
3. これで、モデル空間の法線ができました。

ライトの計算の基本のディフューズの明るさは、ライトの方向ベクトルと面の法線の内積で決めます。
ただライトはワールド空間であり、法線はモデル空間なので、どちらかを変換してあわせます。
A. モデルの法線をワールド空間に変換する model -> world
B. ライトをオブジェクト空間に変換するかです。 world -> model

4. ライトの数が法線よりも圧倒的に少ないので、”B. ライトをオブジェクト空間に変換”します。
5. ライトの方向ベクトルと面の法線の内積を計算
6. ライトの色を5.の結果倍します。

これでいけるはず!

法線マップのベクトルを変換するために、モデルには法線とそれと直行する接線が必要です。
例えば、接線はモデルの隣の頂点にしたいのですが、シェーダーの中では隣の頂点は見えません。
外で用意する必要があります。
3Dツールが作ってくれたりしますが、今回は計算でモデルを生成しているので自作します。

以上、数式を日本語化した感じです。
きっとうまくいくはず。
そんじゃまた。