How can I draw two objects? (Newbie)

Hello guys, basically I am trying to draw a background and a player in front of it. I don’t know whether I should create a new VBO or VAO for each different object. Here’s what I have so far:

In my Sprite Class: (This is currently only drawing the background, which is two triangles)

Sprite::Sprite(Vertex* vertices, unsigned int numVertices)
{
	// Create Shaders 
	m_Program = m_Shader.CreateProgram("VShader.vs", "FShader.fs");

	m_NumVertices = numVertices;
	
	GLubyte m_Background[] = { 0, 1, 3, 1, 2, 3 };

	glGenVertexArrays(1, &m_VertexArrayObject);
	glBindVertexArray(m_VertexArrayObject);

	glGenBuffers(1, &m_VertexBufferObject);
	glBindBuffer(GL_ARRAY_BUFFER, m_VertexBufferObject);
	glBufferData(GL_ARRAY_BUFFER, m_NumVertices * sizeof(vertices[0]), vertices, GL_STATIC_DRAW);

	glGenBuffers(1, &m_ElementBufferObject);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ElementBufferObject);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(m_Background), m_Background, GL_STATIC_DRAW);

	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);
	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
	
	glEnableVertexAttribArray(0);
	glEnableVertexAttribArray(1);
}

In the main header file

// Background
Vertex Position[] =
{
	Vertex(glm::vec3(1.0f, 1.0f, 0.0f), glm::vec2(0.0f, 0.0f)),
	Vertex(glm::vec3(1.0f, -1.0f, 0.0f), glm::vec2(0.0f, 1.0f)),
	Vertex(glm::vec3(-1.0f, -1.0f, 0.0f), glm::vec2(1.0f, 1.0f)),
	Vertex(glm::vec3(-1.0f, 1.0f, 0.0f), glm::vec2(1.0f, 0.0f))
};
// Player
Vertex Position2[] =
{
	Vertex(glm::vec3(0.5f, 0.5f, 0.0f), glm::vec2(0.0f, 0.0f)),
        Vertex(glm::vec3(0.5f, -0.5f, 0.0f), glm::vec2(0.0f, 1.0f)),
	Vertex(glm::vec3(-0.5f, -0.5f, 0.0f), glm::vec2(1.0f, 1.0f)),
	Vertex(glm::vec3(-0.5f, 0.5f, 0.0f), glm::vec2(1.0f, 0.0f))
};

void Render()
{
	CSprite Background(Position, sizeof(Position) / sizeof(Position[0]));
	CSprite Player(Position2, sizeof(Position2) / sizeof(Position2[0]));
	Background.Draw();
	Player.Draw();
}

The result is just a player (that’s really just two triangles for now) but no background behind.

How can I make it so that I can draw more than one object on the screen?

Thank you.

usualy its done issuing 2 times a drawcall, like “glDrawArrays(…)” or “glDrawElements(…)”, with different arguments and / or transformation matrices applied. you are far better of if you remove the drawing part out of the “sprite” class, and put it somewhere else where you draw everything at once, for example in a “renderer” class. that means also that you can share the same resources (buffer / vertexarray / program) for different sprites

Hey John, thank you for your answer.

So, here’s what I have managed so far:

 void Sprite::DrawGeometry(Vertex* Vertices, unsigned int numOfVertices)
 {
    GLubyte m_Background[] = { 0, 1, 3, 1, 2, 3 };

    glGenVertexArrays(1, &m_BackgroundVAO);
    glBindVertexArray(m_BackgroundVAO);

    glGenBuffers(1, &m_BackgroundVBO);
    glBindBuffer(GL_ARRAY_BUFFER, m_BackgroundVBO);
    glBufferData(GL_ARRAY_BUFFER, numOfVertices * sizeof(Vertices[0]), Vertices, GL_STATIC_DRAW);

    glGenBuffers(1, &m_BackgroundEBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_BackgroundEBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(m_Background), m_Background, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));

    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);

    glGenTextures(1, &m_Textures);
    glBindTexture(GL_TEXTURE_2D, m_Textures);

    // Texture Wrapping
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    // Texturing etc...

    SOIL_free_image_data(image);
    glBindTexture(GL_TEXTURE_2D, 0);
}
void Sprite::DrawGeometryPlayer(Vertex* Vertices, unsigned int numOfVertices)
{
    GLubyte m_Player[] = { 0, 1, 3, 1, 2, 3 };

    glGenVertexArrays(1, &m_PlayerVAO);
    glBindVertexArray(m_PlayerVAO);

    glGenBuffers(1, &m_PlayerVBO);
    glBindBuffer(GL_ARRAY_BUFFER, m_PlayerVBO);
    glBufferData(GL_ARRAY_BUFFER, numOfVertices * sizeof(Vertices[0]), Vertices, GL_STATIC_DRAW);

    glGenBuffers(1, &m_PlayerEBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_PlayerEBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(m_Player), m_Player, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));

    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);

    glGenTextures(1, &m_Textures);
    glBindTexture(GL_TEXTURE_2D, m_Textures);

    // Texture etc....

    SOIL_free_image_data(image);
    glBindTexture(GL_TEXTURE_2D, 0);
}

void Sprite::Render()
{   
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glUseProgram(m_Program);

    // Player
    glBindVertexArray(m_PlayerVAO);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, m_Textures);
    glUniform1i(glGetUniformLocation(m_Program, "Texture1"), 0);

    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0);

    // Background 
    glBindVertexArray(m_BackgroundVAO);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, m_Textures);
    glUniform1i(glGetUniformLocation(m_Program, "Texture1"), 0);

    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0);

    glBindTexture(GL_TEXTURE_2D, 0);
    glBindVertexArray(0);

    glutSwapBuffers();
}

Result is just a player. If I call draw background first, then the result will be the background. This is frustrating… :frowning:

you only need to initialize once, you dont need to create the resources each frame again:

void Initialize()
{
// create 1 program, comipile shader + link program
// create vertexarray, vertexbuffer + fill vertexbuffer with all vertices
// store {vertexoffset, vertexcount} for each model
}

void Render(Scene& myscene)
{
glUseProgram()
glBindVertexArray()

for each (element in myscene)
{
mat4 transformation = element.GetModelToWorldTransformation();
// set uniform to this transformation
glDrawArrays(GL_TRIANGLES, …, …) with the arguments depending on what model they are using (which you’ve stored previously)
}

}

take a look at my examples:

another this is that you need to have glEnable(GL_DEPTH_TEST); called for a 3D scene, otherwise the most recent drawcall will overwrite previous once

[QUOTE=john_connor;1286512]you only need to initialize once, you dont need to create the resources each frame again:

void Initialize()
{
// create 1 program, comipile shader + link program
// create vertexarray, vertexbuffer + fill vertexbuffer with all vertices
// store {vertexoffset, vertexcount} for each model
}

void Render(Scene& myscene)
{
glUseProgram()
glBindVertexArray()

for each (element in myscene)
{
mat4 transformation = element.GetModelToWorldTransformation();
// set uniform to this transformation
glDrawArrays(GL_TRIANGLES, …, …) with the arguments depending on what model they are using (which you’ve stored previously)
}

}

take a look at my examples:

another this is that you need to have glEnable(GL_DEPTH_TEST); called for a 3D scene, otherwise the most recent drawcall will overwrite previous once[/QUOTE]

Fixed it thank you for the examples! Your work looks really nice. I hope I’ll be able to code like that soon. :slight_smile:

This is an useful example how to draw two objects with
different shaders (with solid colour and textured) in WebGL: https://jsfiddle.net/8Observer8/jnd0j6w0/

It is simple to port it in C++, because I ported it in C#/OpenTK