c++ - 在渲染多个对象时,在 C++ 中使用 OpenGL 有困难

标签 c++ opengl sdl

我在将多个立方体渲染到屏幕时遇到问题。我有一个立方体类,它设置立方体顶点并加载适当的着色器。发生的问题是,当我的类的多个实例是这样创建的:

Cube * cube = new Cube();
Cube * cube1 = new Cube();

然后我像这样初始化立方体对象:

cube->setPos(0, 0, 0);
cube->setType(Cube::Type::Green);
cube->createCube();

cube1->setPos(1, 0, 0);
cube1->setType(Cube::Type::Red);
cube1->createCube();

然后我在渲染方法中将立方体绘制到屏幕上,如下所示:

cube->draw();
cube1->draw();

我的立方体类如下所示:

包含“cube.h”

Shader* shader;

GLuint tex;

GLuint shaderProgram, fragmentShader, vertexShader;

GLuint vbo, ebo;

GLfloat x, y, z;
GLfloat r, g, b;

Cube::Cube() {
}

void Cube::setPos(GLfloat X, GLfloat Y, GLfloat Z) {
    x = X;
    y = Y;
    z = Z;
}

    void Cube::setType(Type type) {
    switch (type) {
        case Type::Red:
        r = 1.0f;
        g = 0.0f;
        b = 0.0f;
        break;

    case Type::Green:
        r = 0.0f;
        g = 1.0f;
        b = 0.0f;
        break;

    case Type::Blue:
        r = 0.0f;
        g = 1.0f;
        b = 0.0f;
        break;

    default:
        r = 0.0f;
        g = 0.0f;
        b = 0.0f;
        break;
}
}

Cube::~Cube() {
glDeleteProgram(shaderProgram);
glDeleteShader(fragmentShader);
glDeleteShader(vertexShader);

glDeleteBuffers(1, &ebo);
glDeleteBuffers(1, &vbo);
}

void Cube::createCube() {

createShader();

GLfloat vertices[] = {
        //X,    Y,     Z,    R,    G,    B
        x - 0.5f, y - 0.5f, z - 0.5f, r, g, b,      // 0
        x + 0.5f, y - 0.5f, z - 0.5f, r, g, b,      // 1
        x + 0.5f, y + 0.5f, z - 0.5f, r, g, b,      // 2
        x - 0.5f, y + 0.5f, z - 0.5f, r, g, b,      // 3

        x - 0.5f, y - 0.5f, z + 0.5f, r, g, b,      // 4
        x + 0.5f, y - 0.5f, z + 0.5f, r, g, b,      // 5
        x + 0.5f, y + 0.5f, z + 0.5f, r, g, b,      // 6
        x - 0.5f, y + 0.5f, z + 0.5f, r, g, b,      // 7
 };

GLuint elements[] = {
        0, 1, 2, 2, 3, 0,
        4, 5, 6, 6, 7, 4,
        7, 3, 0, 0, 4, 7,
        6, 2, 1, 1, 5, 6,
        0, 1, 5, 5, 4, 0,
        3, 2, 6, 6, 7, 3
};

// Create a Vertex Buffer Object and copy the vertex data to it
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);

glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

// Create an element array
glGenBuffers(1, &ebo);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements,
GL_STATIC_DRAW);

glBindFragDataLocation(shaderProgram, 0, "outColor");
glLinkProgram(shaderProgram);
glUseProgram(shaderProgram);

// Specify the layout of the vertex data
GLint posAttrib = glGetAttribLocation(shaderProgram, "position");
glEnableVertexAttribArray(posAttrib);
glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), 0);

GLint colAttrib = glGetAttribLocation(shaderProgram, "color");
glEnableVertexAttribArray(colAttrib);
glVertexAttribPointer(colAttrib, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat),
        (void*) (3 * sizeof(GLfloat)));
}

void Cube::update() {
// Calculate transformation
glm::mat4 trans;
trans = glm::rotate(trans, (float) clock() / (float) CLOCKS_PER_SEC * 1.0f,
        glm::vec3(0.0f, 0.0f, 1.0f));

GLint uniTrans = glGetUniformLocation(shaderProgram, "model");
glUniformMatrix4fv(uniTrans, 1, GL_FALSE, glm::value_ptr(trans));
glUniformMatrix4fv(uniTrans, 1, GL_FALSE, glm::value_ptr(trans));

glm::mat4 view = glm::lookAt(glm::vec3(1.2f, 1.2f, 1.2f), glm::vec3(0.0f, 0.0f, 0.0f),
        glm::vec3(0.0f, 0.0f, 1.0f));
GLint uniView = glGetUniformLocation(shaderProgram, "view");
glUniformMatrix4fv(uniView, 1, GL_FALSE, glm::value_ptr(view));

glm::mat4 proj = glm::perspective(45.0f, 800.0f / 600.0f, 1.0f, 10.0f);
GLint uniProj = glGetUniformLocation(shaderProgram, "proj");
glUniformMatrix4fv(uniProj, 1, GL_FALSE, glm::value_ptr(proj));
}

void Cube::draw() {
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
}


void Cube::createShader() {
// load vertex shader source
const GLchar* vertexSource = shader->fileRead("src/shaders/vertex.vs");
if (vertexSource != NULL) std::cout << "vertexSource" << std::endl;

// load fragment shader source
const GLchar* fragmentSource = shader->fileRead("src/shaders/fragment.fs");
if (fragmentSource != NULL) std::cout << "fragmentSource" << std::endl;

// Create and compile the vertex shader
vertexShader = shader->compileShader(vertexSource, GL_VERTEX_SHADER);

// Create and compile the fragment shader
fragmentShader =  shader->compileShader(fragmentSource, GL_FRAGMENT_SHADER);

// Link the vertex and fragment shader into a shader program
shaderProgram = shader->compileProgram(vertexShader, fragmentShader);
}

长话短说。我创建并初始化了两个立方体。两者都用代码绘制到屏幕上,但当编译程序运行时,屏幕上只显示第二个立方体。 我的完整代码的拷贝可从 My GitHub 获得。 ,如果您想克隆和构建它。

我花了几个小时来寻找解决此问题的方法,但做不到,所以我正在联系社区。我感觉这与需要 VAO 有关,但我不知道如何或在何处实现它,我已经尝试了几种不同的方法。

非常感谢任何帮助。提前致谢!

最佳答案

您在 create 函数中设置的任何状态都不会在另一次调用之后持续存在。

首先,您应该将值移动到多维数据集类的成员。

然后在创建中你应该创建并使用一个 vao:

glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);

在指定顶点布局之前。

然后在绘制调用期间:

void Cube::draw() {
    glUseProgram(shaderProgram);
    glBindVertexArray(vao);
    glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
}

在更新中添加对 glUseProgram(shaderProgram); 的调用。

然而,使用单个静态程序然后在 uniform 中加载模型矩阵会更高效;

void Cube::draw() {
    //assume program is already bound and non-cube-specific uniforms are already set
    glBindVertexArray(vao);
    glUniformMatrix4fv(uniTrans, 1, GL_FALSE, glm::value_ptr(trans));//kept in a field
    glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
}

关于c++ - 在渲染多个对象时,在 C++ 中使用 OpenGL 有困难,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27463242/

相关文章:

c++ - 元组 vector 和 initializer_list

c++ - 如何在 Clang 中获取 NamedDecl 的错位名称?

haskell - 在屏幕上渲染纹理

android - 为 Android 构建 SDL 混音器

c++ - Visual Studio(用于 SDL)中的 vcproj 文件在哪里?

c++ - 从专门的模板结构/类继承

c++ - 如果参数采用引用,在函数参数中传递 *this 会导致内存泄漏吗?

c++ - Bullet Physics - 从网格创建 ShapeHull

animation - Assimp 动画骨骼变换

c++ - main 已经在 main.obj 中定义