web-dev-qa-db-ja.com

モデルビュー行列の逆行列の転置で法線を変換するのはなぜですか?

私はいくつかのシェーダーに取り組んでおり、法線を変換する必要があります。

いくつかのチュートリアルでは、法線を変換する方法はあなたですmodelview行列の逆行列の転置で乗算します。しかし、なぜそうなのかの説明を見つけることができず、その背後にある論理は何ですか?

42
user1796942

このチュートリアルをご覧ください。

https://paroj.github.io/gltut/Illumination/Tut09%20Normal%20Transformation.html

球体の表面が伸びると(球体が1つの軸などに沿って拡大縮小されると)、その表面の法線はすべて互いに「曲がる」ことが想像できます。これを実現するには、法線に適用されたスケールを反転する必要があることがわかります。これは、Inverse Transpose Matrixを使用した変換と同じです。上記のリンクは、これから逆転置行列を導き出す方法を示しています。

また、スケールが均一の場合、元のマトリックスを通常のマトリックスとして渡すことができることに注意してください。同じ球体がすべての軸に沿って均一にスケーリングされていると想像してください。サーフェスは伸びたり曲がったりせず、法線もありません。

28
Invalid

それは法線の定義から流れます。

法線NとベクトルVがオブジェクト上の法線と同じ位置に接線ベクトルであるとします。次に、定義によりN·V = 0

接線ベクトルは、オブジェクトの表面と同じ方向に走ります。したがって、表面が平面の場合、接線はオブジェクト上の2つの識別可能な点の差です。 QRが表面上の点であるV = Q - Rの場合、Bでオブジェクトを変換すると:

V' = BQ - BR
   = B(Q - R)
   = BV

同じロジックは、制限を考慮することにより、非平面サーフェスに適用されます。

この場合、マトリックスBによってモデルを変換することを想定しています。したがって、Bがジオメトリに適用されます。次に、行列に対して解く必要がある法線に対して何をするかを理解するために、Aを設定します。

(AN)·(BV) = 0

明示的なドット積を排除するために、それを行と列に変換します。

[tranpose(AN)](BV) = 0

転置を外側に引き出し、ブラケットを取り外します。

transpose(N)*transpose(A)*B*V = 0

つまり、「法線の転置」[との積] [既知の変換行列の転置] [との積] [我々が解決しようとしている変換] [との積] "モデルの表面上のベクトル" = 0

しかし、それはtranspose(N)*V = 0と言うことから始めました。それはN·V = 0と言うのと同じだからです。したがって、制約を満たすために、式の中央部分(transpose(A)*B)をなくす必要があります。

したがって、次のように結論付けることができます。

 transpose(A)*B = identity
 => transpose(A) = identity*inverse(B)
 => transpose(A) = inverse(B)
 => A = transpose(inverse(B))
41
Tommy

私のお気に入りの証明は以下です。ここで、Nは法線、Vは接線ベクトルです。それらは垂直なので、その内積はゼロです。 Mは任意の3x3可逆変換(M-1 * M = I)。 N 'およびV'は、Mによって変換されたベクトルです。

enter image description here

直観を得るために、以下のせん断変換を検討してください。

enter image description here

これは、notが接線ベクトルに適用されることに注意してください。

28
wcochran

モデル行列が平行移動、回転、スケールで構成されている場合、通常の行列を計算するために逆転置を行う必要はありません。法線を二乗スケールで除算し、モデル行列で乗算するだけで完了です。それを垂直軸を持つ任意のマトリックスに拡張し、代わりに使用しているマトリックスの各軸の2乗スケールを計算するだけです。

詳細をブログに書きました: https://lxjk.github.io/2017/10/01/Stop-Using-Normal-Matrix.html

1
eric