【问题标题】:How to draw multiple objects in OpenGL using multiple VAO and VBO?如何使用多个 VAO 和 VBO 在 OpenGL 中绘制多个对象?
【发布时间】:2019-07-02 03:53:05
【问题描述】:

我正在尝试使用多个 VAO 和 VBO 在 OpenGL 中渲染多个对象。要使用相同的顶点渲染多个对象,我已经完成了,但我想做的是为每个对象使用不同的顶点,例如绘制正方形和圆形。对于正方形,我只需要 6 个顶点,但对于圆形,我需要 360。 我在读取或创建着色器时出错。

这是顶点着色器:

#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;
}

片段着色器:

#version 330 core

layout(location = 0) out vec4 color;

uniform vec4 u_Color;

void main()
{
    color = u_Color;
}

VAO和VBO的生成和绑定

// 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);

以及渲染循环中的draw call:

    //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);
    }

我重复一遍,使用我已经完成的相同顶点绘制多个对象。我需要知道如何使用相同的顶点和片段着色器但顶点数不同来绘制多个对象。该项目很小,最多只能在 2D 中渲染 10 个对象。

【问题讨论】:

  • 您是否尝试绑定vao1,调用第一个glDrawArrays,然后绑定vao2,并再次调用glDrawArrays?您的绘图代码调用 glDrawArrays 两次,但不会在调用之间绑定不同的 VAO
  • @s_diaconu 如果您好心,能否分享一下您的VertexFormat 类型的实现细节?我是 OpenGL 的新手,并试图简单地画一个圆,你的着色器和前 8 行代码似乎能够完成。但是在不知道VertexObject 到底是什么的情况下,我无法效仿你的例子……而你的似乎是唯一一个甚至接近我需要的现代代码 sn-p。谢谢! :D

标签: c++ opengl vbo glm-math vao


【解决方案1】:

glDrawArrays等绘图命令处理并绘制当前绑定的Vertex Array Object中指定的通用顶点属性数据数组。

这意味着你需要在执行Draw调用之前绑定正确的顶点数组对象:

// [...]

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

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

【讨论】:

  • 我不知道我必须在渲染循环中调用glDrawArrays。它设法使它工作,但在渲染循环中只使用了一个 VAO 和两个 VBO。谢谢。
【解决方案2】:

@Kenny83 自从我接触OpenGL 已经有一段时间了,老实说,我不记得我是从哪里得到VertexFormat 的,但幸运的是我找到了带有代码的项目。我不知道如何将 sn-p 添加到评论中,我认为这甚至不可能,所以我将其添加为答案:

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

struct VertexFormat
{

    glm::vec3 position;

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

    VertexFormat()
    {

    }

};

希望对你有帮助。

【讨论】:

    猜你喜欢
    • 2020-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多