简体   繁体   中英

How to draw multiple objects in OpenGL using multiple VAO and VBO?

I'm trying to render multiple objects in OpenGL using multiple VAO's and VBO's. To render multiple objects using the same vertices I've done it, but what I want to do is to use different vertices for each object, for example to draw a square and a circle. For a square I only need 6 vertices but for circle I need 360. I have error with reading or creating the shaders.

Here is the Vertex Shader:

#version 330 core

layout (location = 0) in vec4 position;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
    gl_Position = projection * view * model * position;
}

Fragment Shader:

#version 330 core

layout(location = 0) out vec4 color;

uniform vec4 u_Color;

void main()
{
    color = u_Color;
}

The VAO and VBO generating and binding

// Circle
std::vector<VertexFormat> vertices;

for (int i = 0; i < 360; i++)
{
    GLfloat angle = i * ((2.0f * 3.14159f) / 360);
    vertices.push_back(VertexFormat(glm::vec3(cos(angle) * 100.0f, sin(angle) * 100.0f, 0.0f)));
}

// Pipette object
std::vector<VertexFormat> pipetteVertices;
pipetteVertices.push_back(VertexFormat(glm::vec3(injPipette.x + 500.0f, injPipette.y + 500.0f, 0.0f))); // 0
pipetteVertices.push_back(VertexFormat(glm::vec3(injPipette.x + 700.0f, injPipette.y + 500.0f, 0.0f))); // 1
pipetteVertices.push_back(VertexFormat(glm::vec3(injPipette.x + 700.0f, injPipette.y + 700.0f, 0.0f))); // 2
pipetteVertices.push_back(VertexFormat(glm::vec3(injPipette.x + 500.0f, injPipette.y + 700.0f, 0.0f))); // 3
pipetteVertices.push_back(VertexFormat(glm::vec3(injPipette.x + 500.0f, injPipette.y + 500.0f, 0.0f)));
pipetteVertices.push_back(VertexFormat(glm::vec3(injPipette.x + 700.0f, injPipette.y + 700.0f, 0.0f)));

GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);

GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(VertexFormat) * 6, &pipetteVertices[0], GL_STATIC_DRAW);

//Position attribute
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexFormat), (GLvoid *)0);

GLuint vao2;
glGenVertexArrays(1, &vao2);
glBindVertexArray(vao2);

GLuint vbo2;
glGenBuffers(1, &vbo2);
glBindBuffer(GL_ARRAY_BUFFER, vbo2);
glBufferData(GL_ARRAY_BUFFER, sizeof(VertexFormat) * 360, &vertices[0], GL_STATIC_DRAW);

//Position attribute
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexFormat), (GLvoid *) 0);

glBindBuffer(GL_ARRAY_BUFFER, 0);

And the draw call in the rendering loop:

    //Get the uniform locations of model, view and projection matrices
    modelID = glGetUniformLocation(program, "model");
    viewID = glGetUniformLocation(program, "view");
    projectionID = glGetUniformLocation(program, "projection");

    //View transform
    glm::mat4 view = glm::lookAt(glm::vec3(0, 0, 2), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
    //Projection transform
    //glm::mat4 projection = glm::perspective(45.0f, (GLfloat)screenWidth / (GLfloat)screenHeight, 0.1f, 1000.0f);
    glm::mat4 projection = glm::ortho(0.0f, (GLfloat)screenWidth, 0.0f,  (GLfloat)screenHeight, 0.1f, 10.0f);

    {
        glUniformMatrix4fv(viewID, 1, GL_FALSE, glm::value_ptr(view));
        glUniformMatrix4fv(projectionID, 1, GL_FALSE, glm::value_ptr(projection));

        glm::mat4 translate = glm::translate(glm::mat4(1.0), glm::vec3(100.0f + move_x, 100.0f + move_y, 0.0f));
        glm::mat4 rotate = glm::rotate(glm::mat4(1.0), 0.0f, glm::vec3(0.0f, 0.0f, 1.0f));
        glm::mat4 scale = glm::scale(glm::mat4(1.0), glm::vec3(1.0f, 1.0f, 2.0f));

        glm::mat4 model = translate * rotate * scale;
        glUniformMatrix4fv(modelID, 1, GL_FALSE, glm::value_ptr(model));

        glUniform4f(color, 0.0f, 0.0f, 1.0f, 1.0f);

        //Render
        glDrawArrays(GL_TRIANGLE_FAN, 0, 360);
    }

    {
        glUniformMatrix4fv(viewID, 1, GL_FALSE, glm::value_ptr(view));
        glUniformMatrix4fv(projectionID, 1, GL_FALSE, glm::value_ptr(projection));

        glm::mat4 translate = glm::translate(glm::mat4(1.0), glm::vec3(300.0f + injPipette.x, 300.0f + injPipette.y, 0.0f));
        glm::mat4 rotate = glm::rotate(glm::mat4(1.0), 0.0f, glm::vec3(0.0f, 0.0f, 1.0f));
        glm::mat4 scale = glm::scale(glm::mat4(1.0), glm::vec3(1.0f, 1.0f, 2.0f));

        glm::mat4 model = translate * rotate * scale;
        glUniformMatrix4fv(modelID, 1, GL_FALSE, glm::value_ptr(model));

        glUniform4f(color, 1.0f, 0.0f, 0.0f, 0.5f);

        //Render
        glDrawArrays(GL_TRIANGLES, 0, 6);
    }

I repeat, to draw multiple objects using the same vertices I've done it. I need to know how to draw multiple objects using the same vertex and fragment shader but different number of vertices. The project is small, just rendering maximum 10 objects in 2D.

Drawing commands such as glDrawArrays process and draw the arrays of generic vertex attribute data specified in the currently bound Vertex Array Object .

This means that you need to bind the correct vertex array object before executing the Draw call:

// [...]

glBindVertexArray(vao2);
glDrawArrays(GL_TRIANGLE_FAN, 0, 360);
// [...]

glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, 6); 

@Kenny83 It's been a while since I touched OpenGL and honestly I don't remember from where I got the VertexFormat but thankfully I found the project with the code. I don't know how to add snippet to comment and I think it's not even possible so I added it as an answer:

#pragma once
#include "glm\glm.hpp"

struct VertexFormat
{

    glm::vec3 position;

    VertexFormat(const glm::vec3 &iPos)
    {
        position = iPos;
    }

    VertexFormat()
    {

    }

};

Hope it helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM