PDA

View Full Version : What's happening to my triangles?



mynameisjohn
03-15-2015, 05:33 AM
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.col or));

//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)?

GClements
03-15-2015, 06:21 AM
I thought that binding the VAO would rebind these by default? Is that not the case?

The glBindBuffer() call was made while the VAO was bound, so unbinding the element array buffer changes the setting stored within the VAO.

Also, note that the VAO doesn't store the current binding for GL_ARRAY_BUFFER; for each attribute, it stores the buffer which was bound at the time of the corresponding glVertexAttribPointer() call.

mynameisjohn
03-18-2015, 05:23 AM
Thanks, that actually clears up a lot for me.