Wie sende ich mehrere Matrizen an einen Vertex-Shader?

9

Ich übe Animationen mit Knochen / Häuten. Ich versuche, dem Shader eine Matrix pro Scheitelpunkt zu senden. Ich kann mir diese beiden Ansätze vorstellen.

Methode 1

Ich habe einen einheitlichen Griff für jede Knochenmatrix wie diese

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

und in der onDrawsende ich jeden von ihnen an den Shader: GLES20.glUniformMatrix4fv(u_Bone0, 1, false, matrix0, 0);

Dies ist offensichtlich kein guter Ansatz, wenn ich eine große Anzahl von Matrizen habe. Meine zweite Idee, die ich noch nicht ausprobiert habe, da es viel Code zum Refactor gibt

Methode 2

Ist das zu verwenden glUniformMatrix4fv, um sie alle auf einmal zu senden (nehme an, ich habe 20 Matrizen)

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

wo matricesist float[16 * 20]. Aber dann wird das Ändern der Matrizen für jeden Knochen etwas mühsam. Wenn ich zum Beispiel die 3. Matrix erhalten möchte, brauche ich etwas in der Art von

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

und das Zurückspeichern der Werte kann noch ärgerlicher werden.


Ich benutze jetzt Methode 1, aber es sieht nicht sehr klug aus ...

Was ist der beste Weg, um mehrere Matrizen an einen OpenGL ES 2-Shader zu senden?

LE: Ich benutze Android und suche nach einer Java-Lösung.

asynchron
quelle
Nur eine Randnotiz: Wenn Sie zu viele Matrizen haben, können Sie diese auch über die fp-Textur senden.
Kromster

Antworten:

2

Das Senden mehrerer Matrizen an den Shader ist unkompliziert:

Shader:

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

Programm:

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

Das Ändern der Matrizen für jeden Knochen hängt jedoch nicht davon ab, wie Sie sie an den Shader übergeben. Sie können Änderungen vereinfachen, wenn Sie mit Strukturen anstelle von Zahlenreihen arbeiten.

bones20: array of TMatrix; // Declare array of matrices
bones20[2] := TMatrix.Identity; //Reset 3rd matrix
Kromster
quelle
1
Ich benutze Android / Java. Daher kann ich keine "Strukturen" oder andere Datentypen verwenden (Entschuldigung für den kurzen Kommentar, ich kann atm nicht näher erläutern, werde aber später wiederkommen)
async
2

Ich würde vorschlagen, einen VBO zu verwenden. Füllen Sie Ihren VBO mit den Matrizen und übergeben Sie sie mit einem Attribut anstelle einer Uniform. Auf diese Weise verteilt der VBO eine neue mat4 pro Vertex-Pass im Shader.

Wenn Sie den VBO vor dem Zeichnen binden (oder einen VAO für diese Zustände erstellen):

  • Aktivieren Sie die Vertex-Attribute (glEnableVertexAttribArray)
  • Setzen Sie die Vertexattributteiler auf 0 (glVertexAttribDivisor).
  • Setzen Sie den Zeiger für die Scheitelpunktattribute (glVertexAttribPointer).

Sehen Sie sich an, wie Sie eine mat4 als Attribut übergeben: /programming/17355051/using-a-matrix-as-vertex-attribute-in-opengl3-core-profile

Hoffe das hilft

Luka
quelle
1
Interessant. Die Matrizen können sich jedoch ziemlich häufig ändern (zum Beispiel kann ich jedem von ihnen in jedem Frame eine zusätzliche Drehung hinzufügen). Sie werden nicht gleich bleiben. Sind VBOs für dieses Szenario geeignet?
Async
Ja, Sie laden einfach die neuen Matrizen in jedem Frame mit glBufferData
Luka
0

Methode 1 kann erweitert werden, um mithilfe von Arrays die Anzahl der Matrizen im Code zu abstrahieren: (unter der Annahme von 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+"]");

und dann, wenn Sie die Matrizen einstellen, können Sie tun

for(int i=0;i<matrix.length;i++)
    GLES20.glUniformMatrix4fv(u_Bone[i], 1, false, matrix[i], 0);
Ratschenfreak
quelle
Am Ende habe ich das implementiert, aber es verbessert die Dinge immer noch nicht so sehr. Aber bisher könnte es der beste Ansatz sein.
Async