opengl es - Reducir datos duplicados en búferes de vértices
opengl-es opengl-es-2.0 (2)
Estoy usando búferes de 3 vértices a la vez (en realidad tengo muchos, pero solo hay 3 usados a la vez).
Contienen información que se mezcla en un sombreador para producir la salida deseada: una animación esquelética en 2D.
Hay dos amortiguadores de huesos , que contienen la posición / rotación / escala para un hueso en cualquier marco dado.
Hay un buffer de piel , que contiene los vértices para representar una región de una textura como si estuviera en el origen mundial, (0,0) .
En el sombreado, los dos amortiguadores de huesos se combinan con un valor de suavizado (que se pasa como un uniforme), y luego al transformar los vértices de la piel, las partes se renderizan en los lugares correctos.
Esto funciona muy bien, y es una buena mejora en cuanto a donde empecé - Calculé todo en la GPU, y simplemente pasé las coordenadas x / y / u / v, estaba limitado al transmitir tanta información a la GPU en cada fotograma.
Sin embargo, hay mucha información duplicada. El buffer de la piel contiene solo lo que necesita, 4 vértices por parte de la piel, cada uno único.
Sin embargo, cuando se combina con el hueso, cada vértice del hueso se duplica 4 veces para que coincida con el tampón de la piel. Trabajar en dispositivos móviles es un problema, porque me estoy quedando sin memoria, y me molesta que haya tanto desperdicio.
Así es como se verían los búferes si solo hubiera 1 hueso.
Búfer de huesos 1
[x1,y1,rot1] [x1,y1,rot1] [x1,y1,rot1] [x1,y1,rot1]
Tampón óseo 2
[x2,y2,rot2] [x2,y2,rot2] [x2,y2,rot2] [x2,y2,rot2]
Protector de piel
[xA,yA,uA,vA] [xB,yB,uB,vB] [xC,yC,uC,vC] [xD,yD,uD,vD]
No publicaré el sombreador completo, porque hay demasiadas cosas en juego (la rotación y la escala funcionan de manera similar):
attribute vec2 bonePosition1; // x1, y1
attribute vec2 bonePosition2; // x2, y2
attribute vec2 skinPosition; // xA (or xB .. ), yA (or yB .. )
uniform float a; // Some value 0..1 depending on time
...
vec2 bonePosition = mix(bonePosition1, bonePosition2, a);
vec2 combinedPosition = skinPosition * bonePosition;
Nota; dado que me estoy enfocando en iOS principalmente (otros también, pero es el más restrictivo), sé que estoy limitado a 16 atributos.
¿Hay alguna manera de reducir la huella de memoria de los amortiguadores de huesos? Tengo muchos, muchos cuadros en un buffer de piel.
Como veo, debe vincular más de un búfer de índices ( GL_ELEMENT_ARRAY_BUFFER
) para búferes con datos ( GL_ARRAY_BUFFER
). Si fue capaz de vincular 2 búferes GL_ARRAY_BUFFER
, puede vincular también un GL_ELEMENT_ARRAY_BUFFER
separado. No sé si esto se puede implementar en OpenGL ES. Si esto es imposible, puede intentar guardar la memoria usando enteros en lugar de flotantes, pero creo que esto no es aplicable a los valores de traducción / rotación de los huesos.
En cuanto a tu nota. Para superar el límite de 16 atributos, puede combinar atributos vec2
más vec2
en vec4
. Por ejemplo, puede combinar bonePosition1
y bonePosition2
en un vec4
:
attribute vec4 bonePosition12;
Y luego usarlo de esta manera en shader:
vec2 bonePosition1 = vec2(bonePosition12.x,bonePosition12.y);
vec2 bonePosition2 = vec2(bonePosition12.z,bonePosition12.w);
Esto podría tener un impacto menor en el rendimiento, pero dado que este código está en el sombreado de vértices, la caída del rendimiento debería ser insignificante, en comparación con las matemáticas del sombreado. Utilicé un código similar para manipular los colores (en el sombreador de fragmentos) y el rendimiento está bien.
¿Por qué estás poniendo huesos para atribuir? Mira, necesitas acceder a un hueso aleatorio desde cualquier invocación de sombreado de vértice. Por lo tanto, deberías usar un gran conjunto uniforme para todos tus huesos. Su estructura de vértices se verá así:
struct MyVertex
{
GLfloat x;
GLfloat y;
GLfloat z;
GLfloat w;
GLushort boneIndex;
};
Para vertex shader, necesitarás una matriz uniforme:
uniform vec4 bones[MAX_BONES];
Luego, usando boneIndex
puedes encontrar un hueso al que pertenece un vértice.
Las matrices uniformes funcionan bien para todas las versiones de GL ES. Si desea usar las características GL ES 3.0 (que están disponibles para iOS), use un objeto buffer uniforme .