Rendering mesh polygons in OpenGL - very slow - c++

I recently switched from intermediate mode and have a new rendering process. There must be something I am not understanding. I think it has something to do with the indices.
Here is my diagram: Region->Mesh->Polygon Array->3 vertex indices which references the master list of vertices.
Here my render code:
// Render the mesh
void WLD::render(GLuint* textures, long curRegion, CFrustum cfrustum)
{
int num = 0;
// Set up rendering states
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// Set up my indices
GLuint indices[3];
// Cycle through the PVS
while(num < regions[curRegion].visibility.size())
{
int i = regions[curRegion].visibility[num];
// Make sure the region is not "dead"
if(!regions[i].dead && regions[i].meshptr != NULL)
{
// Check to see if the mesh is in the frustum
if(cfrustum.BoxInFrustum(regions[i].meshptr->min[0], regions[i].meshptr->min[2], regions[i].meshptr->min[1], regions[i].meshptr->max[0], regions[i].meshptr->max[2], regions[i].meshptr->max[1]))
{
// Cycle through every polygon in the mesh and render it
for(int j = 0; j < regions[i].meshptr->polygonCount; j++)
{
// Assign the index for the polygon to the index in the huge vertex array
// This I think, is redundant
indices[0] = regions[i].meshptr->poly[j].vertIndex[0];
indices[1] = regions[i].meshptr->poly[j].vertIndex[1];
indices[2] = regions[i].meshptr->poly[j].vertIndex[2];
// Enable texturing and bind the appropriate texture
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textures[regions[i].meshptr->poly[j].tex]);
glVertexPointer(3, GL_FLOAT, sizeof(Vertex), &vertices[0].x);
glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), &vertices[0].u);
// Draw
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, indices);
}
}
}
num++;
}
// End of rendering - disable states
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
Sorry if I left anything out. And I really appreciate feedback and help with this. I would even consider paying someone who is good with OpenGL and optimization to help me with this.

There is no point in using array rendering if you're only rendering 3 vertices at a time. The idea is to send thousands through with a single call. That is, you render a single "Polygon Array" or "Mesh" with one call.

Related

C++ Vertex Buffer Issue

I'm attempting to add a vertex buffer to the Mesh.cpp file of the pixel city procedural city-generating program. Part of the current code looks like this:
for (qsi = _quad_strip.begin(); qsi < _quad_strip.end(); ++qsi) {
glBegin (GL_QUAD_STRIP);
for (n = qsi->index_list.begin(); n < qsi->index_list.end(); ++n) {
glTexCoord2fv (&_vertex[*n].uv.x);
glVertex3fv (&_vertex[*n].position.x);
}
glEnd ();
}
This draws textures onto the rectangular sides of some of the buildings. Just going off the VBO tutorials I've found online, I attempt to convert this to use a vertex buffer like so (I store vboId in Mesh.h):
for (qsi = _quad_strip.begin(); qsi < _quad_strip.end(); ++qsi) {
void * varray = (char *) malloc(sizeof(GLfloat)*5*qsi->index_list.size());
GLfloat *p = (GLfloat*)varray;
int counter = 0;
for (n = qsi->index_list.begin(); n < qsi->index_list.end(); ++n) {
memcpy(&p[counter+0],&_vertex[*n].uv.x, sizeof(GLfloat)*2);
memcpy(&p[counter+2],&_vertex[*n].position.x, sizeof(GLfloat)*3);
counter+=5;
}
glGenBuffersARB(1, &vboId);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vboId);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(GLfloat)*5*qsi->index_list.size(), p, GL_STATIC_DRAW_ARB);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glTexCoordPointer(2, GL_FLOAT, sizeof(GLfloat)*5, (GLfloat*)0);
glVertexPointer(3, GL_FLOAT, sizeof(GLfloat)*5, (GLfloat*)2);
glDrawArrays(GL_QUAD_STRIP, 0, qsi->index_list.size());
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
free(varray);
}
However, this code simply doesn't work. Nothing is rendered. Sometimes, when I mess with the parameters into glTexCoordPointer or glVertexPointer, I really skewed/garbage data drawn on the screen (or the program crashes), but nothing that has even come close to remotely working.
Your vertex pointer is wrong. When using VBOs, the pointer is interpreted as the byte offset relative to the currently bound buffer. So, you need sizeof(GLfloat)*2 bytes as offset.
glVertexPointer(3, GL_FLOAT, sizeof(GLfloat)*5, (char*)0 +sizeof(GLfloat)*2);
As a side note: you could save the additional data copy if you would create the VBO with the correct size but NULL as the data pointer (which basically creates the data storage) and memory-map it with glMapBuffer(), completely avoivding the malloc()ed temporary buffer you use.

glDrawArrays doesn't draw

I use vectors to store vertex and normal data
vector<float> vertex;
vector<float> normal;
For example:
normal.push_back(-1);
normal.push_back(0);
normal.push_back(0);
vertex.push_back(BARRIER_RADIUS);
vertex.push_back(POLE_HEIGHT);
vertex.push_back(-POLE_RADIUS);
for (int i = POLE_POINTS, i >= 0; i--)
{
//add more vertex
}
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, &vertex[0]);
glNormalPointer(GL_FLOAT, 0, &normal[0]);
glDrawArrays(GL_TRIANGLE_FAN, 0, vertex.size());
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
//Add some more + Draw some thing else the same way
What I've got from this is nothing. it doesn't draw anything onto the screen.
The previous version, which works, is as follow:
glNormal3f(-1, 0, 0);
glBegin(GL_TRIANGLE_FAN);
glVertex3f(BARRIER_RADIUS, POLE_HEIGHT, -POLE_RADIUS);
for ()
{
//add more vertex
glVertex3f(........);
}
glEnd();
//draw more the same way
Point me to where I've gone wrong.
You have defined vertex as a vector of float, but a geometric vertex consists of 3 floats, so that's a recipe for confusion. The number of vertices is not vertex.size(), but rather one third of that. I'm not sure if that's your only problem, but it's a problem.
You should have the same number of normals as vertices.

Vertex buffers and rendering problems

I am trying to approximate a curved surface using quadrilateral patches. I did it using straight forward rendering using GL_QUADS and specifying the four vertices of the quad patch.
Now I am trying to get some performance using vertex buffers and overlayed array (verNor) of vertices and normals. The problem is that I get some random shapes but not the correct shape I got previously.
Here I am putting my code:
GLenum err = glewInit();
if (GLEW_OK != err){
std::cout<<"Filed to Initialize GLEW :: "<<glewGetErrorString(err)<<std::endl;
}
verNor = new GLfloat [NA*NP*6]; // NA and NP are number of points in lets say x and y axis
indices = new GLuint [(NA)*(NP)*4]; // When the tube is cut an spread out.
// VBOs
glGenBuffers(1, &vbo_tube); // Ask the GPU driver for a buffer array. "vbo" now has the ID
glGenBuffers(1, &ibo_indices);
// For Vertices and Normals which are interleved
glBindBuffer(GL_ARRAY_BUFFER, vbo_tube);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 6*NA*NP, NULL, GL_STATIC_DRAW);
// Obtaining the pointer to the memory in graphics buffer
buffer_verNor = glMapBuffer(GL_ARRAY_BUFFER,GL_WRITE_ONLY);
// For Indices
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_indices);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int) * 4*(NA-1)*(NP-1), NULL, GL_STATIC_DRAW);
buffer_indices = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER,GL_WRITE_ONLY);
// Calculate the vertices of the points around the tube. Correctness guarenteed because I can draw exactly what I wanted
// using normal stright forward GL_QUADS that is drawing quad by quad and with out any VBOs
// Calculated vertices are stored in vPoints.
for (int i=0; i<NP; i++) {
for (int j=0; j<NA; j++) {
// Calculate the normals of each and every point above and store them in v3
// Storing the vertices
verNor[6*( (i)*NA+(j) )+0] = (GLfloat)vPoints[i*NA+j].GetX();
verNor[6*( (i)*NA+(j) )+1] = (GLfloat)vPoints[i*NA+j].GetY();
verNor[6*( (i)*NA+(j) )+2] = (GLfloat)vPoints[i*NA+j].GetZ();
// Storing the Normals
verNor[6*((i-1)*NA+(j-1))+3] = (GLfloat)v3.GetX();
verNor[6*((i-1)*NA+(j-1))+4] = (GLfloat)v3.GetY();
verNor[6*((i-1)*NA+(j-1))+5] = (GLfloat)v3.GetZ();
// Calculating the indices which form the quad
indices[4*((i)*NA+(j))+0] = (GLuint) (i)*NA+j ;
indices[4*((i)*NA+(j))+1] = (GLuint) (i+1)*NA+j ;
indices[4*((i)*NA+(j))+2] = (GLuint) (i+1)*NA+j+1 ;
indices[4*((i)*NA+(j))+3] = (GLuint) (i)*NA+j+1 ;
}
}
memcpy(buffer_verNor, verNor, 6*(NA)*(NP));
glUnmapBuffer(GL_ARRAY_BUFFER); // Unmapping the buffer
memcpy(buffer_indices, indices, 4*(NA-1)*(NP-1));
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
glEnable(GL_LIGHTING);
// Performing the Vertex Buffer Stuff
// For Vertices and Normals
glBindBuffer(GL_ARRAY_BUFFER, vbo_tube);
glVertexPointer( 3, GL_FLOAT, 6*sizeof(GLfloat), (GLvoid*)((char*)NULL + 0*sizeof(GLfloat)) );
glNormalPointer( GL_FLOAT, 6*sizeof(GLfloat), (GLvoid*)(((char*)NULL)+3*sizeof(GLfloat)) );
// For Indices
// Mapping the indices_vbo memory here
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_indices);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)*4*(NA-1)*(NP-1), indices, GL_STATIC_DRAW);
// Enabling all the buffers and drawing the quad patches
glBindBuffer(GL_ARRAY_BUFFER, vbo_tube);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_indices);
// Enabling normals and vertices to draw
glEnableClientState (GL_NORMAL_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
// Drawing the patches
glDrawElements(GL_QUADS, (NA-1)*(NP-1), GL_UNSIGNED_INT,(GLvoid*)((char*)NULL));
// Disabling the buffer objects for safety
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glDeleteBuffers(1, &vbo_tube);
glDeleteBuffers(1, &ibo_indices);
The gird has NA by NP points so I have to draw (NP-1)*(NA-1) quads.
Also I can only get some thing(but not correct) drawn only when I give wrong offsets and stride in glVertexPointer() and glNormalPointer() function. Correct ones i think are
vertexPointer :: Stride - 6*sizeof(GLfloat) , offset - 0(last argument)
normalPointer :: Stride - 6*sizeof(GLfloat) , offset - 3*sizeof(GLfloat)

Using C++ std::Vector in glVertexPointer OpenGL function

I have a vector of floats, this vector describes a set of triangles each triangle is described using 18 floats, first 3 are the first vertex, next 3 decribes the normal of the last vertex, and so on 3 times until describe each triangle.
i am using
std::vector< GLfloat >
to store all numbers, and this is my code to render the triangles
void Visualizer::draw3dModel()
{
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glNormalPointer(GL_FLOAT, 6 * sizeof(GLfloat), this->vertexes->data() + 3);
glVertexPointer(3, GL_FLOAT, 6 * sizeof(GLfloat), this->vertexes->data());
glPushMatrix();
glScalef(0.05f, 0.05f, 0.05f);
glColor3f(1,1,1);
glDrawArrays(GL_TRIANGLES, 0, this->vertexes->size());
glPopMatrix();
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
}
this code actually works, but in certain moments I recreate the vector of floats with new triangles, it can be more or less triangles
before creating new triangles I clear the vector of vertexes, using this functions
std::vector< GLfloat >* MarchingCubesThread::getTriangles(float minvalue_scale)
{
this->generateTriangles(minvalue_scale);
for(unsigned int i=0; i < this->num_triangles; i++)
{
for(int j=0; j < 3; j++)
{
this->vertexes.push_back(this->triangles[i].p[j].x);
this->vertexes.push_back(this->triangles[i].p[j].y);
this->vertexes.push_back(this->triangles[i].p[j].z);
this->vertexes.push_back(this->triangles[i].norm.x);
this->vertexes.push_back(this->triangles[i].norm.y);
this->vertexes.push_back(this->triangles[i].norm.z);
}
}
return &(this->vertexes);
}
void MarchingCubesThread::generateTriangles(float minvalue_scale)
{
this->vertexes.clear();
this->triangles.clear();
this->triangles = MarchingCubesDataset(this->dataset->getMaxVal() * minvalue_scale, *(this->dataset), LinearInterp, this->num_triangles);
}
After playing around creating a new set of new triangles, the OpenGL render updates the mesh well, but in certain moments, I get some garbage triangles, and/or triangles that are from last iteration, and they should be cleared by calling this:
this->vertexes.clear();
this->triangles.clear();
here some screenshots taken in consecutive times:
any clues about what is happening here?, thank you
PD: for a complete source code, this is the public git repository on github:
https://github.com/joecabezas/MemoriaJoeCabezasCode/tree/visualizer
glDrawArrays expects not count of floats in your buffer, but count of vertices.
So correct call should be:
glDrawArrays(GL_TRIANGLES, 0, this->vertexes->size() / 6);
By letting glDrawArrays to draw 6 times more vertices you were displaying garbage after end of valid vector data, and sometimes it was data from previous iteration.

Texturing VBOs (Vertex Buffer Objects)

I'm currently working on a procedural planet generation tool that works by taking a cube, mapping it to a sphere and then applying a heightmap to each face to generate terrain.
I'm using a VBO for each face which is created using the following method:
void Planet::setVertexBufferObject()
{
Vertex* vertices;
int currentVertex;
Vertex* vertex;
for(int i = 0; i < 6; i++)
{
// bottom face
if(i == 0)
{
glBindBuffer(GL_ARRAY_BUFFER, bottomVBO);
}
// top face
else if(i == 1)
{
glBindBuffer(GL_ARRAY_BUFFER, topVBO);
}
// front face
else if(i == 2)
{
glBindBuffer(GL_ARRAY_BUFFER, frontVBO);
}
// back face
else if(i == 3)
{
glBindBuffer(GL_ARRAY_BUFFER, backVBO);
}
// left face
else if(i == 4)
{
glBindBuffer(GL_ARRAY_BUFFER, leftVBO);
}
// right face
else
{
glBindBuffer(GL_ARRAY_BUFFER, rightVBO);
}
vertices = (Vertex*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
currentVertex = 0;
for(int x = 0; x < size; x++)
{
for(int z = 0; z < size; z++)
{
currentVertex = z * size + x;
vertex = &vertices[currentVertex];
vertex->xTextureCoord = (x * 1.0f) / 512.0f;
vertex->zTextureCoord = (z * 1.0f) / 512.0f;
Vector3 normal;
vertex->xNormal = normal.x;
vertex->yNormal = normal.y;
vertex->zNormal = normal.z;
vertex->x = heightMapCubeFace[i][x][z][0];
vertex->y = heightMapCubeFace[i][x][z][1];
vertex->z = heightMapCubeFace[i][x][z][2];
vertex->x *= (1.0f +((heightMaps[i][z][x]/256.0f) * 0.1));
vertex->y *= (1.0f +((heightMaps[i][z][x]/256.0f) * 0.1));
vertex->z *= (1.0f +((heightMaps[i][z][x]/256.0f) * 0.1));
}
}
glUnmapBuffer(GL_ARRAY_BUFFER);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
}
I have left out the setIndexBufferObject() method as that is working OK.
I am then rendering the sphere using this method:
void Planet::render()
{
// bottom face
glBindBuffer(GL_ARRAY_BUFFER, bottomVBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bottomIBO);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(6 * sizeof(float)));
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(3 * sizeof(float)));
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(0));
TextureManager::Inst()->BindTexture(textueIDs[0]);
glClientActiveTexture(GL_TEXTURE0+textueIDs[0]);
glDrawElements(GL_TRIANGLE_STRIP, numberOfIndices, GL_UNSIGNED_INT, BUFFER_OFFSET(0));
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// next face and so on...
The textures are being loaded in using free image, as you can see from the above code I am just using the example texture manager that came with freeimage.
Why is binding the texture not working?
Why is binding the texture not working?
Describing very specifically the behavior you're seeing, or better attaching a URL to a screenshot, goes a long way when trying to get through graphics questions.
Next, you need to include the gl error state or at least demonstrate that within the code that you're checking and failing if glGetError() doesn't return GL_NO_ERROR.
Your VBO / draw element state looks reasonable though you've deliberately omitted the definition of the index buffer object so we'll take it on faith that you're sending real indices into your glDrawElements() call. For a sanity check, do the glDrawElements() call with the raw indices pointer rather than binding a VBO for the elements.
You've also omitted the type definition of Vertex which is required to know if the offsets you're supplying to glTexCoordPointer() are consistent with the struct definition.
Lastly, I'm guessing most people on the forum don't know "free image" which I believe is what you've stated you're using to load textures with. If there's a texturing problem it's impossible to see because of the opaque nature of using this 3rd party library to set up texturing on your behalf.
If they've confused texture IDs, set up a wrap mode that isn't supported, not set the minification filter consistent with the expected mipmapping (on/off), not enabled texturing, or set the texture environment mode such that the modulation with the base geometry color is not as you expect - all of these would make texturing not work / appear to be working.
To troubleshoot just use the library for texture load and use the texture ID they provide. Then set up the filter modes and texture environment yourself. Turn off mipmapping while troubleshooting. Incomplete mipmap chains is a very common error when texturing.
You can also turn off per-fragment operations to simplify your troubleshooting. Disable blending, depth testing, and scissoring.
Assuming your texture is power of two dimensions or your implementation supports NPOT, try these settings immediately before drawing:
glDisable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
glDisable(GL_SCISSOR_TEST);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glBindTexture(GL_TEXTURE_2D, texID);
glTexEnvi(GL_TEXTURE_ENV_MODE, GL_REPLACE); // turn off modulation
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // turn off mipmapping
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); // turn off repeats
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glClientActiveTexture(GL_TEXTURE0+textueIDs[0]);
What are you trying to do here?
The active texture unit has nothing to do with a random texture object.