Unable two render two separate objects with two VAOs

Hello.

I’m pretty new to the modern GL pipeline even though I feel like I understand it pretty well. I’m setting up a simple test to render two textured triangles next to eachother.

I have one shader and one texture. I create two VAOs, two VBOs, fill those VBOs with float data, and proceed in this order:

[NOTE][ul]
[li]Bind VAO1[/li][li]Bind VBO1[/li][li]Set and enable VertexAttribPointers[/li][li]Bind VAO2[/li][li]Bind VBO2[/li][li]Set and enable VertexAttribPointers[/ul][/NOTE][/li]
Drawing looks like this:

[NOTE][ul]
[li]Enable shader[/li][li]Bind VAO1[/li][li]glDrawArrays[/li][li]Bind VAO2[/li][li]glDrawArrays[/ul][/NOTE][/li]
This is my output:
[ATTACH=CONFIG]1402[/ATTACH]

As you can see it’s only drawing one of my objects. If I remove the Bind VBO2 call referenced in the first note above, the object on the left then draws but obviously the second one no longer does. Am I misunderstanding something about the way you’re supposed to use these objects?

This is the relevant code, all there is besides this is using SDL to get a window to draw to and receive input.

Init code, ran once:

    //openGL state setup
    glEnable(GL_BLEND);
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_DEPTH_TEST);
    
    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    mat4x4 ViewMatrix;
    mat4x4 ProjMatrix;
    v3 Cam     = V3(0.0f, 0.0f, 2.0f);

    // shader
    gl_shader_program WorldShader;
    GLLoadShaderProgram(&WorldShader, "shaders/default.vert", "shaders/default.frag");
    GLUseShader(&WorldShader);

    glUniform1i(glGetUniformLocation(WorldShader.Program, "diffuse"), 0);

    // texture
    gl_texture Texture;
    GLLoadTexture(&Texture, "textures/shooter.png");
    
    // vao
    GLuint VAO;
    glGenBuffers(1, &VAO);
    GLuint VAO2;
    glGenBuffers(1, &VAO2);
    
    // vbo
    r32 Verts[] = {
	-1.0f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.5f, 0.0f,
	-0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f,
	-1.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f,
    };
    r32 Verts2[] = {
	1.0f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.5f, 0.0f,
	1.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f,
	0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f,
    };

    GLuint VBO;
    glGenBuffers(1, &VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Verts), Verts, GL_STATIC_DRAW);
    GLuint VBO2;
    glGenBuffers(1, &VBO2);
    glBindBuffer(GL_ARRAY_BUFFER, VBO2);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Verts2), Verts2, GL_STATIC_DRAW);

    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 9*sizeof(float), (void *)(0));
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 9*sizeof(float), (void *)(3*sizeof(float)));
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 9*sizeof(float), (void *)(7*sizeof(float)));
    glEnableVertexAttribArray(2);

    glBindVertexArray(VAO2);
    glBindBuffer(GL_ARRAY_BUFFER, VBO2);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 9*sizeof(float), (void *)(0));
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 9*sizeof(float), (void *)(3*sizeof(float)));
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 9*sizeof(float), (void *)(7*sizeof(float)));
    glEnableVertexAttribArray(2);

Running loop:

	r32 AspectRatio = (Window.Resolution.w / Window.Resolution.h);
	    
	ViewMatrix = LookAt(Cam, V3(), V3(0.0f, 1.0f, 0.0f));
	ProjMatrix = Perspective(AspectRatio, 0.1f, 1000.0f, 60.0f);

	glUniformMatrix4fv(glGetUniformLocation(WorldShader.Program, "View"),
			   1, GL_TRUE, &ViewMatrix.A[0]);
	glUniformMatrix4fv(glGetUniformLocation(WorldShader.Program, "Proj"),
			   1, GL_TRUE, &ProjMatrix.A[0]);
	
	// do render

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	
	GLUseShader(&WorldShader);

	glBindVertexArray(VAO);
	glDrawArrays(GL_TRIANGLES, 0, 3);

	glBindVertexArray(VAO2);
	glDrawArrays(GL_TRIANGLES, 0, 3);

	SDL_GL_SwapWindow(Window.WindowHandle);

Shaders:

// vert
#version 330

layout(location = 0) in vec3 position;
layout(location = 1) in vec4 color;
layout(location = 2) in vec2 uv;

out vec4 Color;
out vec2 UV;

uniform mat4 View;
uniform mat4 Proj;

void main()
{
    vec4 InputPos = vec4(position, 1.0f);
    InputPos.y *= -1.0f;

    Color = color;
    UV = uv;
    
    gl_Position = Proj * View * InputPos;
}


// frag
#version 330

in vec4 Color;
in vec2 UV;

out vec4 outColor;

uniform sampler2D diffuse;

void main()
{  
    vec4 inColor = texture(diffuse, UV)*Color;
    outColor = inColor;
}

Thanks.

I think you would have to show us some of your actual code. Try to narrow your code down to the smallest program that reproduces your problem. There are plenty of possible reasons for your problem, without more details its hard to pinpoint.

Sorry about that, you’re right. I don’t know why I didn’t include any of the actual code. I’ll put it here and edit the post. Thanks for the speedy reply.

This is the relevant code, all there is besides this is using SDL to get a window to draw to and receive input.

Init code, ran once:

    //openGL state setup
    glEnable(GL_BLEND);
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_DEPTH_TEST);
    
    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    mat4x4 ViewMatrix;
    mat4x4 ProjMatrix;
    v3 Cam     = V3(0.0f, 0.0f, 2.0f);

    // shader
    gl_shader_program WorldShader;
    GLLoadShaderProgram(&WorldShader, "shaders/default.vert", "shaders/default.frag");
    GLUseShader(&WorldShader);

    glUniform1i(glGetUniformLocation(WorldShader.Program, "diffuse"), 0);

    // texture
    gl_texture Texture;
    GLLoadTexture(&Texture, "textures/shooter.png");
    
    // vao
    GLuint VAO;
    glGenBuffers(1, &VAO);
    GLuint VAO2;
    glGenBuffers(1, &VAO2);
    
    // vbo
    r32 Verts[] = {
	-1.0f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.5f, 0.0f,
	-0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f,
	-1.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f,
    };
    r32 Verts2[] = {
	1.0f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.5f, 0.0f,
	1.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f,
	0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f,
    };

    GLuint VBO;
    glGenBuffers(1, &VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Verts), Verts, GL_STATIC_DRAW);
    GLuint VBO2;
    glGenBuffers(1, &VBO2);
    glBindBuffer(GL_ARRAY_BUFFER, VBO2);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Verts2), Verts2, GL_STATIC_DRAW);

    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 9*sizeof(float), (void *)(0));
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 9*sizeof(float), (void *)(3*sizeof(float)));
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 9*sizeof(float), (void *)(7*sizeof(float)));
    glEnableVertexAttribArray(2);

    glBindVertexArray(VAO2);
    glBindBuffer(GL_ARRAY_BUFFER, VBO2);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 9*sizeof(float), (void *)(0));
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 9*sizeof(float), (void *)(3*sizeof(float)));
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 9*sizeof(float), (void *)(7*sizeof(float)));
    glEnableVertexAttribArray(2);

Running loop:

	r32 AspectRatio = (Window.Resolution.w / Window.Resolution.h);
	    
	ViewMatrix = LookAt(Cam, V3(), V3(0.0f, 1.0f, 0.0f));
	ProjMatrix = Perspective(AspectRatio, 0.1f, 1000.0f, 60.0f);

	glUniformMatrix4fv(glGetUniformLocation(WorldShader.Program, "View"),
			   1, GL_TRUE, &ViewMatrix.A[0]);
	glUniformMatrix4fv(glGetUniformLocation(WorldShader.Program, "Proj"),
			   1, GL_TRUE, &ProjMatrix.A[0]);
	
	// do render

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	
	GLUseShader(&WorldShader);

	glBindVertexArray(VAO);
	glDrawArrays(GL_TRIANGLES, 0, 3);

	glBindVertexArray(VAO2);
	glDrawArrays(GL_TRIANGLES, 0, 3);

	SDL_GL_SwapWindow(Window.WindowHandle);

Shaders:

// vert
#version 330

layout(location = 0) in vec3 position;
layout(location = 1) in vec4 color;
layout(location = 2) in vec2 uv;

out vec4 Color;
out vec2 UV;

uniform mat4 View;
uniform mat4 Proj;

void main()
{
    vec4 InputPos = vec4(position, 1.0f);
    InputPos.y *= -1.0f;

    Color = color;
    UV = uv;
    
    gl_Position = Proj * View * InputPos;
}


// frag
#version 330

in vec4 Color;
in vec2 UV;

out vec4 outColor;

uniform sampler2D diffuse;

void main()
{  
    vec4 inColor = texture(diffuse, UV)*Color;
    outColor = inColor;
}

If there’s any other info needed just let me know.

Your uniforms seem to be sent to the same shader all the time:


        ProjMatrix = Perspective(AspectRatio, 0.1f, 1000.0f, 60.0f);
 
	glUniformMatrix4fv(glGetUniformLocation(WorldShader.Program, "View"),
			   1, GL_TRUE, &ViewMatrix.A[0]);
	glUniformMatrix4fv(glGetUniformLocation(WorldShader.Program, "Proj"),
			   1, GL_TRUE, &ProjMatrix.A[0]);
 
	// do render
 
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
	GLUseShader(&WorldShader);

Send them to both shaders.

I’m only using one shader at the moment. Could you clarify?

I’m able to use one shader to render multiple different objects, right? I thought this was the case.

Not really sure where else to go with this. I’ve found that simply creating and binding a single VAO on startup, and setting VertexAttribPointers and drawing with VBOs directly before each draw call gives me the behavior I want:

// do render

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	
GLUseShader(&WorldShader);

glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 9*sizeof(float), (void *)(0));
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 9*sizeof(float), (void *)(3*sizeof(float)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 9*sizeof(float), (void *)(7*sizeof(float)));
glEnableVertexAttribArray(2);
glDrawArrays(GL_TRIANGLES, 0, 3);

glBindBuffer(GL_ARRAY_BUFFER, VBO2);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 9*sizeof(float), (void *)(0));
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 9*sizeof(float), (void *)(3*sizeof(float)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 9*sizeof(float), (void *)(7*sizeof(float)));
glEnableVertexAttribArray(2);
glDrawArrays(GL_TRIANGLES, 0, 3);

But isn’t that the whole point of VAOs? To not have to run this many calls to glVertexAttribPointer and the like every time you want to draw new objects? Putting those same glBindBuffer and VertexAttrib calls between VAO binds on init (like in my previous post) and just binding VAOs for drawing instead leads to only my second object being drawn. Am I using them incorrectly? It seems really straightforward.

True, you have a single shader. I got puzzled by your snaps… You should send uniforms to currently bound shaders so not before calling to glUseShader (there we can believe you are sending uniforms to a previously used one).

You are right, you should not reset the pointers once the VAO has been created.
I checked your code once again. It also seems that you don’t bind your VAO before binding the VBO when setting the data. You should:


glGenBuffers(1, &VAO);
    GLuint VAO2;
    glGenBuffers(1, &VAO2);
 
    // vbo
    r32 Verts[] = {
	-1.0f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.5f, 0.0f,
	-0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f,
	-1.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f,
    };
    r32 Verts2[] = {
	1.0f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.5f, 0.0f,
	1.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f,
	0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f,
    };
 
    GLuint VBO;
    glGenBuffers(1, &VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);

If this is not enough, you can try to check any OpenGL errors. You can also try to follow a tutorial. The first english one I just found is here.

Well don’t I feel foolish…

Thank you for the replies. Make sure you’re actually generating vertex array objects and not buffer objects when you want to work with VAOs!

glGenBuffers(1, &VAO);

should have been

glGenVertexArrays(1, &VAO);

I really don’t know how I missed this after staring at this code for a couple of days now. Is there a way to mark this as solved?

Right. What is looking weird is that it worked with a single VAO… Which made me focus on this.

AFAIK, no.