Comment envoyer plusieurs matrices vers un vertex shader?

9

Je pratique des animations utilisant des os / skinning. J'essaie d'envoyer au shader une matrice par sommet. Je peux penser à ces deux approches.

Méthode 1

J'ai une poignée uniforme pour chaque matrice osseuse comme celle-ci

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

et dans le onDrawje les envoie chacun au shader: GLES20.glUniformMatrix4fv(u_Bone0, 1, false, matrix0, 0);

Ce n'est évidemment pas une bonne approche si j'ai un grand nombre de matrices. Ma deuxième idée que je n'ai pas encore essayée car il y a beaucoup de code à refactoriser

Méthode 2

Est d'utiliser le glUniformMatrix4fvpour les envoyer tous en même temps (supposons que j'ai 20 matrices)

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

matricesest float[16 * 20]. Mais alors, modifier les matrices pour chaque os devient un peu fastidieux. Par exemple, si je veux obtenir la 3e matrice, j'ai besoin de quelque chose comme

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

et sauvegarder les valeurs peut devenir encore plus ennuyeux.


J'utilise la méthode 1 maintenant, mais ça n'a pas l'air très intelligent ...

Quelle est la meilleure façon d'envoyer plusieurs matrices vers un shader OpenGL ES 2?

LE: J'utilise Android, donc je cherche une solution Java.

async
la source
Juste une note: si vous avez trop de matrices, vous pouvez également les envoyer via la texture fp.
Kromster

Réponses:

2

L'envoi de plusieurs matrices au shader est simple:

Shader:

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

Programme:

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

La modification des matrices pour chaque os n'est cependant pas liée à la façon dont vous les passez au shader. Vous pouvez simplifier les modifications si vous travaillez avec des structures au lieu d'un tableau de nombres.

bones20: array of TMatrix; // Declare array of matrices
bones20[2] := TMatrix.Identity; //Reset 3rd matrix
Kromster
la source
1
J'utilise Android / Java. Par conséquent, je ne peux pas utiliser de "structures" ou d'autres types de données (Désolé pour le bref commentaire, je ne peux pas élaborer atm, mais je reviendrai plus tard)
async
2

Je suggère d'utiliser un VBO. Remplissez votre VBO avec les matrices et passez-les en utilisant un attribut au lieu d'un uniforme. De cette façon, le VBO distribuera un nouveau mat4 par passe de sommet dans le shader.

Lorsque vous liez le VBO avant de dessiner (ou créez un VAO pour ces états):

  • Activer les attributs de sommet (glEnableVertexAttribArray)
  • Définissez les diviseurs d'attributs de sommet à 0 (glVertexAttribDivisor)
  • Définir le pointeur des attributs de sommet (glVertexAttribPointer)

Découvrez comment passer un mat4 en tant qu'attribut: /programming/17355051/using-a-matrix-as-vertex-attribute-in-opengl3-core-profile

J'espère que cela t'aides

Luka
la source
1
Intéressant. Cependant, les matrices peuvent changer assez fréquemment (par exemple, je peux ajouter une rotation supplémentaire à l'une d'entre elles à chaque image). Ils ne resteront pas les mêmes. Les VBO conviennent-ils à ce scénario?
asynchrone
oui vous téléchargez simplement les nouvelles matrices à chaque image en utilisant glBufferData
Luka
0

la méthode 1 peut être développée pour utiliser des tableaux pour extraire le nombre de matrices dans le code: (en supposant 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+"]");

puis lorsque vous définissez les matrices, vous pouvez le faire

for(int i=0;i<matrix.length;i++)
    GLES20.glUniformMatrix4fv(u_Bone[i], 1, false, matrix[i], 0);
monstre à cliquet
la source
J'ai fini par implémenter cela, mais ça n'améliore toujours pas beaucoup les choses. Mais jusqu'à présent, cela pourrait être la meilleure approche.
async