Unable to draw using glDrawElements correctly - c++

I'm trying to draw a rectangle and apply a texture unto it. The code was copied from a book I'm reading, I just passed to C++(from Java), here it is:
void draw(){
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 4, vertices.data());//vertexSize is 4
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 2, vertices.data() + 2);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices.data());
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
}
the vertices is a std::vector of size 16 and the following values:
[-0.25,-0.25,0.0,0.25,0.25,-0.25,0.25,0.25,0.25,0.25,0.25,0.0,-0.25,0.25,0.0,0.0]
each 4 floats specifies a vertex coord and a texture coord,
and the indices is a std::vector of size 6 with the following values:
[0,1,2,2,3,0]
which specifies two triangles(with textures) in the vertices array.
This two arrays are always set before calling draw.
The problem is that the rendered object is not right, instead of a rectangle I have a trapezium rotated. The vectors seems correct, as I'm new to OpenGL, I've no idea of what is going wrong in this code.
Thank you for your attention.
---EDITED---
The opengl matrices are set right before enter the application loop:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClearColor(0.0, 1.0, 0.0, 1.0);
glEnable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
/*application loop, no more matrices use*/

glVertexPointer(2, GL_FLOAT, 4, vertices.data());//vertexSize is 4
Yes, there are 4 floats per-vertex. But that's not what the fourth parameter is. It's the number of bytes from one position to the next. That's not 4; it's 4 * sizeof(GLfloat).
Also:
glTexCoordPointer(2, GL_FLOAT, 2, vertices.data() + 2);
The second 2 here should also be 4 * sizeof(GLfloat). The byte stride for your array is the same for positions and texture coordinates.

Related

OpenGL Draw only some indexes from vertex array

how can I only draw selected indices from vertex array in OpenGL?
For instance, I am drawing my vertices like points, with some variable m_pointCloud containing my point cloud vertices (points):
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glPointSize(m_pointSize * point_scale);
glColorPointer(4, GL_UNSIGNED_BYTE,
static_cast<GLsizei>(sizeof(DensePoint)), &((*m_pointCloud)[0].r));
// glNormalPointer(GL_FLOAT,
// static_cast<GLsizei>(sizeof(DensePoint)), &((*m_pointCloud)[0].n_x));
glVertexPointer(3, GL_FLOAT,
static_cast<GLsizei>(sizeof(DensePoint)), &((*m_pointCloud)[0].x));
glDrawArrays(GL_POINTS, 0, static_cast<GLsizei>(m_pointCloud->size()) - 1);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
But I have some std::vector<size_t> indices containing the indices from m_pointCloud that I want to draw. How is this done?
Instead of glDrawArrays, use glDrawElements.
For example:
std::vector<GLuint> indices;
// populate vertices
glDrawElements(GL_POINTS, indices.size(), GL_UNSIGNED_INT, reinterpret_cast<void*>(indices.data()));
Note also that you cannot use size_t as an index type as OpenGL only allows 8, 16 and 32-bit indices.

C++/OpenGL - Drawing a cube VBO

Recently I started to learn OpenGL and I am beginning to learn the newer assets of it. For a while now I've been trying to work with VBOs, to draw a simple cube from a vertex point array. I am having trouble rendering it and understanding some of the arguments in the functions. It throws no errors but nothing is in my view.
float cubeVertPoints[72]; //An array containing the vertex points
Here is my VBO init
void loadBufferData()
{
glGenBuffers(1, &cubeVBO);
glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertPoints[0])*3, &cubeVertPoints[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(cubeVertPoints[0])*3, (void*)sizeof(GL_FLOAT));
}
Drawing
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-ratio, ratio, -1.f, 1.f, 1.f, -1.f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(cubeVertPoints[0])*3, (void*)sizeof(GL_FLOAT));
glDrawArrays(GL_TRIANGLES, 0, 1);
glDisableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
You are not transferring all your data into the vertex buffer. The 2nd parameter of glBufferData takes the size of all of your vertex data in bytes. You should set it to sizeof(vertex) * vertex_count.
Also, calling glEnableVertexAttribArray and glVertexAttribPointer in loadBufferData is redundant. You should call them only in your rendering function.
Your second problem is with glVertexAttribPointer. You are not passing the correct offset to your vertex position data in your vertex data "structure". Since your vertices only consist of positions, this offset should be 0. If you would have positions and colors for each vertex, these offset could be 0 (for position) and sizeof(float) * 3 (for color, because you have 3 coordinates).
Finally, you only draw a single vertex. You should draw 72/3=24 if your cube has 24 vertices.
I think you can make your life easier by defining an actual structure for your vertices, like so:
struct Vertex
{
float position[3];
};
Then, you can compute offsets for each of your vertex positions, colors, etc, with (GLvoid*)(&((Vertex*)NULL)->position).

A cube is rendered as a square in QGLWidget

I've been trying to render a cube in a QGLWidget, but it comes out wrong. No matter how I rotate it, it looks like a flat square. It's like it didn't notice the Z coordinates of its vertices. Just before I added clearing of the GL_DEPTH_BUFFER_BIT, the square looked like all of the cube's sides crammed into one. Now it seems to discard vertices which don't belong in the front side, but it still isn't a cube.!
Screenshots [link]
My initializeGL() and paintGL():
typedef struct
{
float XYZW[4];
float RGBA[4];
} Vertex;
Vertex Vertices[8] =
{
//vertices
};
const GLubyte Indices[36] =
{
//indices
};
void ModelView::initializeGL()
{
m_program = new QGLShaderProgram(this);
m_program->addShaderFromSourceCode(QGLShader::Vertex, vertexShaderSource);
m_program->addShaderFromSourceCode(QGLShader::Fragment, fragmentShaderSource);
m_program->link();
}
void ModelView::paintGL()
{
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glClearColor(.5f, .5f, .5f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, width(), height());
m_program->bind();
QMatrix4x4 matrix;
matrix.perspective(60, 4.0/3.0, 0.1, 100.0);
matrix.translate(0, 0, -2);
matrix.rotate(50.0, 1, 1, 1);
m_program->setUniformValue(m_matrixUniform, matrix);
m_posAttr = m_program->attributeLocation("posAttr");
m_colAttr = m_program->attributeLocation("colAttr");
m_matrixUniform = m_program->uniformLocation("matrix");
glGenBuffers(1, &BufferId);
glGenBuffers(1, &IndexBufferId);
glBindBuffer(GL_ARRAY_BUFFER, BufferId);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBufferId);
glBufferData(GL_ARRAY_BUFFER, BufferSize, Vertices, GL_STATIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW);
glVertexAttribPointer(m_posAttr, 2, GL_FLOAT, GL_FALSE, VertexSize, 0);
glVertexAttribPointer(m_colAttr, 3, GL_FLOAT, GL_FALSE, VertexSize, (GLvoid *)RgbOffset);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, NULL);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(0);
m_program->release();
}
Vertices and Indices should be defined correctly, they're taken from a tutorial, as is most of the code. Rendering of 2D object seems to be just fine, though.
Also, why does the tutorial call matrix.translate with the -2 argument? If I change it to anything else greater than 1 or remove it, the rendered object disappears.
Qt5, Windows Vista 32-bit.
Also, why does the tutorial call matrix.translate with the -2
argument? If I change it to anything else greater than 1 or remove it,
the rendered object disappears.
This is due to clipping. When you render objects, things that are "too close" or "too far" are discarded, via the near and far clipping planes (respectively).
By moving the cube closer (changing -2 to 1 or 0), you are bringing the cube forward, past the near clipping plane, and it consequently disappears.
glVertexAttribPointer() has a size parameter, which specifies the number of components per vertex. In the code it is 2, therefore everything is 2D. Changing to 3 solves the issue.

VBO: not drawing correctly. Manual drawing works

so I will need to edit this question. As stated in one of the comments, I changed to rendering method to use buffers. However, the geometry isn't being drawn correctly. If I use the same buffer and draw the vertices manually, it looks alright (without the texture though, something is messed up with it). I also tried constructing a buffer with just vertex information but that didn't help at all.
void ModelHandler::DrawModels(){
//go through each of the models
for(int i=0;i<Models3D.size();i++){
//glEnableClientState(GL_VERTEX_ARRAY);
//glVertexPointer(3, GL_FLOAT, 0, Models3D[i]->object.m_pVertice);
//now draw all the material groups with their vertices for the model
for(int j=0;j<Models3D[i]->object.mtlGroups.size();j++){
//Drawing the vertices manually from the buffer object seems to work
/*
for(int lj=0;lj<Models3D[i]->object.mtlGroups[j]->m_vecgroupVerticeIndex.size();lj++){
int mtlIndex2 = Models3D[i]->object.FindMaterial(Models3D[i]->object.mtlGroups[j]->mtlName);
bool tOn = false;
//check if there was a texture for this material
if(Models3D[i]->object.materials[mtlIndex2]->texturePresent){
glEnable(GL_TEXTURE_2D);
//glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
glBindTexture(GL_TEXTURE_2D, Models3D[i]->object.materials[mtlIndex2]->textureIDDiffuse);
tOn = true;
}
if(tOn){
glBegin (GL_QUADS);
glTexCoord2f (0.0, 0.0);
glVertex3f (0.0+5, 0.0, -2.0f);
glTexCoord2f (1.0, 0.0);
glVertex3f (1.4f+5, 0.0, -2.0f);
glTexCoord2f (1.0, 1.0);
glVertex3f (1.4f+5, -1.0, -2.0f);
glTexCoord2f (0.0, 1.0);
glVertex3f (0.0f+5, -1.0, -2.0f);
glEnd ();
}
glBegin(GL_TRIANGLES);
glColor3f(Models3D[i]->object.mtlGroups[j]->VBO[lj*3].colour[0],Models3D[i]->object.mtlGroups[j]->VBO[lj*3].colour[1],Models3D[i]->object.mtlGroups[j]->VBO[lj*3].colour[2]);
if(tOn){
glTexCoord2f (Models3D[i]->object.mtlGroups[j]->VBO[lj*3].tex[0], Models3D[i]->object.mtlGroups[j]->VBO[lj*3].tex[1]);
}
glVertex3f(Models3D[i]->object.mtlGroups[j]->VBO[lj*3].location[0], Models3D[i]->object.mtlGroups[j]->VBO[lj*3].location[1], Models3D[i]->object.mtlGroups[j]->VBO[lj*3].location[2]);
glColor3f(Models3D[i]->object.mtlGroups[j]->VBO[lj*3+1].colour[0],Models3D[i]->object.mtlGroups[j]->VBO[lj*3+1].colour[1],Models3D[i]->object.mtlGroups[j]->VBO[lj*3+1].colour[2]);
if(tOn){
glTexCoord2f (Models3D[i]->object.mtlGroups[j]->VBO[lj*3+1].tex[0], Models3D[i]->object.mtlGroups[j]->VBO[lj*3+1].tex[1]);
}
glVertex3f(Models3D[i]->object.mtlGroups[j]->VBO[lj*3+1].location[0], Models3D[i]->object.mtlGroups[j]->VBO[lj*3+1].location[1], Models3D[i]->object.mtlGroups[j]->VBO[lj*3+1].location[2]);
glColor3f(Models3D[i]->object.mtlGroups[j]->VBO[lj*3+2].colour[0],Models3D[i]->object.mtlGroups[j]->VBO[lj*3+2].colour[1],Models3D[i]->object.mtlGroups[j]->VBO[lj*3+2].colour[2]);
if(tOn){
glTexCoord2f (Models3D[i]->object.mtlGroups[j]->VBO[lj*3+2].tex[0], Models3D[i]->object.mtlGroups[j]->VBO[lj*3+2].tex[1]);
}
glVertex3f(Models3D[i]->object.mtlGroups[j]->VBO[lj*3+2].location[0], Models3D[i]->object.mtlGroups[j]->VBO[lj*3+2].location[1], Models3D[i]->object.mtlGroups[j]->VBO[lj*3+2].location[2]);
glEnd();
}
glDisable(GL_TEXTURE_2D);
*/
//####
glBindBuffer(GL_ARRAY_BUFFER, Models3D[i]->object.mtlGroups[j]->vboID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Models3D[i]->object.mtlGroups[j]->indexvboID);
/*
//this could also be used BUT if glDrawElements uses the indices (m_pgroupVerticeIndex), we will need to give the array with all the
//vertices to glVertexPointer. That array would be m_pVertice
//glVertexPointer(3, GL_FLOAT, 5, Models3D[i]->object.mtlGroups[j]->buffer);
*/
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
//Get the material that belongs to this mtlGroup
int mtlIndex = Models3D[i]->object.FindMaterial(Models3D[i]->object.mtlGroups[j]->mtlName);
//check if there was a texture for this material
if(Models3D[i]->object.materials[mtlIndex]->texturePresent){
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
glBindTexture(GL_TEXTURE_2D, Models3D[i]->object.materials[mtlIndex]->textureIDDiffuse);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(12));
//glTexCoordPointer(2, GL_FLOAT, 5, Models3D[i]->object.mtlGroups[j]->buffer);
//glTexCoordPointer(2, GL_FLOAT, 0, Models3D[i]->object.m_pTexture);
}
// Resetup our pointers. This doesn't reinitialise any data, only how we walk through it
glNormalPointer(GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(20));
glColorPointer(3, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(32));
glVertexPointer(3, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(0));
glDrawElements(GL_TRIANGLES, Models3D[i]->object.mtlGroups[j]->m_vecgroupVerticeIndex.size()*3, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));
//glDrawElements(GL_TRIANGLES, Models3D[i]->object.mtlGroups[j]->m_vecgroupVerticeIndex.size()*3, GL_UNSIGNED_INT, Models3D[i]->object.mtlGroups[j]->m_pgroupVerticeIndex);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glDisable(GL_TEXTURE_2D);
}
}
}
My buffer contains the vertices (array of Vertex structs):
struct Vertex {
GLfloat location[3];
GLfloat tex[2];
GLfloat normal[3];
GLfloat colour[3];
GLubyte padding[20]; //apparently to get 64 bytes -> improved performance
};
And here is how I initialize/generate buffers for each of the materials:
//This function was implemented based on the tutorial shown at
//http://sdickinson.com/wordpress/?p=122
void CObjLoader::GenerateVBO(){
for(int mj=0;mj<mtlGroups.size();mj++){
glGenBuffers(1, &mtlGroups[mj]->vboID);
//printf("bufferID: %d", mtlGroups[mj]->vboID);
glBindBuffer(GL_ARRAY_BUFFER, mtlGroups[mj]->vboID); // Bind the buffer (vertex array data)
// Allocate space. We could pass the mesh in here (where the NULL is), but it's actually faster to do it as a
// seperate step. We also define it as GL_STATIC_DRAW which means we set the data once, and never
// update it. This is not a strict rule code wise, but gives hints to the driver as to where to store the data
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * mtlGroups[mj]->m_vecgroupVerticeIndex.size()*3, NULL, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vertex) * mtlGroups[mj]->m_vecgroupVerticeIndex.size()*3, mtlGroups[mj]->VBO); // Actually upload the data
// Set the pointers to our data. Except for the normal value (which always has a size of 3), we must pass
// the size of the individual component. ie. A vertex has 3 points (x, y, z), texture coordinates have 2 (u, v) etc.
// Basically the arguments are (ignore the first one for the normal pointer), Size (many components to
// read), Type (what data type is it), Stride (how far to move forward - in bytes - per vertex) and Offset
// (where in the buffer to start reading the data - in bytes)
// Make sure you put glVertexPointer at the end as there is a lot of work that goes on behind the scenes
// with it, and if it's set at the start, it has to do all that work for each gl*Pointer call, rather than once at
// the end.
glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(12));
glNormalPointer(GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(20));
glColorPointer(3, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(32));
glVertexPointer(3, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(0));
// When we get here, all the vertex data is effectively on the card
// Our Index Buffer, same as above, the variable needs to be accessible wherever we draw
glGenBuffers(1, &mtlGroups[mj]->indexvboID); // Generate buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mtlGroups[mj]->indexvboID); // Bind the element array buffer
// Upload the index array, this can be done the same way as above (with NULL as the data, then a
// glBufferSubData call, but doing it all at once for convenience)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mtlGroups[mj]->m_vecgroupVerticeIndex.size()*3*sizeof(GLubyte), mtlGroups[mj]->index, GL_STATIC_DRAW);
}
}
For the sake of simplicity, my index array looks like this: 0, 1, 2, 3, 4, 5, .... This means that my buffer contains some of the vertices twice. VBO and index have therefore the same length.
Maybe I am messing something up with the initialization?
So the error was the following (I will just copy my previous comments explaining the solution):
Ok, I've found the error. Apparently, I was using GLubyte for the indices and in my case, I have way more than 255 vertices. Changing to GLuint has resolved the issue. However, my texture still isn't drawn correctly onto the object. The object stays grey. But colors seem to work.
The .obj loader is yielding better results now and is ok with simpler models. I will do some further testing and in case of trouble, I will be back.

How do you handle multiple textures in an OpenGL indexed buffer array for use with a data-shader?

I'm attempting to implement this paper. I've have most of it down, but the part about sending arbitrary, non-geometric data to the shader for use in determining and displaying geometric edges is causing me problems. I've managed to successfully send most of my data just fine using what I know of VBOs. However, I need to send a large amount of data, which necessitates the use of multiple texture coordinates.
I've already implemented several variations of what I believe to be the correct way of setting up multiple sets of texture coordinates, and followed the instructions of many forum posters. No solutions work thus far.
For context, the program is sending 4 nearly identical copies of a set of 4 vertices, 2 normal vectors, a float, and an integer (stored as a float) for each unique edge in the model. I've laid out the data like this:
v0 is stored in gl_Vertex (vec3)
v1 is stored in gl_Color (vec3)
v2 is stored in gl_MultiTexCoord0 (vec3)
v3 is stored in gl_MultiTexCoord1 (vec3)
n0 is stored in gl_Normal (vec3)
n1 is stored in gl_SecondaryColor (vec3)
r and i are stored in gl_MultiTexCoord2 (vec2)
The only difference between the 4 copies is the i value, which helps determine how to organize the vertices if and when a drawable edge is found.
As you can see, I need at least 3 texture coordinates. I was able to get the first one working (gl_MultiTexCoord0) just fine, but any following texture coordinates, though on the graphics card, appear to have uncontrollable behavior, sometimes working, but usually not.
My rendering function used to look like this:
void Mesh::RenderLineEdgesGPU()
{
// Enable client state
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_SECONDARY_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// Turn on edge shader
edgeProgram.Activate();
// Link buffers
// v0
glBindBufferARB(GL_ARRAY_BUFFER_ARB, edgeMeshHandles[0]);
glVertexPointer(3, GL_FLOAT, 0, 0);
// v1
glBindBufferARB(GL_ARRAY_BUFFER_ARB, edgeMeshHandles[1]);
glColorPointer(3, GL_FLOAT, 0, 0);
// v2
glClientActiveTextureARB(GL_TEXTURE0_ARB);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, edgeMeshHandles[2]);
glTexCoordPointer(3, GL_FLOAT, 0, 0);
// v3
glClientActiveTextureARB(GL_TEXTURE1_ARB);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, edgeMeshHandles[3]);
glTexCoordPointer(3, GL_FLOAT, 0, 0);
// n0
glBindBufferARB(GL_ARRAY_BUFFER_ARB, edgeMeshHandles[4]);
glNormalPointer(GL_FLOAT, 0, 0);
// n1
glBindBufferARB(GL_ARRAY_BUFFER_ARB, edgeMeshHandles[5]);
glSecondaryColorPointer(3, GL_FLOAT, 0, 0);
// r and i
glClientActiveTextureARB(GL_TEXTURE2_ARB);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, edgeMeshHandles[6]);
glTexCoordPointer(2, GL_FLOAT, 0, 0);
// Indicies
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, edgeMeshHandles[7]);
// Draw
glDrawElements(GL_POINTS, EdgeVertexQuantity, GL_UNSIGNED_INT, 0);
// Turn off edge shader
edgeProgram.Deactivate();
// Disable client state
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_SECONDARY_COLOR_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
This was my original one. It definitely works for v0, v1, and v2. It appears to work for "r and i", but that could be an illusion. I don't have the ability to test n0 or n1 yet. v3 definitely DOES NOT work. As you can see, I'm drawing them as points, which tells me if they are there or not (via the shader). v0, v1, and v2 are all there. Attempting to do the same for v3 yields either a single point at the origin or nothing at all.
After looking at suggestions online, here's my new setup:
void Mesh::RenderLineEdgesGPU()
{
// Enable client state
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_SECONDARY_COLOR_ARRAY);
// Turn on edge shader
edgeProgram.Activate();
// Link buffers
// v0
glBindBufferARB(GL_ARRAY_BUFFER_ARB, edgeMeshHandles[0]);
glVertexPointer(3, GL_FLOAT, 0, 0);
// v1
glBindBufferARB(GL_ARRAY_BUFFER_ARB, edgeMeshHandles[1]);
glColorPointer(3, GL_FLOAT, 0, 0);
// v2
glClientActiveTextureARB(GL_TEXTURE0_ARB);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glActiveTextureARB(GL_TEXTURE0_ARB);
glEnable(GL_TEXTURE_2D);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, edgeMeshHandles[2]);
glTexCoordPointer(3, GL_FLOAT, 0, 0);
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
// v3
glClientActiveTextureARB(GL_TEXTURE1_ARB);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glActiveTextureARB(GL_TEXTURE1_ARB);
glEnable(GL_TEXTURE_2D);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, edgeMeshHandles[3]);
glTexCoordPointer(3, GL_FLOAT, 0, 0);
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
// n0
glBindBufferARB(GL_ARRAY_BUFFER_ARB, edgeMeshHandles[4]);
glNormalPointer(GL_FLOAT, 0, 0);
// n1
glBindBufferARB(GL_ARRAY_BUFFER_ARB, edgeMeshHandles[5]);
glSecondaryColorPointer(3, GL_FLOAT, 0, 0);
// r and i
glClientActiveTextureARB(GL_TEXTURE2_ARB);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, edgeMeshHandles[6]);
glTexCoordPointer(2, GL_FLOAT, 0, 0);
// Indicies
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, edgeMeshHandles[7]);
// Draw
glDrawElements(GL_POINTS, EdgeVertexQuantity, GL_UNSIGNED_INT, 0);
// Turn off edge shader
edgeProgram.Deactivate();
// Disable client state
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_SECONDARY_COLOR_ARRAY);
}
Notice how I've done the glEnableClientState / glDisableClientState calls around the actual "loading" of each texture coordinate list. I also use glActiveTextureARB and glEnable(GL_TEXTURE_2D). While I think I might understand why glActiveTextureARB is needed here, the other one baffles me. According to the GLSL Common Mistakes page, you're not supposed to use glEnable(GL_TEXTURE_2D) when you make your own shaders, since the use of shaders ignores this call anyway.
So that's it. I've gotten this far without being able to find any tutorials specifically addressing how to send non-texture coordinate data in texture coordinates. Perhaps if someone knows a tutorial on that, my problem would be alleviated. Thanks for your time!
glClientActiveTextureARB changes which specific texture coordinate unit following calls to glEnableClientState(GL_TEX_COORD_ARRAY) and glTexCoordPointer will alter.
glActiveTextureARB affects glEnable(GL_TEXTURE_2D), which, as you mentioned, you don't need for shaders.
If you look at your code closely, picking only those 5 calls (and their equivalent Disable), here is what you have:
glClientActiveTextureARB(GL_TEXTURE0_ARB);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glActiveTextureARB(GL_TEXTURE0_ARB);
glEnable(GL_TEXTURE_2D);
glTexCoordPointer(3, GL_FLOAT, 0, 0);
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTextureARB(GL_TEXTURE1_ARB);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glActiveTextureARB(GL_TEXTURE1_ARB);
glEnable(GL_TEXTURE_2D);
glTexCoordPointer(3, GL_FLOAT, 0, 0);
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTextureARB(GL_TEXTURE2_ARB);
glTexCoordPointer(2, GL_FLOAT, 0, 0);
glDrawElements(GL_POINTS, EdgeVertexQuantity, GL_UNSIGNED_INT, 0);
Ok, we already said that glActiveTextureARB and glEnable are not useful (by the way, you enable/disable GL_TEXTURE_2D without any draw in between, that's not useful), so remove them:
glClientActiveTextureARB(GL_TEXTURE0_ARB);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(3, GL_FLOAT, 0, 0);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTextureARB(GL_TEXTURE1_ARB);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(3, GL_FLOAT, 0, 0);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTextureARB(GL_TEXTURE2_ARB);
glTexCoordPointer(2, GL_FLOAT, 0, 0);
glDrawElements(GL_POINTS, EdgeVertexQuantity, GL_UNSIGNED_INT, 0);
What stands out now ? 2 issues:
You Disable your client state before ever executing Draw
You don't set the Enable bit for TEXTURE2
What should you write ? Something along those lines: (Beware, you'll need to add the BindBuffer calls back to each Pointer call):
// texture coord 0
glClientActiveTextureARB(GL_TEXTURE0_ARB); // program texcoord unit 0
glEnableClientState(GL_TEXTURE_COORD_ARRAY); // enable array data to shader
glTexCoordPointer(3, GL_FLOAT, 0, 0); // say what data
// texture coord 1
glClientActiveTextureARB(GL_TEXTURE1_ARB);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(3, GL_FLOAT, 0, 0);
// texture coord 2
glClientActiveTextureARB(GL_TEXTURE2_ARB);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, 0);
glDrawElements(GL_POINTS, EdgeVertexQuantity, GL_UNSIGNED_INT, 0);
// done with those texcoord units, turn them off
glClientActiveTextureARB(GL_TEXTURE0_ARB);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTextureARB(GL_TEXTURE1_ARB);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTextureARB(GL_TEXTURE2_ARB);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
Some more comments on BindBuffer: glBindBufferARB(GL_ARRAY_BUFFER_ARB,...) does not get affected by the glClientActiveTextureARB, but it does affect the next glTexCoordPointer call. In essence, think of glClientActiveTextureARB and glBindBufferARB as providing extra arguments to glTexCoordPointer.
Last thing, you probably want to group some of those VBOs in less buffers. Something for another question maybe ? (Hint, the 2 arguments to glTexCoordPointer don't have to be 0)