web-dev-qa-db-fra.com

Pourquoi transformer des normales avec la transposition de l'inverse de la matrice modelview?

Je travaille sur des shaders et j'ai besoin de transformer les normales. 

J'ai lu dans quelques tutoriels que vous transformiez les normales en multipliez-les par la transposée de l'inverse de la matrice modelview}. Mais je ne trouve pas d'explication sur la raison de cela, et quelle est la logique derrière cela?

37
user1796942

Jetez un oeil à ce tutoriel:

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

Vous pouvez imaginer que, lorsque la surface d’une sphère s’étire (la sphère est mise à l’échelle le long d’un axe ou similaire), les normales de cette surface se «courbent» l’une l’autre. Pour ce faire, il faut inverser l'échelle appliquée aux normales. Cela revient à transformer avec la matrice de transposition Inverse. Le lien ci-dessus montre comment en déduire la matrice transposée inverse.

Notez également que lorsque l'échelle est uniforme, vous pouvez simplement passer la matrice d'origine en tant que matrice normale. Imaginez que la même sphère soit mise à l'échelle de manière uniforme sur tous les axes, la surface ne s'étirera pas et ne se pliera pas, pas plus que les normales.

25
Invalid

Cela découle de la définition d'une normale.

Supposons que vous ayez la normale, N, et un vecteur, V, un vecteur tangent à la même position sur l'objet que la normale. Puis par définition N·V = 0.

Les vecteurs tangents vont dans la même direction que la surface d'un objet. Donc, si votre surface est plane, la tangente est la différence entre deux points identifiables sur l'objet. Donc, si V = Q - RQ et R sont des points de la surface, alors si vous transformez l'objet par B:

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

La même logique s'applique aux surfaces non planes en prenant en compte les limites.

Dans ce cas, supposons que vous souhaitiez transformer le modèle à l'aide de la matrice B. Donc B sera appliqué à la géométrie. Ensuite, pour savoir quoi faire avec les normales à résoudre pour la matrice, A, de sorte que:

(AN)·(BV) = 0

En transformant cela en une ligne par rapport à une colonne pour éliminer le produit scalaire explicite:

[tranpose(AN)](BV) = 0

Tirez la transposition à l'extérieur, éliminez les supports:

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

C’est donc "la transposée du produit normal" [produit avec] "la transposée de la matrice de transformation connue" [produit avec] "la transformation que nous résolvons pour" [produit avec] "le vecteur à la surface du modèle" = 0

Mais nous avons commencé par énoncer que transpose(N)*V = 0, puisque c’est la même chose que dire N·V = 0. Donc, pour satisfaire nos contraintes, nous avons besoin de la partie centrale de l'expression - transpose(A)*B - pour s'en aller.

Nous pouvons donc en conclure que:

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

Ma preuve préférée est ci-dessous où N est la normale et V est un vecteur tangent. Comme ils sont perpendiculaires, leur produit scalaire est zéro. M est une transformation inversible 3x3 (M-1 * M = I). N 'et V' sont les vecteurs transformés par M.

enter image description here

Pour obtenir une certaine intuition, considérons la transformation de cisaillement ci-dessous.

enter image description here

Notez que ceci not ne s'applique pas aux vecteurs tangents.

26
wcochran

Si la matrice du modèle est composée de translation, rotation et échelle, vous n'avez pas besoin de transposer inversement pour calculer une matrice normale. Il suffit de diviser la normale par une échelle au carré et de multiplier par la matrice du modèle et nous avons terminé. Vous pouvez l'étendre à toute matrice d'axes perpendiculaires. Il vous suffit de calculer une échelle au carré pour chaque axe de la matrice que vous utilisez à la place. 

J'ai écrit les détails dans mon blog: https://lxjk.github.io/2017/10/01/Stop-Using-Normal-Matrix.html

0
eric