在渲染多个对象时,在C ++中使用OpenGL时遇到困难

时间:2014-12-13 20:21:51

标签: 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有关,但我无法知道如何或在何处实施这一点我已经尝试了几种不同的方法。

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

2 个答案:

答案 0 :(得分:3)

您在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);的调用。

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

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

答案 1 :(得分:1)

如果不深入研究OpenGL的使用情况(@ratchetfreak在单独的答案中已经做过),你就会遇到一个非常基本的C ++问题。

您在Cube.cpp文件的开头声明了一堆变量:

Shader* shader;

GLuint tex;

GLuint shaderProgram, fragmentShader, vertexShader;

GLuint vbo, ebo;

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

使用这样声明的变量,您将只拥有这些值的单个副本,这些副本在Cube类的所有实例之间共享。例如,您的所有多维数据集将具有相同的位置,这是您创建的最后一个多维数据集之一,因为它们共享相同的xyz变量。位置。

您需要将这些变量定义为类成员,以便每个Cube实例具有单独的值。这意味着他们需要进入头文件,通常是在类的私有部分。例如:

class Cube {
public:
    // Declaration of constructor, methods, etc.

private:
    GLfloat x, y, z;
};

您可能希望为变量使用更具描述性的名称。