¿Cómo es la “Columna Mayor” de GLKMatrix de GLKit?

5 minutos de lectura

Avatar de usuario de Matt Wilding
mate salvaje

Premisa A

Cuando se habla de matrices de “Columna Mayor” en la memoria lineal, las columnas se especifican una tras otra, de modo que las primeras 4 entradas en la memoria corresponden a la primera columna de la matriz. Las matrices de “fila principal”, por otro lado, se entiende que especifican filas una tras otra, de modo que las primeras 4 entradas en la memoria especifican la primera fila de la matriz.


A GLKMatrix4 Se ve como esto:

union _GLKMatrix4
{
    struct
    {
        float m00, m01, m02, m03;
        float m10, m11, m12, m13;
        float m20, m21, m22, m23;
        float m30, m31, m32, m33;
    };
    float m[16];
}
typedef union _GLKMatrix4 GLKMatrix4;

los documentación sobre el m miembro dice:

Una matriz unidimensional de los elementos de la matriz en orden de columna principal.

Premisa B

Una “fila” en un GLKMatrix4 es un conjunto de 4 flotantes declarados horizontalmente ([m00, m01, m02, m03] sería la primera “fila”). Por lo tanto, esas entradas se pueden interpretar como mRowCol (m12 sería la entrada en la fila 1, columna 2).


Si observamos cómo se distribuyen esos miembros de la estructura GLKMatrix en función del orden de las declaraciones, vemos:

[m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, ...]

Donde las primeras 4 entradas representan claramente la primera fila de la matriz, no la primera columna.

Conclusión

m no es en realidad la Columna Mayor, y los documentos están equivocados.


Ahora, debo señalar que en realidad no creo en la conclusión, pero las dos premisas parecen bastante razonables. Realmente, desconfío más de la premisa B, pero parece extraño definir una “fila” como vertical y una “columna” como horizontal. ¿Alguien puede explicar esto?

  • float m00, m01, m02, m03; es la declaración del primero columnaa pesar de que “parece” una fila. Aquí es donde Premisa B se cae.

    – bobobobo

    17 de septiembre de 2012 a las 11:02

Avatar de usuario de Tark
Tarta

La declaración es un poco confusa, pero la matriz está en orden de columna principal. Las cuatro filas en la estructura representan las columnas en la matriz, siendo m0* la columna 0 y m3* la columna 3. Esto es fácil de verificar, simplemente cree una matriz de traducción y verifique los valores m30, m31 y m32 para los componentes de traducción.

Supongo que su confusión proviene del hecho de que la estructura dispone los flotadores en filas, cuando en realidad representan columnas.

  • Eso, y el hecho de que siempre he indexado en matrices pensando en m(fila)(columna), no en m(columna)(fila). Gracias.

    – Matt Wilding

    13 de marzo de 2012 a las 17:32

  • @MattWilding Eso es exactamente lo que me hizo tropezar. Pero m(row)(col) es como se accede a un fila mayor matriz, es decir, fila primero, luego columna. Lo que confunde las cosas es que, aunque MATLAB es “columna principal”, todavía tiene una convención de indexación de fila principal de m(row,col).

    – bobobobo

    17 de septiembre de 2012 a las 10:42

  • Tendemos a pensar que una variable/miembro llamado “mXY” es el elemento para la fila X y la columna Y de la matriz, pero dado que la matriz se declara como columna principal, el primer “subíndice” (en este caso, X) del nombre de cada miembro es la columna.

    – Nicolás Miari

    1 de octubre de 2013 a las 5:59

avatar de usuario de bobobobo
bobobobo

Esto viene de la especificación OpenGL —

columna mayor

El punto de confusión es exactamente este: como otros han señalado, indexamos una matriz de columna principal con el primer índice indicando la columna, no la fila:

  • m00 se refiere a columna=0, fila=0,
  • m01 se refiere a columna=0, fila=1,
  • m02 se refiere a columna=0, fila=2,

Probablemente MATLAB ha hecho mucho para contribuir indirectamente a esta confusión, mientras que MATLAB usa la columna principal para su representación de datos internostodavía usa un fila mayor convención de indexación de x(row,col). No estoy seguro de por qué hicieron esto.

También tenga en cuenta que OpenGL por defecto usa Vectores de columnas — es decir, se espera que publique multiplicar la matriz por el vector que transforma, como (MATRIX*VECTOR) en un sombreador. Contrastar con (VECTOR*MATRIX) que es lo que haría para una matriz de filas principales.

Puede ser útil mirar mi artículo sobre matrices principales de fila frente a columnas principales en C.

La columna principal es contraria a la intuición al diseñar matrices en el código

Cuanto más miro esto, más pienso que es un error trabajar en la columna mayor en código C, debido a la necesidad de transponer mentalmente lo que estás haciendo. Cuando diseña una matriz en código, está restringido por la naturaleza de izquierda a derecha de nuestro idioma para escribir una matriz fila por fila:

float a[4] = { 1, 2,
               3, 4 };

Entonces, muy naturalmente, parece que está especificando por fila, la matriz

1 2
3 4

Pero si está utilizando una especificación principal de columna, entonces en realidad ha especificado la matriz

1 3
2 4

Lo cual es realmente contrario a la intuición. si tuviéramos un vertical (o, lenguaje de “columna mayor”) luego especificando matrices principales de columna en el código haría ser más fácil.

¿Es todo esto otro argumento indirecto para Direct3D? No sé, me dices.

Realmente, ¿por qué OpenGL usa matrices principales de columna entonces?

Cavar más profundoparece que la razón por la que esto se hizo fue para poder “post multiplicar” matrices por vectores como (MATRIX*VECTOR) — es decir, poder usar columna (principal) vectores me gusta:

Multiplicación de matriz principal de columna

┌ 2 8 1 1 ┐ ┌ 2 ┐
│ 2 1 7 2 │ │ 2 │
│ 2 6 5 1 │ │ 2 │
└ 1 9 0 0 ┘ └ 1 ┘

Contraste esto con tener que usar vectores de fila:

Multiplicación de matriz principal por filas

[ 2 2 2 1 ]  ┌ 2 8 1 1 ┐ 
             │ 2 1 7 2 │
             │ 2 6 5 1 │
             └ 1 9 0 0 ┘

El trato es, si las matrices se especifican como fila principal, entonces “debería” usar vectores de fila y premultiplicar las matrices por el vector que están transformando.

La razón por la que “debería” usar vectores de fila cuando usa matrices de fila principal es representación de datos consistente: después de todo, un vector de fila es solo una matriz de 1 fila y 4 columnas.

avatar de usuario de sch
sch

el problema en Premisa B es que supones que Una “fila” en un GLKMatrix4 es un conjunto de 4 flotantes declarados horizontalmente ([m00, m01, m02, m03] sería la primera “fila”).

Podemos comprobar que simplemente comprobando el valor de column en el siguiente código:

GLKMatrix3 matrix = {1, 2, 3, 4, 5, 6, 7, 8, 9};
GLKVector3 column = GLKMatrix3GetColumn(m, 0);

Nota: yo usé GLKMatrix3 por simplicidad, pero lo mismo se aplica a GLKMatrix4.

  • Sí, eso confirma mis sospechas. Gracias.

    – Matt Wilding

    13 de marzo de 2012 a las 17:31

¿Ha sido útil esta solución?