web-dev-qa-db-fra.com

Confusion entre l'ordre matriciel C ++ et OpenGL (ligne-majeur vs colonne-majeur)

Je suis complètement dérouté par les définitions de matrice. J'ai une classe de matrice, qui détient un float[16] dont je suppose qu’il s’agit d’une rangée principale, à partir des observations suivantes:

float matrixA[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
float matrixB[4][4] = { { 0, 1, 2, 3 }, { 4, 5, 6, 7 }, { 8, 9, 10, 11 }, { 12, 13, 14, 15 } };

matrixA et matrixB ont tous deux la même disposition linéaire en mémoire (c’est-à-dire que tous les nombres sont dans l’ordre). Selon http://en.wikipedia.org/wiki/Row-major_order , cela indique une disposition en lignes majeures.

matrixA[0] == matrixB[0][0];
matrixA[3] == matrixB[0][3];
matrixA[4] == matrixB[1][0];
matrixA[7] == matrixB[1][3];

Donc, matrixB[0] = rangée 0, matrixB[1] = rangée 1, etc. Là encore, cela indique une disposition principale en rangées.

Mon problème/confusion survient lorsque je crée une matrice de traduction qui ressemble à:

1, 0, 0, transX
0, 1, 0, transY
0, 0, 1, transZ
0, 0, 0, 1

Qui est mis en mémoire comme, { 1, 0, 0, transX, 0, 1, 0, transY, 0, 0, 1, transZ, 0, 0, 0, 1 }.

Ensuite, lorsque j'appelle glUniformMatrix4fv , je dois définir le drapeau de transposition sur GL_FALSE, indiquant qu'il s'agit d'une colonne-majeure, sinon les transformations telles que translate/scale, etc. ne sont pas appliquées correctement:

Si transpose est GL_FALSE, chaque matrice est supposée être fournie dans l'ordre des colonnes. Si transpose est GL_TRUE, chaque matrice est supposée être fournie dans l'ordre principal de la ligne.

Pourquoi ma matrice, qui semble être en lignes majeures, doit-elle être transmise à OpenGL en tant que colonne majeure?

68
Mark Ingram

La notation matricielle utilisée dans la documentation opengl ne décrit pas la disposition en mémoire des matrices OpenGL

Si vous pensez que ce sera plus facile si vous supprimez/oubliez toute la fonction "ligne/colonne-majeur" En effet, en plus de la ligne/colonne majeure, le programmeur peut également décider comment il souhaite disposer la matrice dans la mémoire (si les éléments adjacents forment des lignes ou des colonnes), en plus de la notation, ce qui ajoute à la confusion.

Les matrices OpenGL ont même structure mémoire que les matrices directx .

x.x x.y x.z 0
y.x y.y y.z 0
z.x z.y z.z 0
p.x p.y p.z 1

ou

{ x.x x.y x.z 0 y.x y.y y.z 0 z.x z.y z.z 0 p.x p.y p.z 1 }
  • x, y, z sont des vecteurs à 3 composantes décrivant le système de coordonnées de la matrice (système de coordonnées local compris dans le système de coordonnées global).

  • p est un vecteur à 3 composantes décrivant le système de coordonnées Origin of matrix.

Ce qui signifie que la matrice de traduction devrait être mise en mémoire de la manière suivante:

{ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, transX, transY, transZ, 1 }.

Laissez cela, et le reste devrait être facile.

--- citation du vieil opengl faq--


9.005 Les matrices OpenGL sont-elles des colonnes ou des lignes majeures?

Pour la programmation, les matrices OpenGL sont des tableaux à 16 valeurs avec des vecteurs de base disposés de manière contiguë en mémoire. Les composants de traduction occupent les 13ème, 14ème et 15ème éléments de la matrice à 16 éléments, où les indices sont numérotés de 1 à 16 comme décrit dans la section 2.11.2 de la spécification OpenGL 2.1.

Colonne-majeur contre ligne-majeur est purement une convention de notation. Notez que la post-multiplication avec les matrices colonnes-majeures produit le même résultat que la prémultiplication avec les matrices lignes-majeures. La spécification OpenGL et le manuel de référence OpenGL utilisent tous deux la notation colonne-majeure. Vous pouvez utiliser n'importe quelle notation, à condition que cela soit clairement indiqué.

Malheureusement, l'utilisation du format colonne-majeur dans les spécifications et le livre bleu a entraîné une confusion sans fin dans la communauté de programmation OpenGL. La notation en colonnes majeure suggère que les matrices ne sont pas mises en mémoire comme le programmeur l’attend.


64
SigTerm

Pour résumer les réponses par SigTerm et dsharlet: La manière habituelle de transformer un vecteur en GLSL consiste à multiplier le vecteur à gauche par la matrice de transformation:

mat4 T; vec4 v; vec4 v_transformed; 
v_transformed = T*v;

Pour que cela fonctionne, OpenGL s'attend à ce que la configuration de la mémoire de T soit, comme décrit par SigTerm,

{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, transX, transY, transZ, 1 }

qui s'appelle également 'colonne majeure'. Cependant, dans votre code de shader (comme indiqué dans vos commentaires), vous avez multiplié à droite le vecteur par la matrice de transformation:

v_transformed = v*T;

qui ne donne que le résultat correct si T est transposé, c’est-à-dire qu’il a la disposition

{ 1, 0, 0, transX, 0, 1, 0, transY, 0, 0, 1, transZ, 0, 0, 0, 1 }

(c'est-à-dire "rangée majeure"). Comme vous avez déjà fourni la bonne mise en page à votre shader, à savoir la ligne principale, il n’était pas nécessaire de définir le drapeau transpose de glUniform4v.

52
Roberto

Vous traitez de deux problèmes distincts.

Premièrement, vos exemples traitent de la disposition de la mémoire. Votre tableau [4] [4] est une ligne majeure parce que vous avez utilisé la convention établie par les tableaux multidimensionnels C pour correspondre à votre tableau linéaire.

Le deuxième problème concerne la manière dont vous interprétez les matrices dans votre programme. glUniformMatrix4fv est utilisé pour définir un paramètre de shader. Que votre transformation soit calculée pour un vecteur de rangée ou un vecteur de colonne est une question de comment vous utilisez la matrice dans votre code de shader. Puisque vous dites que vous devez utiliser des vecteurs de colonne, je suppose que votre code de shader utilise la matrice [~ # ~] un [~ # ~] et un vecteur de colonne x à calculer x ' = Un x .

Je dirais que la documentation de glUniformMatrix prête à confusion. La description du paramètre transpose est une façon très détournée de dire que la matrice est transposée ou non. OpenGL ne fait que transporter ces données dans votre shader, que vous souhaitiez les transposer ou non est une question de convention que vous devez établir pour votre programme.

Ce lien a encore de bonnes discussions: http://steve.hollasch.net/cgindex/math/matrix/column-vec.html

14
dsharlet