Jak wysłać wiele macierzy do modułu cieniującego wierzchołki?

9

Ćwiczę animacje przy użyciu kości / skórowania. Próbuję wysłać moduł cieniujący jedną macierz na wierzchołek. Mogę wymyślić te dwa podejścia.

Metoda 1

Mam jeden jednolity uchwyt dla każdej takiej matrycy kostnej

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

a następnie onDrawwysyłam każdego z nich do modułu cieniującego: GLES20.glUniformMatrix4fv(u_Bone0, 1, false, matrix0, 0);

To oczywiście nie jest dobre podejście, jeśli mam dużą liczbę matryc. Mój drugi pomysł, którego jeszcze nie wypróbowałem, ponieważ jest dużo kodu do refaktoryzacji

Metoda 2

Jest użyć, glUniformMatrix4fvaby wysłać je wszystkie jednocześnie (zakładając, że mam 20 macierzy)

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

gdzie matricesjest float[16 * 20]. Ale modyfikowanie matryc dla każdej kości staje się nieco nudne. Na przykład, jeśli chcę uzyskać trzecią macierz, potrzebuję czegoś podobnego do

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

a zapisanie wartości może stać się jeszcze bardziej irytujące.


Używam teraz Metody 1, ale nie wygląda to zbyt mądrze ...

Jaki jest najlepszy sposób wysyłania wielu macierzy do modułu cieniującego OpenGL ES 2?

LE: Używam Androida, więc szukam rozwiązania Java.

asynchronizacja
źródło
Po prostu sidenote: jeśli masz zbyt wiele macierzy, możesz również wysłać je przez teksturę fp.
Kromster

Odpowiedzi:

2

Wysyłanie wielu macierzy do modułu cieniującego jest proste:

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

Modyfikacja macierzy dla każdej kości nie ma jednak związku z tym, jak przekazujesz je do modułu cieniującego. Możesz uprościć modyfikacje, jeśli pracujesz ze strukturami zamiast z tablicą liczb.

bones20: array of TMatrix; // Declare array of matrices
bones20[2] := TMatrix.Identity; //Reset 3rd matrix
Kromster
źródło
1
Używam Androida / Java. Dlatego nie mogę używać „struktur” ani innych typów danych (przepraszam za krótki komentarz, nie mogę opracować bankomatu, ale wrócę później)
asynchronizuje
2

Sugerowałbym użycie VBO. Wypełnij VBO macierzami i przekaż je za pomocą atrybutu zamiast munduru. W ten sposób VBO rozdzieli nowy moduł mat4 na przebieg wierzchołka w module cieniującym.

Gdy powiążesz VBO przed rysowaniem (lub utworzysz VAO dla tych stanów):

  • Włącz atrybuty wierzchołka (glEnableVertexAttribArray)
  • Ustaw dzielniki atrybutów wierzchołków na 0 (glVertexAttribDivisor)
  • Ustaw wskaźnik atrybutów wierzchołka (glVertexAttribPointer)

Zobacz, jak przekazać mat4 jako atrybut: /programming/17355051/using-a-matrix-as-vertex-attribute-in-opengl3-core-profile

Mam nadzieję że to pomoże

Luka
źródło
1
Ciekawy. Jednak matryce mogą zmieniać się dość często (na przykład mogę dodać dodatkowy obrót do jednej z nich w każdej klatce). Nie pozostaną takie same. Czy VBO są odpowiednie dla tego scenariusza?
asynchronizacja
tak, po prostu przesyłasz nowe macierze co klatkę za pomocą glBufferData
Luka
0

metodę 1 można rozszerzyć o użycie tablic do wyodrębnienia liczby macierzy w kodzie: (przy założeniu 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+"]");

a po ustawieniu macierzy możesz to zrobić

for(int i=0;i<matrix.length;i++)
    GLES20.glUniformMatrix4fv(u_Bone[i], 1, false, matrix[i], 0);
maniak zapadkowy
źródło
Skończyło się na tym, ale wciąż nie poprawiam zbyt wiele. Ale jak dotąd może to być najlepsze podejście.
asynchronizuje