glVertexAttribPointer() - when should this be called? - opengl

I have some example code that calls glVertexAttribPointer() in 2 places. Is this necessary or can it just be done once?
First time - associating the vertex buffer data:
glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, sizeof( COLVERTEX ), 0 );
glBufferData( GL_ARRAY_BUFFER, sizeof( v ), v, GL_STATIC_DRAW );
Second time - in the rendering callback function:
glEnableVertexAttribArray(0);
glBindBuffer( GL_ARRAY_BUFFER, vboQuad );
glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, sizeof( COLVERTEX ), 0 );
glDrawArrays( GL_QUADS, 0, 4 );
glDisableVertexAttribArray(0);
Is it really necessary to describe the vertex attributes twice?

BufferData fills VBO with raw data. At this point it doesn't matter how data is supposed to be interpreted when drawing (e.g. the same data may be interpreted as vertex positions at one draw but as normals in another). So yes, you can remove this first call.
If you use vertex array objects, you could set vertex attribute pointers only once (via binding VBO, enabling vertex attibute, and setting vertex attribute pointer) and then just call glBindVertexArray before drawing and have all recorded vertex attrubtes set up (you don't even need to bind VBO containing vertex attributes before draw call).

Related

Unexpected triangles rendered with OpenGL

I want to render blender's default cube and Suzanne. I have them both exported as OBJ-files. Loading and rendering works fine, but when I attempt to render them both in the same scene, things become confusing (to me).
The "relevant" code is in lines 48 to 56.
In the beginning there was just model1 (Line 51, Suzanne or a cube or anything else) and the scene was rendered as expected.
Then I added another model2 (Line 54), which happened to be the cube.
The unintended triangles (see rendered scene, Screenshot (I)) where drawn ontop of the cube, which was not translated "away" at this point.
Don't know my plans or thoughts of when I moved the cube into the back, but was surprised to find the garbage triangles stay where they are.
Since I had no idea where they came from, I started flipping lines around to get my hands on it:
It is of no importance whether model1 is rendered first, or model2.
When I load two default_cubes instead of one suzanne, one cube is perfectly fine, and the other one just like in the first screenshot.
The result is seen in Screenshot (II). I'm constructing model2 before model1 and the garbage is now rendered differently in a different place.
The code below shows the last part of the Model-constructor, where the VBA is configured. The render() function is the one being seen in the screenshots.
[...]
glGenVertexArrays( 1, &VBA );
glBindVertexArray( VBA );
glGenBuffers( 1, &VBO[0] );
glBindBuffer( GL_ARRAY_BUFFER, VBO[0] );
glBufferData( GL_ARRAY_BUFFER, sizeof(glm::vec3) * vertices.size(), vertices.data(), GL_STATIC_DRAW );
glEnableVertexAttribArray( 0 );
glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 0, 0 );
}
void Model::render( void )
{
glUniformMatrix4fv( model_location, 1, GL_FALSE, &model_matrix[0][0] );
glBindVertexArray( VBA );
// 'vertices' is of type std::vector<glm::vec3>
glDrawArrays( GL_TRIANGLES, 0, sizeof(glm::vec3) * vertices.size() );
}
You pass wrong data to glDrawArrays. The third parameter has to contain the number of vertices, not the size in bytes. The correct call would be:
glDrawArrays( GL_TRIANGLES, 0, vertices.size() );

OpenGL Vertex Array Object usage

I have been working to get OpenGL to render multiple different entities on the scene.
According to http://www.opengl.org/wiki/Vertex_Specification,
Vertex Array Object should remember what Vertex Buffer Object was bound to GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER. (Or at least that is how I understood what it was saying)
Yet, even though I call draw after binding any vao, the application will use only the last one bound to GL_ARRAY_BUFFER.
Question - Am I understanding it right? Considering the code below, is all sequence of calling to gl functions is correct?
void OglLayer::InitBuffer()
{
std::vector<float> out;
std::vector<unsigned> ibOut;
glGenVertexArrays(V_COUNT, vaos);
glGenBuffers(B_COUNT, buffers);
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= //
glBindVertexArray(vaos[V_PLANE]);
PlaneBuffer(out, ibOut, 0.5f, 0.5f, divCount, divCount);
OGL_CALL(glBindBuffer(GL_ARRAY_BUFFER, buffers[B_PLANE_VERTEX]));
OGL_CALL(glBufferData(GL_ARRAY_BUFFER, out.size()*sizeof(float), out.data(), GL_DYNAMIC_DRAW));
//GLuint vPosition = glGetAttribLocation( programs[P_PLANE], "vPosition" );
OGL_CALL(glEnableVertexAttribArray(0));
//OGL_CALL(glVertexAttribPointer( vPosition, 3, GL_FLOAT, GL_FALSE, sizeof(float)*3, BUFFER_OFFSET(0) ));
OGL_CALL(glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, sizeof(float)*3, BUFFER_OFFSET(0) ));
bufferData[B_PLANE_VERTEX].cbSize = sizeof(float) * out.size();
bufferData[B_PLANE_VERTEX].elementCount = out.size()/3;
OGL_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[B_PLANE_INDEX]));
OGL_CALL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, ibOut.size()*sizeof(unsigned), ibOut.data(), GL_STATIC_DRAW));
bufferData[B_PLANE_INDEX].cbSize = sizeof(float) * ibOut.size();
bufferData[B_PLANE_INDEX].elementCount = ibOut.size();
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= //
glBindVertexArray(vaos[V_CUBE]);
out.clear();
ibOut.clear();
GenCubeMesh(out, ibOut);
glBindBuffer(GL_ARRAY_BUFFER, buffers[B_CUBE_VERTEX]);
glBufferData(GL_ARRAY_BUFFER, out.size()*sizeof(float), out.data(), GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), BUFFER_OFFSET(0));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[B_CUBE_INDEX]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned), ibOut.data(), GL_STATIC_DRAW);
}
void RenderPlane::Render( float dt )
{
// Putting any vao here always results in using the lastly buffer bound.
OGL_CALL(glBindVertexArray(g_ogl.vaos[m_pRender->vao]));
{
OGL_CALL(glUseProgram(g_ogl.programs[m_pRender->program]));
// uniform location
GLint loc = 0;
// Send Transform Matrix ( Rotate Cube over time )
loc = glGetUniformLocation(g_ogl.programs[m_pRender->program], "transfMat");
auto transf = m_pRender->pParent->m_transform->CreateTransformMatrix();
glUniformMatrix4fv(loc, 1, GL_TRUE, &transf.matrix()(0,0));
// Send View Matrix
loc = glGetUniformLocation(g_ogl.programs[m_pRender->program], "viewMat");
mat4 view = g_ogl.camera.transf().inverse();
glUniformMatrix4fv(loc, 1, GL_TRUE, &view(0,0));
// Send Projection Matrix
loc = glGetUniformLocation(g_ogl.programs[m_pRender->program], "projMat");
mat4 proj = g_ogl.camera.proj();
glUniformMatrix4fv(loc, 1, GL_TRUE, &proj(0,0));
}
OGL_CALL(glDrawElements(GL_TRIANGLES, g_ogl.bufferData[m_pRender->ib].elementCount, GL_UNSIGNED_INT, 0));
}
The GL_ARRAY_BUFFER binding is not part of the VAO state. The wiki page you link explains that correctly:
Note: The GL_ARRAY_BUFFER​ binding is NOT part of the VAO's state! I know that's confusing, but that's the way it is.
The GL_ELEMENT_ARRAY_BUFFER binding on the other hand is part of the VAO state.
While I don't completely disagree with calling this confusing, it actually does make sense if you start thinking about it. The goal of a VAO is to capture all vertex state that you would typically set up before making a draw call. When using indexed rendering, this includes binding the proper index buffer used for the draw call. Therefore, including the GL_ELEMENT_ARRAY_BUFFER binding in the VAO state makes complete sense.
On the other hand, the current GL_ARRAY_BUFFER binding does not influence a draw call at all. It only matters that the correct binding is established before calling glVertexAttribPointer(). And all the state set by glVertexAttribPointer() is part of the VAO state. So the VAO state contains the vertex buffer reference used for each attribute, which is established by the glVertexAttribPointer() call. The current GL_ARRAY_BUFFER on the other hand is not part of the VAO state because the current binding at the time of the draw call does not have any effect on the draw call.
Another way of looking at this: Since attributes used for a draw call can be pulled from different vertex buffers, having a single vertex buffer binding tracked in the VAO state would not be useful. On the other hand, since OpenGL only ever uses a single index buffer for a draw call, and uses the current index buffer binding for the draw call, tracking the index buffer binding in the VAO makes sense.

OpenGL - Correct way to load multi faces

If I got a cube model for example (cube got 6 faces). how can I draw each face with vbo? do I need to call glDrawElements 6 times? or is there another function to draw all at once? Usually I draw it like this:
for (int i = 0; i < facesNum; i++)
glDrawElements(GL_TRIANGLE_FAN, 4 + i*4, GL_UNSIGNED_INT, (GLvoid*)(i*4));
Is that the best way?
You can use Primitive Restart (OpenGL 3.1+) to restart a primitive such as a triangle fan while rendering, as if you started another glDraw* command.
Use glEnable(GL_PRIMITIVE_RESTART) to enable it, then glPrimitiveRestartIndex(restartIndex) to set an index (such as 0xFFFF) to use to signal a restart. Then whenever OpenGL encounters the restart index, it will stop the currently drawn primitive and start another one.
This lets you draw multiple triangle strips, fans, line loops, or strips with one index buffer and draw command. Just add the restart index between each primitive's index data.
Generally, what you would do is draw your object as GL_TRIANGLES instead of GL_TRIANGLE_FAN, which allows you to just draw all 12 triangles (6 faces * 2 triangles per face) with one call to glDrawElements.
To do this, you of course have to somewhat rearrange your Index Buffer, to include the information for the vertices of each triangle. This means you have to duplicate some indices, which should however not be a problem, as the point of the Index Buffer is precisely to be able to do this and not duplicate vertices.
Assuming your top face consists of the vertices index 0,1,2,3 in counterclockwise order,
you would change that part of the index buffer from 0,1,2,3 to 0,1,2,0,2,3 for example.
With this changed setup of the index buffer, all it should take would be a call to
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, NULL);
(36 as we are drawing 12 triangles for the cube with 3 vertices each)
You should only have to call DrawElements once with a single VBO. There are alternatives such as IBO's, but I am going to provide an example for a VBO since that is what you requested. Ideally, you should store all the vertices in an array or std::vector holding Vertex objects. Put all of your cube face vertices in this array or std::vector. You do not need an array/vector for each face. You will want to keep the data tightly compact and avoid using the virtual keyword as it creates a non exposed pointer (vtptr) which adds to your class memory footprint. The reason you want to keep the data compact is for when you send it to OpenGL, it will expect step sizes. If you ever are in doubt of the memory footprint of a class, it never hurts to do a quick output with the sizeof( ClassName ) function.
Your vertex class would look something like as follows;
class Vertex {
public:
~Vertex() {}
Vertex() {}
Vector3<float> vertexPosition;
Vector4<float> vertexColor;
Vector2<float> vertexTextureCoords;
Vector3<float> vertexNormal;
Vector3<float> vertexTangent;
Vector3<float> vertexBitangent;
Vector4<int> vertexBoneIndexes;
Vector4<float> vertexBoneWeights;
};
Where all the vector classes are NON virtual and the only data members are the vector components.
Here are the steps I follow:
Create a std::vector (or array) of vertex objects and populate the vertex data
Generate the VBO with the appropriate OpenGL Calls (Here is an example from my engine). I use a singleton which has wrapper functions in order to be Graphics API agnostic. The parameters are in the exact same order OpenGL would expect them for their VBO generation functions.
cbengine::CBRenderer * sharedRenderer = cbengine::CBRenderer::sharedCBRenderer();
sharedRenderer->generateVBOBuffers( 1, &entityToCreate->m_VBOBufferID );
sharedRenderer->bindVBOBuffer( entityToCreate->m_VBOBufferID );
sharedRenderer->bufferDataForVBO( ( sizeof( cbengine::Vertex ) * entityToCreate- >m_verts.size() ), &entityToCreate->m_verts.front() );
In your render function make the following OpenGL Calls. This is why I advised keeping the data tightly compact earlier. OpenGL needs to know what type of data to expect, the size of the data type, and the offset from the start of the data.
glEnableVertexAttribArray( m_vertexLocation );
glVertexAttribPointer( m_vertexLocation, 3, GL_FLOAT, false, sizeof( cbengine::Vertex ), (float*) offsetof( cbengine::Vertex, vertexPosition ) );
glEnableVertexAttribArray( m_colorLocation );
glVertexAttribPointer( m_colorLocation, 4, GL_FLOAT, false, sizeof( cbengine::Vertex ), (float*) offsetof( cbengine::Vertex, vertexColor ) );
glEnableVertexAttribArray( m_diffuseTextureCoordLocation );
glVertexAttribPointer( m_diffuseTextureCoordLocation, 2, GL_FLOAT, false, sizeof( cbengine::Vertex ), (float*) offsetof( cbengine::Vertex, vertexTextureCoords ) );
glEnableVertexAttribArray( m_normalCoordLocation );
glVertexAttribPointer( m_normalCoordLocation, 3, GL_FLOAT, false, sizeof( cbengine::Vertex ), (float*) offsetof( cbengine::Vertex, vertexNormal ) );
glEnableVertexAttribArray( m_tangentLocation );
glVertexAttribPointer( m_tangentLocation, 3, GL_FLOAT, false, sizeof( cbengine::Vertex ), (float*) offsetof( cbengine::Vertex, vertexTangent ) );
glEnableVertexAttribArray( m_bitangentLocation );
glVertexAttribPointer( m_bitangentLocation, 3, GL_FLOAT, false, sizeof( cbengine::Vertex ), (float*) offsetof( cbengine::Vertex, vertexBitangent ) );
glEnableVertexAttribArray( m_boneIndexesLocation ); // Apparently GL_INT causes issues
glVertexAttribPointer( m_boneIndexesLocation, 4, GL_FLOAT, false, sizeof( cbengine::Vertex ), (float*) offsetof( cbengine::Vertex, vertexBoneIndexes ) );
glEnableVertexAttribArray( m_boneWeightsLocation );
glVertexAttribPointer( m_boneWeightsLocation, 4, GL_FLOAT, false, sizeof( cbengine::Vertex ), (float*) offsetof( cbengine::Vertex, vertexBoneWeights ) );
Lastly, make a call to DrawArrays
sharedRenderer->drawArrays( drawPrim, 0, verts.size() );
This is a very quick example of how to accomplish what you want. Other things to keep in mind are winding order for culling, enabling/disabling textures, and custom vertex attrib data you may want to send to your shaders. You may not want to include the Bone Weights and Bone Indexes vectors if your engine does not support skeletal animation.

glVertexAttribPointer() working only with the first stream

I am trying to use glVertexAttribPointer() to give some data to my vertex shader. The thing is that it's working only with the FIRST attribute...
Here is my OpenGL code:
struct Flag_vertex
{
GLfloat position_1[ 8 ];
GLfloat position_2[ 8 ];
};
Flag_vertex flag_vertex;
... // fill some data to flag_vertex
GLuint vertexbuffer_id;
glGenBuffers( 1, &vertexbuffer_id );
glBindBuffer( GL_ARRAY_BUFFER, vertexbuffer_id );
glBufferData( GL_ARRAY_BUFFER, sizeof(flag_vertex), &flag_vertex, GL_STATIC_DRAW );
glEnableVertexAttribArray( 0 );
glEnableVertexAttribArray( 1 );
glBindBuffer( GL_ARRAY_BUFFER, vertexbuffer_id );
glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, 0, (void*)offsetof(Flag_vertex, position_1) );
glVertexAttribPointer( 1, 2, GL_FLOAT, GL_FALSE, 0, (void*)offsetof(Flag_vertex, position_2) );
and my shader is something like:
#version 420 core
layout(location = 0) in vec2 in_position_1;
layout(location = 1) in vec2 in_position_2;
out vec2 texcoord;
void main()
{
gl_Position = vec4(in_position_X, 0.0, 1.0);
texcoord = in_position_X * vec2(0.5) + vec2(0.5);
}
If I use "in_position_1" my texture RENDERS PERFECTLY, but if I use in_position_2 nothing happens...
Tip: before link my shaders I am doing:
glBindAttribLocation( programID, 0, "in_position_1");
glBindAttribLocation( programID, 1, "in_position_2");
Why it works only with the first stream? I need more data going to my vertex... I need to send color, etc... any hint?
glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, 0, (void*)offsetof(Flag_vertex, position_1) );
glVertexAttribPointer( 1, 2, GL_FLOAT, GL_FALSE, 0, (void*)offsetof(Flag_vertex, position_2) );
These lines don't make sense. At least, not with how Flag_vertex is defined. If Flag_vertex is really supposed to be a vertex (and not a quad), then it makes no sense for it to have 8 floats. If each Flag_vertex defines a full quad, then you named it wrong; it's not a vertex at all, it's Flag_quad.
So it's hard to know what you're even trying to accomplish here.
Also:
If I use "in_position_1" my texture RENDERS PERFECTLY, but if I use in_position_2 nothing happens...
Of course it does. Your position data is in attribute 0. Your position data is therefore not in attribute 1. If you pretend attribute 1 has your position data when it clearly doesn't, you will not get reasonable results.
Your problem is that you're always using attribute 0 when you should be using both of them. You shouldn't be picking one or the other. Use in_position_1 for the position and in_position_2 for the texture coordinate. And try to name them reasonably, based on what they do (like position and texture_coord or something). Don't use numbers for them.
Tip: before link my shaders I am doing:
That is the exact same thing as the layout(location=#) setting in the shader. If you want it in the shader, then put it in the shader. If you want it in your OpenGL code, then put it in your OpenGL code. Don't put it in both places.

combining glVertexPointer and glVertexAttribPointer gives problems

I'm having an issue when first rendering a vertexbuffer with a program,
and then rendering a different vertexbuffer without program.
for the first buffer, when a program is enabled, i use code similar to:
glBindBuffer( GL_ARRAY_BUFFER, m_id );
GLint location = glGetAttribLocation( pID, "position" );
glEnableVertexAttribArray( location );
glVertexAttribPointer( location, 3, GL_FLOAT, GL_FALSE, 3 * sizeof( GLfloat ), 0 );
glDrawArrays( m_mode, 0, m_numVertices );
for the second, without program:
glBindBuffer( GL_ARRAY_BUFFER, m_id );
glEnableClientState( GL_VERTEX_ARRAY );
glVertexPointer( 3, GL_FLOAT, 3 * sizeof( GLfloat ), 0 );
glDrawArrays( m_mode, 0, m_numVertices );
both codepaths work fine individually, but when done in the order
"with program"->"without program", the second seems to use the buffer of the first,
and in the order "without program"->"with program", the first is not drawn (in the second iteration).
now this suggests to me that I'm missing some state change done by the glEnableVertexAttribArray block, but I don't understand what state change is causing the problems.
ps the reason I'm rendering with and without program is that in the scenegraph lib im using you can turn programs on or off per node.
Try adding
glDisableVertexAttribArray( location ); // location of "position"
before switching to fixed function rendering.