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.
Related
I'm porting OpenGL 3.X code to OpenGL 2.1, where no VAO available. The codes below make my program crash inside graphics driver, immediately at glDrawElements call.
Part of the code is shared between 3.X and 2.1 mode, and it works properly in OpenGL 3.X above.
struct StrokeVertex
{
glm::vec2 position;
glm::vec2 tangent;
float center_dist;
};
if (use_gl3)
bind_vao();
bind_vbo();
bind_ibo();
send_data();
bind_program();
set_uniforms();
// setup client-side vertex array here
if (!use_gl3)
{
glEnableClientState( GL_VERTEX_ARRAY );
GLHELPER_CHECK;
glEnableVertexAttribArray( 0 );
GLHELPER_CHECK;
glVertexAttribPointer( get_attribute_location( "tangent" ) /* got 1 here */, 2, GL_FLOAT, GL_FALSE, sizeof( StrokeVertex ), (void*) offsetof( StrokeVertex, tangent ) );
GLHELPER_CHECK;
glEnableVertexAttribArray( 1 );
GLHELPER_CHECK;
glVertexAttribPointer( get_attribute_location( "center_dist" ) /* got 2 here */, 1, GL_FLOAT, GL_FALSE, sizeof( StrokeVertex ), (void*) offsetof( StrokeVertex, center_dist ) );
GLHELPER_CHECK;
// I also tried call this before setting the two attributes
glVertexPointer( 2, GL_FLOAT, sizeof( StrokeVertex ), (void*) offsetof( StrokeVertex, position ) );
GLHELPER_CHECK;
}
// immediately crash here
glDrawElements( GL_TRIANGLES, GLsizei( n_elem ), GL_UNSIGNED_INT, nullptr );
GLHELPER_CHECK;
if (!use_gl3)
{
glDisableClientState( GL_VERTEX_ARRAY );
}
else
{
unbind_vao();
}
And the part of vertex shader of OpenGL 3.X and 2.X. Most part are same expect attribute declaration:
in vec2 logic_pos;
in vec2 tangent;
in float center_dist;
OpenGL 2.X:
// builtin gl_Vertex is used, so we omit logic_pos
attribute vec2 tangent;
attribute float center_dist;
There seems to be a mismatch regarding which vertex attributes get enabled and to which data gets bound:
The following code tells OpenGL that it should enable vertex attribute 0, but the data gets bound to attribute 1 (at least according to the comment).
glEnableVertexAttribArray( 0 );
glVertexAttribPointer( get_attribute_location( "tangent" ) /* got 1 here */, 2, GL_FLOAT, GL_FALSE, sizeof( StrokeVertex ), (void*) offsetof( StrokeVertex, tangent ) );
In total, it looks as if your code enables attributes 0 and 1, but binds data to 1 and 2.
If you have attributes enabled but do not bind any data to them, this might lead to the crash you describe.
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() );
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).
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.
I'm preparing some buffers with 2f vertices, 2f texvertices and 4f colors. It's displayed right. The whole thing is in one class. If I have more instances (every generating it's own buffer id, never passed in a function so it's not cleaned up, wrapped as pointers in a std::list) only during the first draw (paused after first draw using gdb and I see all buffered things) all buffered data is visible. In the next draw only the last drawn buffer is visible.
I prepare them by generate, bind and then fill the buffer with data with this call:
glBufferData( GL_ARRAY_BUFFER, Size * 8 * sizeof( float ), f, GL_STATIC_DRAW );
where Size is a std::size_t with the number of vertices and f the float-Array. To draw the buffer I bind it, activate the clientstates: GL_VERTEX_ARRAY, GL_TEXTURE_COORD_ARRAY, GL_COLOR_ARRAY.
glDrawArrays( Mode, 0, Size );
where Mode is a GLenum with GL_TRIANGLES.
I fixed it by calling glBufferData before glDrawArrays every frame but that's not how it supposed to be. It supposed to be generating, binding, filling and then to draw by just binding and calling glDrawArrays, isn't it?
If necessary: I'm working with C++, gcc on a Windows 7 x64.
I was asked for more code:
void Buffer::CopyToGPU( )
{
glBindBuffer( GL_ARRAY_BUFFER, Object );
float* f = new float[ Size * 8 ];
for ( std::size_t s( 0 ) ; s < Size ; ++s )
CopyVertexToFloatArray( &f[ s * 8 ], Vortex[ s ] );
glBufferData( GL_ARRAY_BUFFER, Size * 8 * sizeof( float ), f, GL_STATIC_DRAW );
delete[] f;
glVertexPointer( 2, GL_FLOAT, 8 * sizeof( float ), NULL );
glTexCoordPointer( 2, GL_FLOAT, 8 * sizeof( float ), (char*)( 2 * sizeof( float ) ) );
glColorPointer( 4, GL_FLOAT, 8 * sizeof( float ), (char*)( 4 * sizeof( float ) ) );
}
void Buffer::Render( )
{
glBindBuffer( GL_ARRAY_BUFFER, Object );
glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState( GL_TEXTURE_COORD_ARRAY );
glEnableClientState( GL_COLOR_ARRAY );
//Actually draw the triangle, giving the number of vertices provided
glDrawArrays( Mode, 0, Size );
glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
glDisableClientState( GL_COLOR_ARRAY );
}
int main( ... ) // stripped buffer sfml2 initialization etc.
{
glClearColor( 0, 0, 0, 1 );
glEnable( GL_ALPHA_TEST );
glAlphaFunc( GL_GREATER , 0.1 );
glEnable( GL_TEXTURE_2D );
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
while ( win.isOpen( ) ) // sf::Window
{
/// draw
glClear( GL_COLOR_BUFFER_BIT );
MVP.Apply( );
CallDraw( );
win.display( );
}
}
You seem to specify the attrib pointers when you update the buffer object. This is not how it works. The vertex attrib pointers are (depending on the GL version) either global state, or per-VAO state, but never per-VBO state. Currently, when you do something like
bufferA.CopyToGPU();
bufferB.CopyToGPU();
while(true) {
bufferA.render();
bufferB.render();
}
only buffer B will be used (leaving potential for out-ouf-bounds accesses as you think you use buffer A when rendering it), as the vertex array state is set to buffer B in the second call, overwriting any attrib pointers set in the first call. You need either to respecify the pointers when you draw each object, or use Vertex Array Objects to encapsulate those pointers. Note that the latter path is mandatory on GL >= 3.X core profile.