Como envio várias matrizes para um shader de vértice?

9

Estou praticando animações usando ossos / esfola. Estou tentando enviar ao shader uma matriz por vértice. Eu posso pensar nessas duas abordagens.

Método 1

Eu tenho uma alça uniforme para cada matriz óssea como esta

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

e no onDrawenvio cada um deles ao sombreador: GLES20.glUniformMatrix4fv(u_Bone0, 1, false, matrix0, 0);

Obviamente, isso não é uma boa abordagem se eu tiver um grande número de matrizes. Minha segunda ideia, que ainda não tentei, pois há muito código para refatorar

Método 2

É usar o glUniformMatrix4fvpara enviar todos de uma vez como (suponha que eu tenho 20 matrizes)

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

onde matricesé float[16 * 20]. Porém, modificar as matrizes de cada osso se torna um pouco entediante. Por exemplo, se eu quiser obter a 3ª matriz, preciso de algo ao longo das linhas de

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

e salvar de volta os valores pode se tornar ainda mais irritante.


Estou usando o método 1 agora, mas não parece muito inteligente ...

Qual é a melhor maneira de enviar várias matrizes para um shader OpenGL ES 2?

LE: Estou usando o Android, então estou procurando uma solução Java.

assíncrono
fonte
Apenas uma nota de rodapé: se você tiver muitas matrizes, também poderá enviá-las através da textura fp.
Kromster

Respostas:

2

O envio de várias matrizes para o shader é simples:

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

A modificação das matrizes para cada osso não está relacionada à maneira como você as passa para o shader. Você pode simplificar as modificações se trabalhar com estruturas em vez de matriz de números.

bones20: array of TMatrix; // Declare array of matrices
bones20[2] := TMatrix.Identity; //Reset 3rd matrix
Kromster
fonte
11
Estou usando Android / Java. Portanto, não posso usar "estruturas" ou outros tipos de dados (Desculpem o comentário breve, eu não posso elaborar atm, mas vai voltar mais tarde)
assíncrono
2

Eu sugeriria usar um VBO. Preencha seu VBO com as matrizes e passe-as usando um atributo em vez de um uniforme. Dessa forma, o VBO distribuirá uma nova passagem de mat4 por vértice no shader.

Quando você vincula o VBO antes de desenhar (ou cria um VAO para esses estados):

  • Habilite os atributos de vértice (glEnableVertexAttribArray)
  • Defina os divisores dos atributos do vértice como 0 (glVertexAttribDivisor)
  • Definir o ponteiro de atributos do vértice (glVertexAttribPointer)

Veja como passar um mat4 como um atributo: /programming/17355051/using-a-matrix-as-vertex-attribute-in-opengl3-core-profile

Espero que isto ajude

Luka
fonte
11
Interessante. No entanto, as matrizes podem mudar com bastante frequência (por exemplo, posso adicionar uma rotação adicional a uma delas a cada quadro). Eles não permanecerão os mesmos. Os VBOs são adequados para esse cenário?
assync 02/03
sim, você acabou de enviar as novas matrizes de cada quadro usando glBufferData
Luka
0

O método 1 pode ser expandido para usar matrizes para abstrair o número de matrizes no código: (assumindo 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+"]");

e então, quando você define as matrizes, pode fazer

for(int i=0;i<matrix.length;i++)
    GLES20.glUniformMatrix4fv(u_Bone[i], 1, false, matrix[i], 0);
catraca arrepiante
fonte
Acabei implementando isso, mas ainda não melhora muito as coisas. Mas até agora poderia ser a melhor abordagem.
assync 28/02