2012-01-06 19 views
9

He estado aprendiendo OpenGL durante unos días siguiendo algunos tutoriales y codificando algunos experimentos propios. Pero hay una cosa que realmente no entiendo que me impide continuar. He estado buscando en Google por unas horas y aún no he encontrado una respuesta a mi pregunta.Buffers separados de OpenGLES 2.0 para vértices, colores y coordenadas de textura

¿Dónde debería especificar cada valor de color y coordenada de textura para cada vértice individual? ¿Deberían enumerarse esas propiedades siempre en la misma matriz (struct) que las posiciones de los vértices? De esta manera:

const Vertex Vertices[] = { 
    // Front 
    {{1, -1, 0}, {1, 0, 0, 1}, {TEX_COORD_MAX, 0}}, 
    {{1, 1, 0}, {0, 1, 0, 1}, {TEX_COORD_MAX, TEX_COORD_MAX}}, 
    {{-1, 1, 0}, {0, 0, 1, 1}, {0, TEX_COORD_MAX}}, 
    {{-1, -1, 0}, {0, 0, 0, 1}, {0, 0}}, 

    ... 

¿O hay una forma de poner los valores de color y las coordenadas de la textura en matrices separadas? Pero entonces surge la pregunta: ¿cómo puedo llamar al glDrawElements con matrices separadas?

En caso de que se pregunte por qué quiero separar estos valores: Actualmente estoy haciendo mi propio analizador .obj en obj-c y me preguntaba: ¿qué pasa si carga un modelo sin una textura y solo desea mostrar un color en el objeto? O bien: ¿y si quieres cargar un modelo con solo una textura mapeada, pero sin color por vértice? Y: no está poniendo valores de color y textura hinchando la estructura Vertex con demasiados datos.

Respuesta

21

En realidad, es la forma habitual de separar los datos de vértice en posición, color, etc. usando varias matrices/almacenamientos intermedios.

La última vez que entré en contacto con ES 2.0 fue en el contexto de WebGL (que tiene una especificación ligeramente diferente, pero que en última instancia se basa en ES 2.0).

Lo que se realiza básicamente está escribiendo los datos en memorias intermedias separadas usando

glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); 
glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(float), positions, GL_STATIC_DRAW); 
glBindBuffer(GL_ARRAY_BUFFER, 0); 

glBindBuffer(GL_ARRAY_BUFFER, colorBuffer); 
glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(float), colors, GL_STATIC_DRAW); 
glBindBuffer(GL_ARRAY_BUFFER, 0); 

... 

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); 
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(ushort), indices, GL_STATIC_DRAW); 
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 

con posiciones y colores que son matrices de flotación que contienen los datos de vértices y los índices que contienen los índices como unsignedshorts en este caso.

Rendir estos datos, tendrá que utilizar los tampones y atributos punteros a su shader:

glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); 
glVertexAttribPointer(vertexPositionAttribute, 3, GL_FLOAT, false, 0, 0); 

glBindBuffer(GL_ARRAY_BUFFER, colorBuffer); 
glVertexAttribPointer(vertexColorAttribute, 4, GL_FLOAT, false, 0, 0); 

Finalmente obligar a la memoria intermedia de índice:

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); 

y render:

glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, 0); 

Para obtener los atributos:

glUseProgram(shaderProgram); 

vertexPositionAttribute= glGetAttribLocation(shaderProgram, "vertexPosition"); 
glEnableVertexAttribArray(vertexPositionAttribute); 

vertexColorAttribute = glGetAttribLocation(shaderProgram, "vertexColor"); 
glEnableVertexAttribArray(vertexColorAttribute); 

... 

Si usted no tiene shaders personalizados (utilizando la función fija) es posible que pueda utilizar

glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); 
glVertexPointer(3, GL_FLOAT, false, 0, 0); 

glBindBuffer(GL_ARRAY_BUFFER, colorBuffer); 
glColorPointer(4, GL_FLOAT, false, 0, 0); 

lugar. Sin embargo, desaconsejaría, ya que está desactualizado (si es que está disponible en ES 2.0). Si aún desea utilizarlo, puede pasar todo el asunto por completo búfer y utilizar

glVertexPointer(3, GL_FLOAT, false, 0, positions); 
glColorPointer(4, GL_FLOAT, false, 0, colors); 

con

glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, indices); 

espero que no era demasiado confuso y ayuda un poco. Para una mayor lectura, aunque apuntado a OpenGL, sugeriría el Nehe tutorials.

+0

¡Claro como el cristal! ;) – polyclick

0

Puede separarlos en subtampones pero si los usa tiene que tenerlos para todos los vértices y si usa los almacenamientos intermedios, entonces tiene que usar un índice-buffer para todos (posición, color, texcoord, etc.). He aquí algunos extractos de mi código:

asignación con

glBindBuffer(GL_ARRAY_BUFFER, mId); 
glBufferData(GL_ARRAY_BUFFER, 
       mMaxNumberOfVertices * (mVertexBlockSize + mNormalBlockSize + mColorBlockSize + mTexCoordBlockSize), 
       0, 
       mDrawMode); 

llene de

glBufferSubData(GL_ARRAY_BUFFER, mVertexOffset, numberOfVertsToStore * mVertexBlockSize, vertices); 
glBufferSubData(GL_ARRAY_BUFFER, mNormalOffset, numberOfVertsToStore * mNormalBlockSize, normals); 
glBufferSubData(GL_ARRAY_BUFFER, mColorOffset, numberOfVertsToStore * mColorBlockSize, colors); 
glBufferSubData(GL_ARRAY_BUFFER, mTexCoordOffset, numberOfVertsToStore * mTexCoordBlockSize, texCoords); 

y su uso con esta (no creo clientStates cambiar constantemente es la mejor práctica sin embargo)

void Vbo::draw(GLenum primMode) 
{ 
    glEnableClientState(GL_VERTEX_ARRAY); 
    glVertexPointer(mVertexComponents, GL_FLOAT, 0, (void*)mVertexOffset); 

    if(mNormalBlockSize){ 
    glEnableClientState(GL_NORMAL_ARRAY); 
    glNormalPointer(GL_FLOAT, 0, (void*)mNormalOffset); 
    } 
    if(mColorBlockSize){ 
    glEnableClientState(GL_COLOR_ARRAY); 
    glColorPointer(mColorComponents, GL_FLOAT, 0, (void*)mColorOffset); 
    } 
    if(mTexCoordBlockSize){ 
    glEnableClientState(GL_TEXTURE_COORD_ARRAY); 
    glTexCoordPointer(mTexCoordComponents, GL_FLOAT, 0, (void*)mTexCoordOffset); 
    } 

    if (mAttachedIndexBuffer) 
    { 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mAttachedIndexBuffer); 
    glDrawElements(primMode, 
        mAttachedIndexBuffer->getNumberOfStoredIndices(), 
        mAttachedIndexBuffer->getDataType(), 
        0); 
    } 
    else 
    { 
    glDrawArrays(primMode, 0, mNumberOfStoredVertices); 
    } 

    if(mTexCoordBlockSize) 
    { 
    glDisableClientState(GL_TEXTURE_COORD_ARRAY); 
    } 
    if(mColorBlockSize) 
    { 
    glDisableClientState(GL_COLOR_ARRAY); 
    } 
    if(mNormalBlockSize) 
    { 
    glDisableClientState(GL_NORMAL_ARRAY); 
    } 
    glDisableClientState(GL_VERTEX_ARRAY); 
}  
+1

Realmente no responde la pregunta si puede almacenar diferentes atributos en búferes completamente diferentes, lo que definitivamente puede hacer. –

+0

Mi mal. Simplemente no creía que hubiera una diferencia significativa entre el uso de subtampones y los almacenamientos intermedios completamente separados para su propósito, ya que se asignarían juntos, se desasignarían y se usarían siempre juntos si contienen datos diferentes para el mismo objeto. – PeterT

+0

Verdaderamente cierto, pero igual hizo una pregunta para ser respondida. –

2

Por supuesto, puede tener sus datos en diferentes buffers. Tenga en cuenta que es la llamada glVertexAttribPointer la que determina el origen de un atributo. Entonces, para usar un buffer diferente para un atributo, simplemente enlace un GL_ARRAY_BUFFER diferente antes de llamar al glVertexAttribPointer. glDrawElements no tiene nada que ver con ello:

glBindBuffer(GL_ARRAY_BUFFER, positionBuffer); 
glVertexAttribPointer(0, ...); 
glEnableVertexAttribArray(0); 
glBindBuffer(GL_ARRAY_BUFFER, colorBuffer); 
glVertexAttribPointer(1, ...); 
glEnableVertexAttribArray(1); 
glBindBuffer(GL_ARRAY_BUFFER, 0); 

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); 
glDrawElements(...); 

glDisableVertexAttribArray(0); 
glDisableVertexAttribArray(1); 

Cuando no utilice OISCIV (que no estoy seguro es posible en ES 2.0), sólo llame glVertexAttribPointer con una matriz diferente para cada atributo:

glVertexAttribPointer(0, ..., positionArray); 
glEnableVertexAttribArray(0); 
glVertexAttribPointer(1, ..., colorArray); 
glEnableVertexAttribArray(1); 

glDrawElements(..., indexArray); 

glDisableVertexAttribArray(0); 
glDisableVertexAttribArray(1); 

Pero generalmente es más eficaz mantener juntos los atributos de un vértice como en el ejemplo, ya que es más compatible con la caché. Si casi todos sus objetos usan todas las matrices, puede ser una mejor idea mantenerlos juntos y simplemente no habilitar el atributo para los pocos objetos que no lo usan. Pero si los atributos utilizados realmente difieren de un objeto a otro, la solución de buffer por separado puede ser una mejor idea. También puede almacenar todas las matrices de atributos separadas una después de la otra en un solo VBO y usar las compensaciones de búfer correspondientes en las llamadas glVertexAttribPointer, por lo que solo necesita un VBO por objeto.

Pero, por supuesto, solo puede usar una matriz de índices por objeto y no diferentes matrices de índices para las posiciones y los colores. Esto puede requerir que postproceses un poco la lectura de datos de un archivo OBJ, ya que los archivos OBJ pueden usar diferentes índices para posiciones, normales y texCoords.

Cuestiones relacionadas