EDIT:
I’ve gotten my cube to draw, but I’m still confused. See edit at bottom of post.
Hello all,
Sorry for the vague title, but that really is my question. As a preface, I am using glm for some things, and I’ve got a Shader class with accessor methods for the handle to the position attribute. I am also using SDL2 to create my context, and the version I am requesting is OpenGL 3.0.
I am just trying to draw a cube, and I have created a VAO using the following function:
//Global geometry struct
struct Geom{
GLuint VAO, nIdx;
vec4 color;
mat4 MV;
};
Geom g_Geometry {0, 0, vec4(1), mat4(1) };
//Global Shader
JShader g_Shader;
bool createGeometry(){
GLuint buffers[2];
//Indices and Vertices taken from an IQM file exported from Blender
vector<GLfloat> vertices{
1,1,-1,
-1,-1,-1,
1,-1,-1,
-1,1,-1,
1,1,1,
-1,-1,1,
-1,1,1,
1,-1,1,
1,1,-1,
1,-1,1,
1,1,1,
1,-1,-1,
1,-1,-1,
-1,-1,1,
1,-1,1,
-1,-1,-1,
-1,-1,-1,
-1,1,1,
-1,-1,1,
-1,1,-1,
1,1,1,
-1,1,-1,
1,1,-1,
-1,1,1
};
vector<GLuint> indices{
0,1,2,
0,3,1,
4,5,6,
4,7,5,
8,9,10,
8,11,9,
12,13,14,
12,15,13,
16,17,18,
16,19,17,
20,21,22,
20,23,21
};
glGenVertexArrays( 1, &g_Geometry.VAO );
glBindVertexArray( g_Geometry.VAO );
glGenBuffers(2, buffers);
//positions
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
glBufferData(GL_ARRAY_BUFFER,
sizeof(GLfloat)*vertices.size(),
vertices.data(),
GL_STATIC_DRAW);
glEnableVertexAttribArray(g_Shader.getPosHandle());
glVertexAttribPointer(g_Shader.getPosHandle(), 3, GL_FLOAT, 0, 0, 0);
//indices
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
sizeof(GLuint)*indices.size(),
indices.data(),
GL_STATIC_DRAW);
//unbind
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
//Set the number of indices and color
g_Geometry.nIdx = indices.size();
g_Geometry.color= vec4(1,0,1,1);
return g_Geometry.VAO != 0;
}
All of that data was taken from an IQM file I exported from Blender (just the default cube), and I think it is correct (it looks like two triangles per face, anyway.)
Here is my render call. I have a Camera struct as well, but I don’t think it’s relevant.
struct Camera{
mat4 proj;
};
Camera g_Camera { mat4(1) };
//Just a rotation to keep things moving
float theta(0.1f);
//Render function
bool render(){
g_Shader.bind();
glBindVertexArray(g_Geometry.VAO);
{
//Send MV matrix to GPU
g_Geometry.MV = glm::translate( vec3(0,0,-5.f) ) * glm::rotate( theta, vec3(0,1,0) );
g_Shader.updateMV(glm::value_ptr(g_Geometry.MV));
//Send projection matrix to GPU
g_Camera.proj = glm::perspective(45.f,SCREEN_DIM.x/SCREEN_DIM.y, 1.f, 20.f);
g_Shader.updateProj(glm::value_ptr(g_Camera.proj));
//Set color uniform on GPU
g_Shader.updateColor(glm::value_ptr(g_Geometry.color));
//Draw call, neither really seems to work
glDrawArrays(GL_TRIANGLES, 0, g_Geometry.nIdx);
// glDrawElements(GL_TRIANGLES, g_Geometry.nIdx, GL_UNSIGNED_INT, NULL);
}
glBindVertexArray(0);
g_Shader.unbind();
theta += 0.01f;
return true;
}
When I use glDrawArrays, I get a shape whose triangles do seem to hit every corner, although the ordering is very incorrect. When I use glDrawElements I don’t see anything at all.
I’m not sure what the deal with enabling and disabling Vertex Attribute Arrays (like position), but I though that with a VAO I only needed to do it during the initialization.
For posterity, here is my shader
//VERTEX SHADER
#version 130
uniform mat4 projMat;
uniform mat4 MVMat;
attribute vec3 vPosition;
void main(){
gl_Position = projMat * MVMat * vec4(vPosition,1);
}
//FRAGMENT SHADER
#version 130
uniform vec4 fColor;
void main(){
gl_FragColor = fColor;
}
Sorry for all that text, but if anyone reads it all, any advice? As I said glDrawArrays does but a magenta cube-esque shape on the screen, but it’s obvious that the draw order is incorrect. I tried GL_TRIANGLE_STRIP, and while it actually did look better it was still somewhat incorrect.
EDIT:
I was able to get it drawing by removing the following calls from createGeometry():
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
I guess this makes sense, but I thought that binding the VAO would rebind these by default? Is that not the case?
And in general, what are some best practices for when to unbind data (especially in a case like this, where I don’t really want to deal with individual VBOs)?