Как отправить несколько матриц в вершинный шейдер?

9

Я практикую анимацию с использованием костей / скинов. Я пытаюсь отправить шейдеру одну матрицу на вершину. Я могу думать об этих двух подходах.

Способ 1

У меня есть одна единая ручка для каждой костной матрицы, как это

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

и onDrawя отправляю каждого из них в шейдер: GLES20.glUniformMatrix4fv(u_Bone0, 1, false, matrix0, 0);

Это, очевидно, не очень хороший подход, если у меня есть большое количество матриц. Моя вторая идея, которую я еще не попробовал, так как есть много кода для рефакторинга

Способ 2

Это использовать, glUniformMatrix4fvчтобы отправить их все сразу, как (предположим, у меня есть 20 матриц)

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

где matricesнаходится float[16 * 20]. Но тогда изменение матриц для каждой кости становится немного утомительным. Например, если я хочу получить 3-ю матрицу, мне нужно что-то вроде

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

и сохранение значений может стать еще более раздражающим.


Я использую метод 1 сейчас, но он не выглядит очень умным ...

Каков наилучший способ отправки нескольких матриц в шейдер OpenGL ES 2?

LE: Я использую Android, поэтому я ищу решение Java.

асинхронной
источник
Просто знаком: если у вас слишком много матриц, вы также можете отправить их через текстуру fp.
Кромстер

Ответы:

2

Посылка нескольких матриц в шейдер проста:

Shader:

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

Программа:

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

Однако изменение матриц для каждой кости не связано с тем, как вы передаете их шейдеру. Вы можете упростить изменения, если будете работать со структурами, а не с массивом чисел.

bones20: array of TMatrix; // Declare array of matrices
bones20[2] := TMatrix.Identity; //Reset 3rd matrix
Kromster
источник
1
Я использую Android / Java. Поэтому я не могу использовать «структуры» или другие типы данных (извините за краткий комментарий, я не могу подробно описать atm, но вернусь позже)
async
2

Я бы предложил использовать VBO. Заполните VBO матрицами и передайте их, используя атрибут вместо униформы. Таким образом, VBO будет распределять новый mat4 за проход вершины в шейдере.

Когда вы связываете VBO перед рисованием (или создаете VAO для этих состояний):

  • Включить атрибуты вершины (glEnableVertexAttribArray)
  • Установите делители атрибутов вершины в 0 (glVertexAttribDivisor)
  • Установить указатель атрибутов вершины (glVertexAttribPointer)

Посмотрите, как передать mat4 как атрибут: /programming/17355051/using-a-matrix-as-vertex-attribute-in-opengl3-core-profile

Надеюсь это поможет

Luka
источник
1
Интересно. Однако матрицы могут меняться довольно часто (например, я могу добавить дополнительный поворот к одному из них в каждом кадре). Они не останутся прежними. Подходят ли VBO для этого сценария?
async
да, вы просто загружаете новые матрицы каждый кадр, используя glBufferData
Luka
0

Метод 1 может быть расширен за счет использования массивов для абстрагирования количества матриц в коде: (при условии, что 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+"]");

а затем, когда вы устанавливаете матрицы, вы можете сделать

for(int i=0;i<matrix.length;i++)
    GLES20.glUniformMatrix4fv(u_Bone[i], 1, false, matrix[i], 0);
чокнутый урод
источник
Я закончил тем, что реализовал это, но все еще не улучшаю вещи настолько. Но пока это может быть лучшим подходом.
async