Simple question:
How does this piece of code
glBindTexture(GL_TEXTURE_2D, texture_);
glColor4f(1,1,1,1);
glBegin(GL_QUADS);
glTexCoord2f(0, 1); glVertex2f(left_, top_);
glTexCoord2f(1, 1); glVertex2f(right_, top_);
glTexCoord2f(1, 0); glVertex2f(right_, bottom_);
glTexCoord2f(0, 0); glVertex2f(left_, bottom_);
glEnd();
translate to modern OpenGL code with vertex arrays?
If you just want to port these lines to vertex arrays, it is as simple as:
static const float texCoords[8] = {
0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f };
float vertices[8] = {
left_, top_, right_, top_, right_, bottom_, left_, bottom_ };
glBindTexture(GL_TEXTURE_2D, texture_);
glColor4f(1,1,1,1);
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, vertices);
glEnableClientState(GL_VERTEX_ARRAY);
glDrawArrays(GL_QUADS, 0, 4);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableCLientState(GL_VERTEX_ARRAY);
However, this has nothing to do with modern OpenGL, in fact this code is completely valid OpenGL 1.1 code. Modern OpenGL is not just about vertex arrays over immediate mode. It is also about storing vertex data in vertex buffer objects (VBOs) and doing every computation (like transformation, lighting, texturing, ...) with shaders instead of the old fixed-function pipeline. So really porting this to modern OpenGL is in fact not such a simple question.
Since your question suggests that you aren't aware of all this, it doesn't make much sense to explain it here, as it doesn't just come down to 5-10 lines of code that you only need to subsitute for the lines in the question. You should rather consult some serious learning resource on modern OpenGL if that is what you want to do.
If all you want to do is indeed to use vertex arrays instead of immediate mode, then the above code should be sufficient, though it won't really buy you anything in this example, I guess.
BindTexture wll stay... but the rest.
1 in init method create VBO for vertices. Those vertices should be:
float verts[4*(2+3)] = { 0, 1, left_, top_, 0,
1, 1, right_, top_, 0,
1, 0, right_, bottom_, 0,
0, 1, left_, bottom_, 0 };
2 copy verts to GPU (glBufferData)
3 use glVertexAttribPointer to set up buffer data with attribs
4 draw arrays
for instance
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, bufID);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float)*5, sizeof(float)*2);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float)*5, 0);
glDrawArrays with Triangle_strip
Related
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.
I've been having a problem recently when getting to grips with Opengl VAOs.
Currently I have code which draws a triangle from a array of floats using a VBO.
Here is the code.
float vpp[] = { 0.75f, 0.75f, 0.0f,
0.75f, -0.75f, 0.0f,
-0.75f, -0.75f, 0.0f};
// Non Indexed
glGenBuffers(1, &m_mainVertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, m_mainVertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vpp), vpp, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays(GL_POINTS, 0, 3);
glDisableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
Now when I try to implement a VAO, the program only draws out 1 point. (I would post a screen cap but I can't).
And the code for this one.
float vp[] = { 0.0f, 0.75f, -0.75f };
//VAO
unsigned short sInds[9] = { 1, 1, 0,
1, 2, 0,
2, 2, 0};
//Indexed
glGenBuffers(1, &m_mainVertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, m_mainVertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vp), vp, GL_STATIC_DRAW);
GLuint elBuf;
glGenBuffers(1, &elBuf);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elBuf);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 9 * sizeof(unsigned short), sInds, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glDrawElements(GL_POINTS, 3, GL_UNSIGNED_SHORT, sInds);
glDisableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
Can anyone show me what I'm doing wrong?
Your code is broken, and that has nothing to do with your "VAO" (or as Datenwolf pointed out, your lack of a VAO).
You don't seem to understand what the index in the index buffer actually does. You defined attribute 0 to be an array of 3 floating-point values. In C terms, you said, float attrib0[numberOfPositions][3];. When OpenGL sees the first index, it will fetch three values from the array. It will fetch:
attrib0[index][0];
attrib0index;
attrib0[index][2];
Your index is a vertex index, not a GL_FLOAT index. The array elements are 3 floats each, not 1 float each.
What you're trying to do is not really possible or useful. And as Datenwolf pointed out, it has nothing to do with VAOs (since your code doesn't use them). You're talking about indexed rendering, which is a different topic from VAOs.
Which OpenGL version do you use? So far your code uses only Vertex Buffer Objects, but there's no Vertex Array Object support code there, yet. If you're on OpenGL-4 core, you need to create a VAO first, otherwise nothing will draw.
If you don't plan on using VAO abstraction, you can create a catch-all VAO right after creation of the context.
GLuint vaoID;
glGenVertexArrays(1, &vaoID);
glBindVertexArray(vaoID);
Update:
I didn't it notice yesterday night, but Nicol Bolas did. Some part of your second code snippet doesn't make sense. vp defines only 3 floats. It now completely depends on the semantics of the vertex shader (using generic vertex attributes mandates the use of shaders) how these are to be interpreted. Your call of glVertexAttribPointer with a element size of 3 tells OpenGL, that each element of that vertex attribute has 3 fields, which are addressed together.
float vp[] = { 0.0f, 0.75f, -0.75f };
\------------------/ one attribute element
It would make more sense with your first definition vpp
float vpp[] = { 0.75f, 0.75f, 0.0f,
\----------------/ attribute element 0
0.75f, -0.75f, 0.0f,
\-----------------/ attribute element 1
-0.75f, -0.75f, 0.0f};
\------------------/ attribute element 2
If you enable several vertex attributes, they together form a long vector of several attributes.
The indices supplied to glDrawElements address such vertex attribute vectors, not their individual fields.
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.
I know, it's quite frustrating. I can't get anything to show up in my OpenGL application - all I see is an empty viewport.
When I first started writing the application, I was manually drawing the vertices (using GL_QUADS) and everything worked fine. Then I decided to switch to VBOs (Vertex Buffer Objects). Now nothing works.
Here is the structure for vertices:
struct SimpleVertex
{
GLfloat x, y;
GLbyte r, g, b, a;
};
As you can see, it is very simple - x and y coords for the vertices and RGBA color data. Here is the code that fills the vertex and index buffer:
const SimpleVertex rect_vertices[] = {
{ -0.8, 0.8, 0, 255, 0, 128 },
{ 0.8, 0.8, 0, 255, 0, 128 },
{ 0.8, -0.8, 0, 255, 0, 128 },
{ -0.8, -0.8, 0, 255, 0, 128 }
};
const GLuint rect_indices[] = {
0, 1, 2, 3
};
GLuint vertices;
GLuint indices;
glGenBuffers(1, &vertices);
glBindBuffer(GL_ARRAY_BUFFER, vertices);
glBufferData(GL_ARRAY_BUFFER,
sizeof(rect_vertices),
rect_vertices,
GL_STATIC_DRAW);
glGenBuffers(1, &indices);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
sizeof(rect_indices),
rect_indices,
GL_STATIC_DRAW);
And last but certainly not least, here is the code that is supposed to draw the rectangle:
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBindBuffer(GL_ARRAY_BUFFER, vertices);
glVertexPointer(2, GL_FLOAT, 0, NULL);
glColorPointer(4, GL_BYTE, 0,
(const GLvoid *)(sizeof(GLfloat) * 2));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices);
glDrawElements(GL_QUADS, 4, GL_UNSIGNED_INT, NULL);
glDisable(GL_BLEND);
I can't figure out why nothing is being rendered. The vertex and color data is essentially unchanged from the previous version that used glVertex2f().
Simply calling the gl*Pointer functions is not enough; you need to tell OpenGL that it should pull from those particular arrays. For the built-in arrays (glVertexPointer, glColorPointer, etc), you use glEnableClientState(), for the particular array in question.
For example:
glBindBuffer(GL_ARRAY_BUFFER, vertices);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, NULL);
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(4, GL_BYTE, 0, (const GLvoid *)(sizeof(GLfloat) * 2));
That should provide better results.
You should also use glDisableClientState() on those arrays after you are finished rendering with them.
You seem to be missing a few steps:
VAO binding
enabling client state (VBO), e.g. glEnableClientState(GL_VERTEX_ARRAY)
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)