2011-10-19 16 views
5

Así que he estado tratando de enseñarme a usar VBOs, con el fin de aumentar el rendimiento de mi proyecto OpenGL y aprender cosas más avanzadas que la renderización de funciones fijas. Pero no he encontrado mucho en el camino de un tutorial decente; los mejores que he encontrado hasta ahora son Songho's tutorials y las cosas en OpenGL.org, pero parece que me falta algún tipo de conocimiento previo para entender completamente lo que está pasando, aunque no puedo decir exactamente qué es lo que no obtengo , guarda el uso de algunos parámetros.Aprendiendo a usar VBOs correctamente

En cualquier caso, me he forjado adelante y propongo un código canibalizado que, al menos, no falla, pero conduce a resultados extraños. Lo que quiero mostrar es esto (representado con una función fija, se supone que es marrón y el fondo gris, pero todas mis capturas de pantalla de OpenGL parecen adoptar magenta como su color favorito, ¿tal vez es porque utilizo SFML para la ventana?).

Target image

Lo consigo, sin embargo, es la siguiente:

Actual image

Estoy en una pérdida. Aquí está el código relevante que uso, primero para la creación de los objetos de amortiguamiento (asigno gran cantidad de memoria de acuerdo con la recomendación de asignar this guy's 4-8mb):

GLuint WorldBuffer; 
GLuint IndexBuffer; 

... 

glGenBuffers(1, &WorldBuffer); 
glBindBuffer(GL_ARRAY_BUFFER, WorldBuffer); 
int SizeInBytes = 1024 * 2048; 
glBufferData(GL_ARRAY_BUFFER, SizeInBytes, NULL, GL_STATIC_DRAW); 

glGenBuffers(1, &IndexBuffer); 
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBuffer); 
SizeInBytes = 1024 * 2048; 
glBufferData(GL_ELEMENT_ARRAY_BUFFER, SizeInBytes, NULL, GL_STATIC_DRAW); 

Luego de cargar los datos en el búfer. Tenga en cuenta que CreateVertexArray() llena el vector en la ubicación pasada con datos de vértice, con cada vértice aportando 3 flotantes para posición y 3 flotantes para normal (una de las cosas más confusas sobre los diversos tutoriales fue qué formato debo almacenar y transferir mi real datos de vértice en, lo que parecía una aproximación decente):

std::vector<float>* VertArray = new std::vector<float>; 
pWorld->CreateVertexArray(VertArray); 
unsigned short Indice = 0; 
for (int i = 0; i < VertArray->size(); ++i) 
{ 
    std::cout << (*VertArray)[i] << std::endl; 
    glBufferSubData(GL_ARRAY_BUFFER, i * sizeof(float), sizeof(float), &((*VertArray)[i])); 
    glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, i * sizeof(unsigned short), sizeof(unsigned short), &(Indice)); 
    ++Indice; 
} 
delete VertArray; 
Indice -= 1; 

Después de eso, en el bucle del juego, utilizo este código:

glBindBuffer(GL_ARRAY_BUFFER, WorldBuffer);   
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBuffer);  

    glEnableClientState(GL_VERTEX_ARRAY);   
    glVertexPointer(3, GL_FLOAT, 0, 0); 
    glNormalPointer(GL_FLOAT, 0, 0); 

    glDrawElements(GL_TRIANGLES, Indice, GL_UNSIGNED_SHORT, 0); 

    glDisableClientState(GL_VERTEX_ARRAY); 

    glBindBuffer(GL_ARRAY_BUFFER, 0); 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 

voy a ser totalmente honesto - no soy seguro entiendo lo que debe ser el tercer parámetro de glVertexPointer() y glNormalPointer() (zancada es el desplazamiento en tes, pero Songho usa un desplazamiento de 0 bytes entre valores - ¿qué?), o cuál es el último parámetro de cualquiera de ellos. El valor inicial se dice que es 0; pero se supone que es un puntero. Pasar un puntero nulo para obtener la primera coordenada/valor normal de la matriz parece extraño. This guy usa BUFFER_OFFSET(0) y BUFFER_OFFSET(12), pero cuando intento eso, me dicen que BUFFER_OFFSET() no está definido.

Además, el último parámetro de glDrawElements() se supone que es una dirección, pero de nuevo, Songho utiliza una dirección de 0. Si uso &IndexBuffer en lugar de 0, aparece una pantalla en blanco sin nada representación en absoluto, excepto el fondo .

¿Alguien me puede aclarar, o al menos apuntarme en la dirección de algo que me ayude a resolver esto? ¡Gracias!

Respuesta

7

Se dice que el valor inicial es 0; pero se supone que es un puntero.

El contexto (lo que no significa OpenGL uno) es importante. Si se llama a una de las funciones del puntero gl * sin que el Objeto Buffer esté enlazado a GL_ARRAY_BUFFER, entonces es un puntero al espacio de direcciones del proceso del cliente. Si un Objeto de Amortiguamiento está obligado a GL_ARRAY_BUFFER es una compensación en el objeto de búfer actualmente encuadernado (puede hacer que el BO forme un espacio de dirección virtual, cuyo parámetro para gl * Puntero es entonces un puntero en ese espacio de direcciones del lado del servidor).

Ahora vamos a echar un vistazo a su código

std::vector<float>* VertArray = new std::vector<float>; 

realidad no se debe mezclar contenedores STL y new, aprender acerca del patrón RAII.

pWorld->CreateVertexArray(VertArray); 

Esto es problemático, ya que vas a eliminar VertexArray más adelante, dejándole con una referencia colgante. No está bien.

unsigned short Indice = 0; 
for (int i = 0; i < VertArray->size(); ++i) 
{ 
    std::cout << (*VertArray)[i] << std::endl; 
    glBufferSubData(GL_ARRAY_BUFFER, i * sizeof(float), sizeof(float), &((*VertArray)[i])); 

Debe enviar grandes lotes de datos con glBufferSubData, no puntos de datos individuales.

glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, i * sizeof(unsigned short), sizeof(unsigned short), &(Indice)); 

Usted está pasando simplemente índices de incremento en el GL_ELEMENT_ARRAY_BUFFER, por tanto, la enumeración de los vértices. ¿Por qué? Puede tener esto, sin el trabajo extra que utiliza glDrawArrays insteaf de glDrawElements.

++Indice; 
} 
delete VertArray; 

Está eliminando VertArray, manteniendo así un puntero colgante.

Indice -= 1; 

¿Por qué no sólo tiene que utilizar el contador del bucle i?

Entonces, ¿cómo solucionarlo? De esta manera:

std::vector<float> VertexArray; 
pWorld->LoadVertexArray(VertexArray); // World::LoadVertexArray(std::vector<float> &); 

glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*VertexArray->size(), &VertexArray[0]); 

Y usando glDrawArrays; por supuesto, si no está enumerando vértices, pero tiene una lista de caras → índices de vértices, usar glDrawElements es obligatorio.

+0

¡Gracias por la crítica y las explicaciones! Revisaré mi código, con suerte con más éxito y comprensión esta vez. – GarrickW

4

No llame al glBufferSubData para cada vértice. Pierde el punto de VBO. Se supone que debes crear un gran buffer de tus datos de vértice y luego pasarlo a OpenGL de una sola vez.

Leer http://www.opengl.org/sdk/docs/man/xhtml/glVertexPointer.xml

Al utilizar OISCIV los punteros son en relación a los datos VBO. Es por eso que generalmente es 0 o un pequeño valor de compensación.

stride = 0 significa que los datos están bien empaquetados y OpenGL puede calcular el stride desde otros parámetros.

lo general el uso VBO así:

struct Vertex 
{ 
    vec3f position; 
    vec3f normal; 
}; 

Vertex[size] data; 

... 

glBufferData(GL_ARRAY_BUFFER, size*sizeof(Vertex), data, GL_STATIC_DRAW); 

... 

glVertexPointer(3,GL_FLOAT,sizeof(Vertex),offsetof(Vertex,position)); 
glNormalPointer(3,GL_FLOAT,sizeof(Vertex),offsetof(Vertex,normal)); 

sólo tiene que pasar un solo fragmento de datos de vértices. Y luego use gl*Pointer para describir cómo se empacan los datos usando macro offsetof.

+0

Así zancada = 0 significa He empaquetado cada coordenada uno junto al otro en la misma matriz, entonces, si Lo entiendo correctamente ¿Puedo usar un std :: vector tan fácilmente como un Vertex []? – GarrickW

+0

@GarrickW usted debe ser capaz de, sí: 'std :: vector < T > a;' ' .....' ' glBufferData (GL_ARRAY_BUFFER, sizeof (T) * a.size(), & a [0 ], GL_STATIC_DRAW); ' – zeboidlund