9
\$\begingroup\$

I'm practising animations using bones/skinning. I am trying to send the shader one matrix per vertex. I can think of these two approaches.

Method 1

I have one uniform handle for each bone matrix like this

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

and in the onDraw I send each of them to the shader: GLES20.glUniformMatrix4fv(u_Bone0, 1, false, matrix0, 0);

This obviously isn't a good approach if I have a large number of matrices. My second idea which I haven't tried yet since there is a lot of code to refactor

Method 2

Is to use the glUniformMatrix4fv to send them all at once like (assume I have 20 matrices)

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

where matrices is float[16 * 20]. But then modifying the matrices for each bones becomes a bit tedious. For example, if I want to get the 3rd matrix, I need something along the lines of

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

and saving back the values can become even more annoying.


I'm using Method 1 now, but it doesn't look very smart...

What is the best way to send multiple matrices to an OpenGL ES 2 shader?

LE: I'm using Android, so I'm looking for a Java solution.

\$\endgroup\$
  • \$\begingroup\$ Just a sidenote: if you have too many matrices you can also send them via fp texture. \$\endgroup\$ – Kromster Feb 14 '14 at 11:36
2
\$\begingroup\$

Sending multiple matrices to shader is straightforward:

Shader:

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

Program:

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

Modifying the matrices for each bone is unrelated to how you pass them to the shader though. You can make modifications simpler if you work with structures instead of array of numbers.

bones20: array of TMatrix; // Declare array of matrices
bones20[2] := TMatrix.Identity; //Reset 3rd matrix
\$\endgroup\$
  • 1
    \$\begingroup\$ I'm using Android/Java. Therefore I can't use "structures" or other data types (Sorry for the brief comment, I can't elaborate atm, but will come back later) \$\endgroup\$ – async Feb 28 '14 at 10:33
2
\$\begingroup\$

I would suggest using a VBO. Fill your VBO with the matrices, and pass them in using an attribute instead of a uniform. That way the VBO will distribute a new mat4 per vertex pass in the shader.

When you bind the VBO before drawing (or create a VAO for these states):

  • Enable the vertex attributes (glEnableVertexAttribArray)
  • Set the vertex attributes divisors to 0 (glVertexAttribDivisor)
  • Set the vertex attributes pointer (glVertexAttribPointer)

Have a look at how to pass a mat4 as an attribute: https://stackoverflow.com/questions/17355051/using-a-matrix-as-vertex-attribute-in-opengl3-core-profile

Hope this helps

\$\endgroup\$
  • 1
    \$\begingroup\$ Interesting. However, the matrices may change quite frequently (for example I may add an additional rotation to one of them every frame). They won't stay the same. Are VBOs suitable for this scenario? \$\endgroup\$ – async Mar 2 '14 at 8:19
  • \$\begingroup\$ yes you just upload the new matrices every frame using glBufferData \$\endgroup\$ – Luka Mar 2 '14 at 10:46
0
\$\begingroup\$

method 1 can be expanded to use arrays to abstract out the number of matrices in the code: (assuming 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+"]");

and then when you set the matrices you can do

for(int i=0;i<matrix.length;i++)
    GLES20.glUniformMatrix4fv(u_Bone[i], 1, false, matrix[i], 0);
\$\endgroup\$
  • \$\begingroup\$ I ended up implementing this, but still doesn't improve things that much. But so far it could be the best approach. \$\endgroup\$ – async Feb 28 '14 at 18:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.