Reputation: 3336
So in my program, I'm using OpenGL/GLSL to construct a square and texturing it.
It's modern OpenGL 4.0+
so doesn't use glBegin
/glEnd
etc.
My square is made up of 2 triangles, constructed using glDrawArrays(GL_TRIANGLES, 0, 6);
As you can see with my function below, it creates 2 triangles. I'm using 18 vertices in an array when really I only need 12 to create a square because 6 of them are used in both triangles. Its the same with the 24 colours and 8 text coordinates.
void Ground::constructGeometry(Shader* myShader)
{
//Triangle 1 (x,y,z)
vert[0] =-dimY; vert[1] = dimX; vert[2] = dimZ; //Point 2
vert[3] =-dimY; vert[4] =-dimX; vert[5] = dimZ; //Point 1
vert[6] = dimY; vert[7] =-dimX; vert[8] = dimZ; //Point 4
//Triangle 2 (x,y,z)
vert[9] = dimY; vert[10] =-dimX; vert[11] = dimZ; //Point 4
vert[12] = dimY; vert[13] = dimX; vert[14] = dimZ; //Point 3
vert[15] =-dimY; vert[16] = dimX; vert[17] = dimZ; //Point 2
//Colours 1 (r,g,b,a)
col[0] = 1.0f; col[1] = 0.0f; col[2] = 0.0f; col[3] = 1.0f;
col[4] = 1.0f; col[5] = 0.0f; col[6] = 0.0f; col[7] = 1.0f;
col[8] = 1.0f; col[9] = 0.0f; col[10] = 0.0f; col[11] = 1.0f;
//Colours 2 (r,g,b,a)
col[12] = 1.0f; col[13] = 0.0f; col[14] = 0.0f; col[15] = 1.0f;
col[16] = 1.0f; col[17] = 0.0f; col[18] = 0.0f; col[19] = 1.0f;
col[20] = 1.0f; col[21] = 0.0f; col[22] = 0.0f; col[23] = 1.0f;
//(s,t) coords for Tri 1
tex[0] = 0.0; tex[1] = 1.0;
tex[2] = 0.0; tex[3] = 0.0;
tex[4] = 1.0; tex[5] = 0.0;
//(s,t) coords for Tri 2
tex[6] = 1.0; tex[7] = 0.0;
tex[8] = 1.0; tex[9] = 1.0;
tex[10] = 0.0; tex[11] = 1.0;
glGenVertexArrays(2, &m_vaoID[0]);
glBindVertexArray(m_vaoID[0]);
glGenBuffers(3, m_vboID);
GLint vertexLocation= glGetAttribLocation(myShader->handle(), "in_Position");
GLint colorLocation= glGetAttribLocation(myShader->handle(), "in_Color");
GLint texCoordLocation = glGetAttribLocation(myShader->handle(), "in_TexCoord");
glUniform1i(glGetUniformLocation(myShader->handle(), "DiffuseMap"), 0);
glBindBuffer(GL_ARRAY_BUFFER, m_vboID[0]);
glBufferData(GL_ARRAY_BUFFER, totalVerts *sizeof(GLfloat), vert, GL_STATIC_DRAW);
glEnableVertexAttribArray(vertexLocation);
glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, m_vboID[1]);
glBufferData(GL_ARRAY_BUFFER, totalCols *sizeof(GLfloat), col, GL_STATIC_DRAW);
glEnableVertexAttribArray(colorLocation);
glVertexAttribPointer(colorLocation, 4, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, m_vboID[2]);
glBufferData(GL_ARRAY_BUFFER, totalTexs *sizeof(GLfloat), tex, GL_STATIC_DRAW);
glVertexAttribPointer(texCoordLocation, 2, GL_FLOAT, GL_FALSE, 0,0);
glEnableVertexAttribArray(texCoordLocation);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glEnableVertexAttribArray(0);
glBindVertexArray(0);
}
How can this be made more efficient so when making the second triangle I can use vert[x] that's already been used instead of declaring the same ones again (points 4 and 2)? And the same with colours?
And how does this affect my rendering function below?
void Ground::render(GLuint texName, Shader* myShader)
{
glUseProgram(myShader->handle()); //find shader passed
glBindTexture(GL_TEXTURE_2D, texName); //blending needed to use alpha channel
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBindVertexArray(m_vaoID[0]); //select first VAO
glDrawArrays(GL_TRIANGLES, 0, 6); //draw first object 0-3, then second 3-6
glDisable(GL_BLEND);
glUseProgram(0);
glBindVertexArray(0); //unbind the vertex array object
}
Obviously I guess it's OK to do it the way I have for only 2 triangles, but I wouldn't want to write out hundreds of vertices if, for some reason, I suddenly wanted a whole bunch of triangles...
Upvotes: 1
Views: 3038
Reputation: 2917
As an alternative to the (correct) answers using glDrawElements
, you could use glDrawArrays
with GL_TRIANGLE_FAN
instead of GL_TRIANGLES
. A fan uses the first three vertices to draw a triangle, then each subsequent vertex will generate a triangle using the new vertex, the last vertex and the first vertex. Now you only need four vertices (arranged counter-clockwise) in your array, and the call looks like:
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
Upvotes: 2
Reputation: 45332
What you asking for is called indexed rendering. The basic idea is to provide an index buffer those elements reference the vertex IDs in your vertex arrays. So for two triangles sharing one edge, you can define just the 4 corner vertices and can use and index array like {0,1,2, 2,1,3}
. You will have to use glDrawElements()
to do the drawing.
You might also want to have a look at this wiki page to get an overview of what drawing paths are available in modern GL.
Upvotes: 1
Reputation: 18803
Use glDrawElements()
instead of glDrawArrays()
if you would like to reuse vertices.
glDrawElements
takes an index array argument, which allows you to specify the indices of vertices in the vertex array, making it possible to use them multiple times.
Upvotes: 3