¿Cómo envío múltiples matrices a un sombreador de vértices?

9

Estoy practicando animaciones usando huesos / desollado. Estoy tratando de enviar al sombreador una matriz por vértice. Puedo pensar en estos dos enfoques.

Método 1

Tengo un mango uniforme para cada matriz ósea como este

u_Bone0 = GLES20.glGetUniformLocation(mProgram, "u_Bone[0]");
u_Bone1 = GLES20.glGetUniformLocation(mProgram, "u_Bone[1]");

y en el onDrawenvío cada uno de ellos al sombreador: GLES20.glUniformMatrix4fv(u_Bone0, 1, false, matrix0, 0);

Obviamente, este no es un buen enfoque si tengo una gran cantidad de matrices. Mi segunda idea, que aún no he probado, ya que hay mucho código para refactorizar

Método 2

Es usar el glUniformMatrix4fvpara enviarlos todos a la vez como (supongo que tengo 20 matrices)

GLES20.glUniformMatrix4fv(u_Bones, 20, false, matrices, 0);

donde matricesestá float[16 * 20]. Pero luego modificar las matrices para cada hueso se vuelve un poco tedioso. Por ejemplo, si quiero obtener la tercera matriz, necesito algo en la línea de

float[] _3rd = Arrays.copy(matrices, 3*16, 4*16);

y volver a guardar los valores puede ser aún más molesto.


Estoy usando el Método 1 ahora, pero no parece muy inteligente ...

¿Cuál es la mejor manera de enviar múltiples matrices a un sombreador OpenGL ES 2?

LE: Estoy usando Android, así que estoy buscando una solución Java.

asíncrono
fuente
Solo una nota al margen: si tiene demasiadas matrices, también puede enviarlas a través de fp texture.
Kromster

Respuestas:

2

Enviar múltiples matrices al sombreador es sencillo:

Shader:

uniform mat4 mBones[20]; //20 matrices
.. skipped code ..
vec4 vert = vec4(vPosition, 1.0) * mBones[int(vaBoneId)];

Programa:

glUniformMatrix4fv(fShaderUnitSkeletal.uBones, 20, False, @bones20[0]); // Passing 20 matrices

Sin embargo, modificar las matrices para cada hueso no está relacionado con la forma en que las pasa al sombreador. Puede simplificar las modificaciones si trabaja con estructuras en lugar de una matriz de números.

bones20: array of TMatrix; // Declare array of matrices
bones20[2] := TMatrix.Identity; //Reset 3rd matrix
Kromster
fuente
1
Estoy usando Android / Java. Por lo tanto, no puedo usar "estructuras" u otros tipos de datos (perdón por el breve comentario, no puedo elaborar cajeros automáticos, pero volveré más tarde)
async
2

Sugeriría usar un VBO. Llena tu VBO con las matrices y pásalas usando un atributo en lugar de un uniforme. De esa manera, el VBO distribuirá un nuevo mat4 por cada paso de vértice en el sombreador.

Cuando vincula el VBO antes de dibujar (o crea un VAO para estos estados):

  • Habilite los atributos de vértice (glEnableVertexAttribArray)
  • Establezca los divisores de atributos de vértice en 0 (glVertexAttribDivisor)
  • Establecer el puntero de atributos de vértice (glVertexAttribPointer)

Eche un vistazo a cómo pasar un mat4 como atributo: /programming/17355051/using-a-matrix-as-vertex-attribute-in-opengl3-core-profile

Espero que esto ayude

Luka
fuente
1
Interesante. Sin embargo, las matrices pueden cambiar con bastante frecuencia (por ejemplo, puedo agregar una rotación adicional a uno de ellos en cada cuadro). No se quedarán igual. ¿Son adecuados los VBO para este escenario?
async
sí, simplemente carga las nuevas matrices cada cuadro usando glBufferData
Luka
0

El método 1 se puede ampliar para usar matrices para abstraer el número de matrices en el código: (suponiendo que Java)

int[] u_Bone=new int[NUM_MATRICES];

for(int i=0;i<u_Bone.length;i++)
   u_Bone[i]=GLES20.glGetUniformLocation(mProgram, "u_Bone["+i+"]");

y luego cuando configuras las matrices puedes hacer

for(int i=0;i<matrix.length;i++)
    GLES20.glUniformMatrix4fv(u_Bone[i], 1, false, matrix[i], 0);
monstruo de trinquete
fuente
Terminé implementando esto, pero aún no mejora mucho las cosas. Pero hasta ahora podría ser el mejor enfoque.
asíncrono