2012-01-06 8 views
9

Ho imparato OpenGL per un paio di giorni ormai, seguendo alcuni tutorial e codifica alcuni esperimenti della mia. Ma c'è una cosa che davvero non capisco e che mi impedisce di continuare. Sono stato su Google per un paio d'ore e non ho ancora trovato una risposta alla mia domanda.OpenGLES 2.0 buffer separati per i vertici, i colori e texture coordinate

Dove devo specificare ogni valore di colore separato e coordinata della texture per ogni vertice individuo? Dovrebbero quelle proprietà sempre essere incluso nello stesso array (struct) le posizioni dei vertici? Così:

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}}, 

    ... 

Oppure esiste un modo per inserire valori di colore e coordinate di trama in array separati? Ma allora sorge la domanda: Come chiamo glDrawElements con gli array separati?

Nel caso ti stia chiedendo perché voglio separare questi valori: attualmente sto creando il mio parser .obj in obj-c e mi chiedevo: cosa succede se carichi un modello senza una trama e vuoi solo mostrare un colore sull'oggetto? Oppure: cosa succede se vuoi caricare un modello con solo una trama mappata ad esso ma nessun colore separato per vertice? E: non sta mettendo i valori del colore e le coordinate delle texture gonfiano la struttura del vertice con troppi dati.

risposta

21

In realtà è il solito modo di separare i dati del vertice in posizione, colore, ecc. usando diversi array/buffer.

ultima volta che sono venuto in contatto con ES 2.0 è stato nel contesto di WebGL (che è ha una spec leggermente diverso, ma è in ultima analisi, basata su ES 2.0).

Ciò che è sostanzialmente fatto è la scrittura dei dati sul buffer separati 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 posizioni e colori essendo matrici mobili contenente i dati di vertice e indici contenenti gli indici come pantaloncini firmati in questo caso.

per rendere questi dati, utilizza i buffer e attribuisci puntatori al 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); 

Infine legano il buffer dell'indice:

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); 

e rendere:

glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, 0); 

Per ottenere gli attributi:

glUseProgram(shaderProgram); 

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

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

... 

Se non si dispone di shaders personalizzati (utilizzando funzione fissa) potrebbe essere in grado di utilizzare

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

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

invece. Ne sconsiglio comunque, dato che è obsoleto (se disponibile in ES 2.0). Se si desidera continuare ad usarlo, si può saltare l'intero buffer business del tutto e utilizzare

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

con

glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, indices); 

Spero che non era troppo confusa e aiuta un po '. Per ulteriori letture, sebbene mirato a OpenGL, suggerirei lo Nehe tutorials.

+0

cristallino! ;) – polyclick

0

È possibile separarli in sub-buffer ma se li si utilizza, è necessario averli per tutti i vertici e se si utilizzano i buffer dell'indice, è necessario utilizzare un buffer di indice per tutti (posizione, colore, texcoord, ecc.). Ecco alcuni brani del mio codice:

allocazione con

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

riempire con

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

e l'uso con questo (non credo clientStates costantemente di commutazione è best-practice però)

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

In realtà non risponde alla domanda se è possibile memorizzare attributi diversi in buffer completamente diversi, cosa che si può sicuramente. –

+0

Il mio male. Semplicemente non pensavo ci fosse una differenza significativa tra l'utilizzo di sub-buffer e buffer completamente separati per il suo scopo, in quanto sarebbero allocati insieme, deallocati insieme e utilizzati sempre insieme se contengono dati diversi per lo stesso oggetto. – PeterT

+0

Veramente vero, ma ha ancora fatto una domanda a cui rispondere. –

2

Ovviamente è possibile avere i dati in buffer diversi. Tieni presente che è la chiamata glVertexAttribPointer che determina la fonte di un attributo. Quindi, per utilizzare un buffer diverso per un attributo, è sufficiente associare un diverso GL_ARRAY_BUFFER prima di chiamare glVertexAttribPointer. glDrawElements non ha nulla a che fare con esso:

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

Quando non si utilizza VBOs (che io non sono sicuro che è possibile in ES 2.0), basta chiamare glVertexAttribPointer con un allineamento diverso per ogni attributo:

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

glDrawElements(..., indexArray); 

glDisableVertexAttribArray(0); 
glDisableVertexAttribArray(1); 

Ma di solito è più performante mantenere gli attributi di un singolo vertice come nell'esempio, poiché questo è più facile da usare nella cache. Se quasi tutti i tuoi oggetti usano tutti gli array, quindi tenerli insieme e non abilitare l'attributo per i pochi oggetti che non li usano, potrebbe essere un'idea migliore. Ma se gli attributi usati differiscono davvero da oggetto a oggetto, la soluzione tampone separata potrebbe essere un'idea migliore. È anche possibile memorizzare tutti gli array di attributi separati uno dopo l'altro in un singolo VBO e utilizzare gli offset di buffer corrispondenti nelle chiamate glVertexAttribPointer, quindi è ancora necessario un solo VBO per oggetto.

Ma ovviamente è possibile utilizzare solo un array di indici per oggetto e non matrici di indici diversi per posizioni e colori. Ciò potrebbe richiedere di postelaborare un po 'i dati letti da un file OBJ, poiché i file OBJ possono effettivamente utilizzare indici diversi per posizioni, normali e texCoords.

Problemi correlati