Як надсилати кілька матриць до вершинного шейдера?


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

Надсилання декількох матриць на шейдер просте:

Шейдер:

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

1
Я використовую Android / Java. Тому я не можу використовувати "структури" чи інші типи даних (Вибачте за короткий коментар, не можу розробити атм, але повернусь пізніше)
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

Сподіваюсь, це допомагає


1
Цікаво. Однак матриці можуть змінюватися досить часто (наприклад, я можу додати додатковий обертання до одного з них кожен кадр). Вони не залишаться такими ж. Чи підходять VBO для цього сценарію?
асинхрон

так, ви просто завантажуйте нові матриці кожен кадр, використовуючи glBufferData
Лука

0

метод 1 може бути розширений, щоб використовувати масиви для вилучення кількості матриць у коді: (якщо ява)

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);

Я в кінцевому підсумку реалізував це, але все ще не настільки покращує речі. Але поки це може бути найкращим підходом.
асинхрон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.