sustitucion sistemas sistema problemas para metodo mejores matematicos matematicas lineales las incognitas ecuaciones con apps app aplicaciones aplicacion android opengl-es linear-algebra

sistemas - ¿El tutorial Android OpenGL de Google enseña algebra lineal incorrecta?



metodo de sustitucion de aplicaciones (5)

Como el tipo que escribió ese tutorial de OpenGL, puedo confirmar que el código de ejemplo es incorrecto. Específicamente, el orden de los factores en el código de sombreado debe invertirse:

" gl_Position = uMVPMatrix * vPosition;"

En cuanto a la aplicación de la matriz de rotación, el orden de los factores también debe invertirse para que la rotación sea el último factor. La regla general es que las matrices se aplican en orden de derecha a izquierda, y la rotación se aplica primero (es la parte "M" de "MVP"), por lo que debe ser el operando más a la derecha. Además, debe usar una matriz de raspado para este cálculo, según lo recomendado por Ian Ni-Lewis (consulte su respuesta más completa a continuación):

float[] scratch = new float[16]; // Combine the rotation matrix with the projection and camera view Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);

Gracias por llamar la atención sobre este problema. Obtendré la clase de entrenamiento y el código de muestra corregidos tan pronto como pueda.

Editar: Este problema ahora se corrigió en el código de muestra descargable y en la clase de capacitación de OpenGL ES, incluidos los comentarios sobre el orden correcto de los factores. Gracias por los comentarios, amigos!

Después de ayudar a otro usuario con una pregunta sobre el tutorial de Android Respondiendo a Touch Events , descargué el código fuente y quedé desconcertado por lo que vi. El tutorial parece no ser capaz de decidir si quiere usar vectores de fila o columnas, y todo se ve confundido para mí.

En la página de Android Matrix, afirman que su convención es column-vector / column-major, que es típica de OpenGL.

¿Estoy en lo cierto o hay algo que me falta? Aquí están los aspectos relevantes de esto:

Comience creando MVPMatrix multiplicando mProjMatrix * mVMatrix. Hasta aquí todo bien.

// Set the camera position (View matrix) Matrix.setLookAtM(mVMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f); // Calculate the projection and view transformation Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0)

A continuación, agregan una rotación al lado izquierdo de MVPMatrix. Esto parece un poco raro.

// Create a rotation for the triangle Matrix.setRotateM(mRotationMatrix, 0, mAngle, 0, 0, -1.0f); // Combine the rotation matrix with the projection and camera view Matrix.multiplyMM(mMVPMatrix, 0, mRotationMatrix, 0, mMVPMatrix, 0)

Subiendo en orden no transpuesto.

GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);

Finalmente, en su shader, ¿vector * multiplicación matricial?

// the matrix must be included as a modifier of gl_Position " gl_Position = vPosition * uMVPMatrix;"

Si sumamos todo esto, obtenemos:

gl_Position = vPosition * mRotation * mProjection * mView;

Lo cual no es correcto por ningún tramo de mi imaginación. ¿Hay alguna explicación de que no estoy viendo qué está pasando aquí?


El tutorial es incorrecto, pero muchos de los errores se cancelan mutuamente o no son obvios en este contexto muy limitado (cámara fija centrada en (0,0), rotación alrededor de Z solamente). La rotación es hacia atrás, pero por lo demás se ve bien. (Para ver por qué está mal, pruebe con una cámara menos trivial: configure el ojo y mire A y = 1, por ejemplo).

Una de las cosas que hizo esto muy difícil de depurar es que los métodos de Matrix no hacen ninguna detección de alias en sus entradas. El código del tutorial hace que parezca que puede llamar a Matrix.multiplyMM con la misma matriz utilizada como entrada y como resultado. Esto no es verdad Pero debido a que la implementación multiplica una columna a la vez, es mucho menos obvio que algo esté mal si se reutiliza el lado derecho (como en el código actual, donde mMVPMatrix es el rhs y el resultado) que si se reutiliza el lado izquierdo . Cada columna de la izquierda se lee antes de escribir la columna correspondiente en el resultado, por lo que la salida será correcta incluso si se sobrescribe el LHS. Pero si el lado derecho es el mismo que el resultado, entonces se sobrescribirá su primera columna antes de que termine de leerse.

Entonces el código del tutorial está en una especie de máximo local: parece que funciona, y si cambias una cosa, se rompe espectacularmente. Lo que lleva a uno a creer que lo que está mal parece, podría ser correcto. ;-)

De todos modos, aquí hay un código de reemplazo que obtiene lo que creo que es el resultado esperado.

Código Java:

@Override public void onDrawFrame(GL10 unused) { float[] scratch = new float[16]; // Draw background color GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); // Set the camera position (View matrix) Matrix.setLookAtM(mVMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f); // Calculate the projection and view transformation Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0); // Draw square mSquare.draw(mMVPMatrix); // Create a rotation for the triangle Matrix.setRotateM(mRotationMatrix, 0, mAngle, 0, 0, 1.0f); // Combine the rotation matrix with the projection and camera view Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0); // Draw triangle mTriangle.draw(scratch); }

Código de sombreado:

gl_Position = uMVPMatrix * vPosition;

Nota: estas correcciones hacen que la proyección sea correcta, pero también invierten la dirección de rotación. Esto se debe a que el código original aplicaba las transformaciones en el orden incorrecto. Piénselo de esta manera: en lugar de girar el objeto en el sentido de las agujas del reloj, estaba girando la cámara en sentido antihorario. Cuando arregla el orden de las operaciones para que la rotación se aplique al objeto en lugar de a la cámara, el objeto comienza a girar en sentido antihorario. No es la matriz lo que está mal; es el ángulo que se usó para crear la matriz.

Entonces, para obtener el resultado ''correcto'', también necesita voltear el signo de mAngle.


Estoy trabajando en el mismo problema y eso es lo que encontré:

Creo que la muestra de Joe es CORRECTA,
incluyendo el orden de los factores en el código de sombreado:

gl_Position = vPosition * uMVPMatrix;

Para verificarlo, simplemente intente rotar el triángulo con el orden de los factores invertidos, estirará el triángulo al punto de fuga a 90 grados.

El verdadero problema parece estar en la función setLookAtM .
En los parámetros de muestra de Joe están:

Matrix.setLookAtM(mVMatrix, 0, 0f, 0f,-3f, 0f, 0f, 0f, 0f, 1f, 0f );

lo cual es perfectamente lógico también.
Sin embargo, la matriz de vista resultante me parece extraña:

-1 0 0 0 0 1 0 0 0 0 -1 0 0 0 -3 1

Como podemos ver, esta matriz invertirá la coordenada X, ya que el primer miembro es -1,
que conducirá a la izquierda / derecha en la pantalla.
También invertirá el orden Z, pero centrémonos aquí en la coordenada X.

Creo que la función setLookAtM también está funcionando correctamente.
Sin embargo, dado que la clase Matrix NO es parte de OpenGL, puede usar algún otro sistema de coordenadas,
por ejemplo, coordenadas de pantalla regulares con el eje Y apuntando hacia abajo.
Esto es solo una suposición, realmente no lo verifiqué.

Soluciones posibles:
Podemos construir la matriz de vista deseable manualmente
el código es:

Matrix.setIdentityM(mVMatrix,0); mVMatrix[14] = -3f;

O
podemos intentar engañar a la función setLookAtM dándole coordenadas de cámara invertidas: 0, 0, +3 (en lugar de -3).

Matrix.setLookAtM(mVMatrix, 0, 0f, 0f, 3f, 0f, 0f, 0f, 0f, 1f, 0f );

La matriz de vista resultante será:

1 0 0 0 0 1 0 0 0 0 1 0 0 0 -3 1

Eso es exactamente lo que necesitamos.
Ahora la cámara se comporta como se esperaba
y la muestra funciona correctamente


No funcionó ninguna otra sugerencia para mí al usar el código de ejemplo actualizado de Android actual, excepto por lo siguiente al intentar mover el triángulo.

El siguiente enlace contiene la respuesta. Tomó más de un día para localizarlo. Publicando aquí para ayudar a otros ya que he visto esta publicación muchas veces. Transformaciones de matriz de OpenGL ES Android


Resolví este problema de la siguiente manera:

@Override public void onDrawFrame(GL10 unused) { GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -1f, 0f, 0f, 0f, 0f, 1.0f, 0.0f); Matrix.setRotateM(mModelMatrix, 0, mAngle, 0, 0, 1.0f); Matrix.translateM(mModelMatrix, 0, 0.4f, 0.0f, 0); mSquare.draw(mProjMatrix,mViewMatrix,mModelMatrix); } @Override public void onSurfaceChanged(GL10 unused, int width, int height) { ... Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 1, 99); } class Square { private final String vertexShaderCode = "uniform mat4 uPMatrix; /n" + "uniform mat4 uVMatrix; /n" + "uniform mat4 uMMatrix; /n" + "attribute vec4 vPosition; /n" + "void main() { /n" + " gl_Position = uPMatrix * uVMatrix * uMMatrix * vPosition; /n" + "} /n"; ... public void draw(float[] mpMatrix,float[] mvMatrix,float[]mmMatrix) { ... mPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uPMatrix"); mVMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uVMatrix"); mMMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMMatrix"); GLES20.glUniformMatrix4fv(mPMatrixHandle, 1, false, mpMatrix, 0); GLES20.glUniformMatrix4fv(mVMatrixHandle, 1, false, mvMatrix, 0); GLES20.glUniformMatrix4fv(mMMatrixHandle, 1, false, mmMatrix, 0); ... } }