Confusión entre C++ y el orden de la matriz OpenGL (fila-mayor vs columna-mayor)


Me estoy confundiendo por completo sobre las definiciones de la matriz. Tengo una clase de matriz, que contiene un float[16] que asumí es mayor de fila, basado en las siguientes observaciones:

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 y matrixB ambos tienen la misma disposición lineal en memoria (es decir, todos los números están en orden). Según http://en.wikipedia.org/wiki/Row-major_order esto indica un diseño de fila mayor.

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

Por lo tanto, matrixB[0] = fila 0, matrixB[1] = fila 1, etc. Una vez más, esto indica fila-mayor diseño.

Mi problema / confusión viene cuando creo una matriz de traducción que se parece a:

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

Que se presenta en la memoria como, { 1, 0, 0, transX, 0, 1, 0, transY, 0, 0, 1, transZ, 0, 0, 0, 1 }.

Luego cuando llamo a glUniformMatrix4fv, necesito establecer la bandera de transposición a GL_FALSE, indicando que es columna mayor, de lo contrario las transformaciones como translate / scale, etc. no se aplican correctamente:

Si transpose es GL_FALSE, se asume que cada matriz se suministra en orden mayor de la columna. Si transponer es GL_TRUE, cada matriz se asume que se suministrará en orden mayor fila.

¿Por qué mi matriz, que parece ser mayor de fila, necesita ser pasada a OpenGL como mayor de columna?

Author: Mark Ingram, 2013-07-18

3 answers

La notación de matriz utilizada en la documentación de opengl no describe el diseño en memoria para matrices OpenGL

Si crees que será más fácil si dejas/olvidas todo lo de "fila/columna-mayor". Esto se debe a que, además de la fila / columna mayor, el programador también puede decidir cómo desea colocar la matriz en la memoria (si los elementos adyacentes forman filas o columnas), además de la notación, lo que aumenta la confusión.

Las matrices OpenGL tienen lo mismo diseño de memoria como 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

O

{ 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 son vectores de 3 componentes que describen el sistema de coordenadas de la matriz (sistema de coordenadas local en relación con el sistema de coordenadas global).

  • P es un vector de 3 componentes que describe el origen del sistema de coordenadas de la matriz.

Lo que significa que la matriz de traducción debe ser presentada en la memoria de esta manera:

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

Déjalo así, y el resto debe ser fácil.

- - - cita del antiguo faq de opengl {


9.005 ¿Las matrices OpenGL son mayores en columna o mayores en fila?

Para fines de programación, las matrices OpenGL son matrices de 16 valores con vectores base dispuestos contiguamente en memoria. Los componentes de traducción ocupan los elementos 13, 14 y 15 de la matriz de 16 elementos, donde los índices están numerados del 1 al 16 como se describe en la sección 2.11.2 de la especificación OpenGL 2.1.

Columna-mayor versus row-major es puramente una convención notacional. Tenga en cuenta que la multiplicación posterior con matrices de columna mayor produce el mismo resultado que la multiplicación previa con matrices de fila mayor. La Especificación de OpenGL y el Manual de Referencia de OpenGL usan notación de columna mayor. Puedes usar cualquier notación, siempre y cuando esté claramente indicada.

Lamentablemente, el uso del formato de columna mayor en las especificaciones y el libro azul ha dado lugar a una confusión sin fin en la comunidad de programación de OpenGL. La notación de columna mayor sugiere que las matrices no se presentan en la memoria como un programador esperaría.


 54
Author: SigTerm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-03 06:57:01

Para resumir las respuestas de SigTerm y dsharlet: La forma habitual de transformar un vector en GLSL es multiplicar a la izquierda el vector por la matriz de transformación:

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

Para que eso funcione, OpenGL espera que el diseño de memoria de T sea, como se describe en SigTerm,

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

Que también se llama 'columna mayor'. En su código de sombreado (como se indica en sus comentarios), sin embargo, multiplicó a la derecha el vector por la matriz de transformación:

v_transformed = v*T;

Que solo rinde el resultado correcto si T se transpone, es decir, tiene la disposición

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

(es decir, 'fila mayor'). Dado que ya ha proporcionado el diseño correcto a su sombreador, es decir, la fila mayor, no fue necesario establecer la bandera transpose de glUniform4v.

 39
Author: Roberto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-03 11:12:54

Se trata de dos cuestiones distintas.

Primero, sus ejemplos están tratando con el diseño de memoria. Su matriz[4] [4] es mayor de fila porque ha utilizado la convención establecida por C matrices multidimensionales para que coincida con su matriz lineal.

La segunda cuestión es una cuestión de convención sobre cómo interpretar las matrices en su programa. glUniformMatrix4fv se utiliza para establecer un parámetro de sombreado. Si su transformación se calcula para un vector de fila o una columna la transformación de vector es una cuestión de cómo se usa la matriz en el código de sombreado. Debido a que dices que necesitas usar vectores de columna, asumo que tu código de sombreado está usando la matriz A y un vector de columna x para calcular x' = A x .

Yo diría que la documentación de glUniformMatrix es confuso. La descripción del parámetro de transposición es una forma realmente indirecta de decir simplemente que la matriz está transpuesta o no lo está. solo el transporte de esos datos a su sombreador, si desea transponerlo o no es una cuestión de convención que debe establecer para su programa.

Este enlace tiene una buena discusión adicional: http://steve.hollasch.net/cgindex/math/matrix/column-vec.html

 14
Author: dsharlet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-18 08:45:20