5

Attualmente sto usando i corsi GLTools che accompagnano la 5a edizione di Superbible. Sto cercando nella classe GLTriangleBatch e ha il seguente codice:Oggetto buffer OpenGL Vertex, posso accedere ai dati del vertice per altri usi come il rilevamento delle collisioni?

// Create the master vertex array object 
glGenVertexArrays(1, &vertexArrayBufferObject); 
glBindVertexArray(vertexArrayBufferObject); 


// Create the buffer objects 
glGenBuffers(4, bufferObjects); 

#define VERTEX_DATA  0 
#define NORMAL_DATA  1 
#define TEXTURE_DATA 2 
#define INDEX_DATA  3 

// Copy data to video memory 
// Vertex data 
glBindBuffer(GL_ARRAY_BUFFER, bufferObjects[VERTEX_DATA]); 
glEnableVertexAttribArray(GLT_ATTRIBUTE_VERTEX); 
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*nNumVerts*3, pVerts, GL_STATIC_DRAW); 
glVertexAttribPointer(GLT_ATTRIBUTE_VERTEX, 3, GL_FLOAT, GL_FALSE, 0, 0); 

// Normal data 
glBindBuffer(GL_ARRAY_BUFFER, bufferObjects[NORMAL_DATA]); 
glEnableVertexAttribArray(GLT_ATTRIBUTE_NORMAL); 
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*nNumVerts*3, pNorms, GL_STATIC_DRAW); 
glVertexAttribPointer(GLT_ATTRIBUTE_NORMAL, 3, GL_FLOAT, GL_FALSE, 0, 0); 

// Texture coordinates 
glBindBuffer(GL_ARRAY_BUFFER, bufferObjects[TEXTURE_DATA]); 
glEnableVertexAttribArray(GLT_ATTRIBUTE_TEXTURE0); 
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*nNumVerts*2, pTexCoords, GL_STATIC_DRAW); 
glVertexAttribPointer(GLT_ATTRIBUTE_TEXTURE0, 2, GL_FLOAT, GL_FALSE, 0, 0); 

// Indexes 
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferObjects[INDEX_DATA]); 
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort)*nNumIndexes, pIndexes, GL_STATIC_DRAW); 

// Done 
glBindVertexArray(0); 

// Free older, larger arrays 
delete [] pIndexes; 
delete [] pVerts; 
delete [] pNorms; 
delete [] pTexCoords; 

// Reasign pointers so they are marked as unused 
pIndexes = NULL; 
pVerts = NULL; 
pNorms = NULL; 
pTexCoords = NULL; 

Da quello che ho capito il codice passa le matrici che i puntatori pVerts, pNorms, pTexCoords, pIndexes e li memorizza in un oggetto array Vertex, che essenzialmente è una matrice di oggetti buffer vertici. Questi sono memorizzati in memoria sulla GPU. I puntatori originali vengono quindi eliminati.

Sono interessato ad accedere alle posizioni dei vertici, che sono state mantenute nell'array pVert indicato.

Ora la mia domanda ruota attorno al rilevamento delle collisioni. Voglio poter accedere a un array di tutti i vertici del mio GLTriangleBatch. Posso ottenerli attraverso lo vertexBufferObject in un secondo momento usando una sorta di metodo getter? Sarebbe meglio mantenere semplicemente il puntatore pVerts e utilizzare invece un metodo getter per questo? Sto pensando in termini di prestazioni, in quanto spero di implementare un algoritmo di rilevamento collisione GJK in futuro ...

risposta

7

Gli oggetti buffer, quando utilizzati come origini per i dati dei vertici, esistono per il beneficio di rendering. Andare indietro (leggere i dati indietro) non è generalmente consigliabile dal punto di vista delle prestazioni.

Il suggerimento che date a glBufferData ha tre schemi di accesso: DRAW, READ e COPY; questi dicono a OpenGL come intendete ottenere/recuperare i dati direttamente dall'oggetto buffer. I suggerimenti non governano il modo in cui OpenGL dovrebbe leggere/scrivere da/a esso. Questi sono solo suggerimenti; l'API non applica alcun particolare comportamento, ma la loro violazione può comportare prestazioni scadenti.

DRAW significa che si inseriranno i dati nel buffer, ma non si leggerà da esso. READ significa che si leggeranno i dati dal buffer, ma non si scriverà su di esso (in genere per il feedback di trasformazione o buffer di pixel). E COPY significa che non leggerete né scriverete direttamente al buffer.

Si noti che non vi è alcun suggerimento per "leggi e scrivi". C'è solo "scrivi", "leggi" e "nessuno dei due". Considera un suggerimento su quanto sia buona l'idea di scrivere i dati direttamente in un buffer e poi iniziare a leggere da quel buffer.

Di nuovo, i suggerimenti sono per l'utente che ottiene o recupera i dati direttamente. glBufferData, glBufferSubData e le varie funzioni di mapping eseguono tutte le scritture, mentre le funzioni glGetBufferSubData e di mapping vengono tutte lette.

In ogni caso no, non dovresti farlo. Conservare una copia dei dati sulla posizione nella memoria del client se è necessario utilizzarla sul client.

Inoltre, alcuni driver ignorano completamente i suggerimenti di utilizzo. Decidono invece dove posizionare l'oggetto buffer in base a come lo si utilizza effettivamente, piuttosto che come si dice che si intende utilizzarlo. Questo sarà peggio per te, perché se inizi a leggere da quel buffer, il driver può spostare i dati del buffer in memoria che non è così veloce. Può essere spostato fuori dalla GPU e persino nello spazio di memoria del client.

Tuttavia, se si insiste per farlo, ci sono due modi per leggere i dati da un oggetto buffer. glGetBufferSubData è l'inverso di glBufferSubData. E puoi sempre mappare il buffer per la lettura anziché scrivere.

+1

Grazie! Questa risposta è stata molto utile! Terrò il puntatore pVert in giro per accedere ai dati del vertice in seguito. – kbirk

+0

@ user785259: mantenere il puntatore non è sufficiente. In realtà devi mantenere la memoria allocata, cioè non 'delete []' o 'free (...)' it. Anche dopo aver rilasciato la memoria potresti avere ancora il puntatore in C, che quindi non è valido. Forse stai venendo da un linguaggio spazzato, quindi scartare un puntatore implica in realtà liberare memoria, e sì, questa è la semantica sana. Ma questo è il C++ con cui hai a che fare e tutto ciò è una necessità inevitabile lì. – datenwolf