Search code examples
c++qtopenglwavefront

Black window when render obj file in opengl


I used opengl in qt5 on ubuntu 18.4, i wanted to load a simple cube(store in an .obj file) and render it. I followed the tutorial here http://www.opengl-tutorial.org/beginners-tutorials/tutorial-7-model-loading/, but i got a black window at last. Here is my code, thank you very much:

myopengl.hpp

class MyOpenGL : public QOpenGLWidget, protected QOpenGLFunctions
{
public:
MyOpenGL(const QString& obj_file);

protected:
    virtual void initializeGL() Q_DECL_OVERRIDE;
    virtual void paintGL() Q_DECL_OVERRIDE;
    virtual void resizeGL(int width, int height) Q_DECL_OVERRIDE;
    void CheckGLerror();

private:
    std::vector< glm::vec3 > vertices;
    std::vector< glm::vec2 > uvs;
    std::vector< glm::vec3 > normals;

/*  Render data  */
    GLuint VAO, VBO, EBO;
};

myopengl.cpp

MyOpenGL ::MyOpenGL (const QString& obj_file) :
VAO(0),
VBO(0),
EBO(0)
{
    std::vector< unsigned int > vertex_indices, uv_indices, normal_indices;
    std::vector< glm::vec3 > temp_vertices;
    std::vector< glm::vec2 > temp_uvs;
    std::vector< glm::vec3 > temp_normals;

//parse obj file
QFile file(obj_file);
file.open(QFile::ReadOnly | QFile::Text);
QTextStream in(&file);
while(!in.atEnd()) {
    QString line = in.readLine();
    QStringList list = line.replace(",","").split(' ', QString::SkipEmptyParts);
    if (list.size() >= 3) {
        if (list.at(0) == "v") {  //veertex
            bool ok1, ok2, ok3;
            float v1 = list.at(1).toFloat(&ok1);
            float v2 = list.at(2).toFloat(&ok2);
            float v3 = list.at(3).toFloat(&ok3);
            if (ok1 && ok2 && ok3) {
                glm::vec3 vertex;
                vertex.x = v1;
                vertex.y = v2;
                vertex.z = v3;
                temp_vertices.push_back(vertex);
            }
        } else if (list.at(0) == "vn") {
            bool ok1, ok2, ok3;
            float v1 = list.at(1).toFloat(&ok1);
            float v2 = list.at(2).toFloat(&ok2);
            float v3 = list.at(3).toFloat(&ok3);
            if (ok1 && ok2 && ok3) {
                glm::vec3 normal;
                normal.x = v1;
                normal.y = v2;
                normal.z = v3;
                temp_normals.push_back(normal);
            }
        } else if (list.at(0) == "vt") {
            bool ok1, ok2;
            float v1 = list.at(1).toFloat(&ok1);
            float v2 = list.at(2).toFloat(&ok2);
            if (ok1 && ok2) {
                glm::vec2 uv;
                uv.x = v1;
                uv.y = v2;
                temp_uvs.push_back(uv);
            }
        } else if (list.at(0) == "f") {
            bool f_ok1, f_ok2, f_ok3;
            bool t_ok1, t_ok2, t_ok3;
            bool n_ok1, n_ok2, n_ok3;
            unsigned int v_index1, v_index2, v_index3;
            unsigned int t_index1, t_index2, t_index3;
            unsigned int n_index1, n_index2, n_index3;
            QStringList f_list = list.at(1).split('/');
            if (f_list.size() >= 3) {
                v_index1 = f_list.at(0).toUInt(&f_ok1);
                if (f_ok1) {
                    v_index1 -= 1;
                }
                t_index1 = f_list.at(1).toUInt(&t_ok1);
                if (t_ok1) {
                    t_index1 -= 1;
                }
                n_index1 = f_list.at(2).toUInt(&n_ok1);
                if (n_ok1) {
                    n_index1 -= 1;
                }
            }
            f_list = list.at(2).split('/');
            if (f_list.size() >= 3) {
                v_index2 = f_list.at(0).toUInt(&f_ok2);
                if (f_ok2) {
                    v_index2 -= 1;
                }
                t_index2 = f_list.at(1).toUInt(&t_ok2);
                if (t_ok2) {
                    t_index2 -= 1;
                }
                n_index2 = f_list.at(2).toUInt(&n_ok2);
                if (n_ok2) {
                    n_index2 -= 1;
                }
            }
            f_list = list.at(3).split('/');
            if (f_list.size() >= 3) {
                v_index3 = f_list.at(0).toUInt(&f_ok3);
                if (f_ok3) {
                    v_index3 -= 1;
                }
                t_index3 = f_list.at(1).toUInt(&t_ok3);
                if (t_ok3) {
                    t_index3 -= 1;
                }
                n_index3 = f_list.at(2).toUInt(&n_ok3);
                if (n_ok3) {
                    n_index3 -= 1;
                }
            }
            if (f_ok1 && f_ok2 && f_ok3 && n_ok1 && n_ok2 && n_ok3
                    && t_ok1 && t_ok2 && t_ok3) {
                vertex_indices.push_back(v_index1);
                vertex_indices.push_back(v_index2);
                vertex_indices.push_back(v_index3);

                uv_indices.push_back(t_index1);
                uv_indices.push_back(t_index2);
                uv_indices.push_back(t_index3);

                normal_indices.push_back(n_index1);
                normal_indices.push_back(n_index2);
                normal_indices.push_back(n_index3);
            }
        }

    }
}
file.close();

for (unsigned int i = 0; i < vertex_indices.size(); ++i) {
    glm::vec3 vertex = temp_vertices.at(vertex_indices.at(i));
    vertices.push_back(vertex);
}
for (unsigned int i = 0; i < uv_indices.size(); ++i) {
    glm::vec2 uv = temp_uvs.at(uv_indices.at(i));
    uvs.push_back(uv);
}
for (unsigned int i = 0; i < normal_indices.size(); ++i) {
    glm::vec3 normal = temp_normals.at(normal_indices.at(i));
    normals.push_back(normal);
}
}

void MyOpenGL::initializeGL()
{
    initializeOpenGLFunctions();
    glClearColor(0.0,0.0,0.0,1);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_DEPTH_TEST);
    glDisable(GL_CULL_FACE);
    glEnable(GL_LIGHT0);

    glewExperimental = GL_TRUE;
    GLenum status = glewInit();
    if (status != GLEW_OK)
    {
        glfwTerminate();
        std::system("pause");
        return;
    }
    glGenVertexArrays(1, &this->VAO);
    glBindVertexArray(this->VAO);
    glGenBuffers(1, &this->VBO);
    glBindBuffer(GL_ARRAY_BUFFER, this->VBO);
    glBufferData(GL_ARRAY_BUFFER, this->vertices.size() * sizeof(glm::vec3), &this->vertices[0], GL_STATIC_DRAW);
    glBindVertexArray(0);
}

void MyOpenGL::resizeGL(int width, int height)
{
    glViewport(0,0,width,height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-width/2,width/2,-height/2,height/2,-1,1);
    glMatrixMode(GL_MODELVIEW);
}

void MyOpenGL::paintGL()
{
    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, this->VBO);
    glDrawArrays(GL_TRIANGLES, 0, vertices.size());
    glDisableVertexAttribArray(0);

}

Solution

  • You have to define an array of generic vertex attribute data by glVertexAttribPointer.

    Note, the vertex buffer object is only a data store for the vertex data. But you have to specify how to "use" them. The specification and states of the vertex attributes are stored in the vertex array object. It is sufficient to bind the vertex array object when you want to draw the mesh:

    specification:

    glBindVertexArray(this->VAO);
    glBindBuffer(GL_ARRAY_BUFFER, this->VBO);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
    

    draw:

    glBindVertexArray(this->VAO);
    glDrawArrays(GL_TRIANGLES, 0, vertices.size());
    glBindVertexArray(0);
    

    Extension:

    Is it essential to use vertex shader and fragment shader? I didn't use them for current.

    If you don't have a shader, then you have to use the Fixed Function Pipeline and to define the fixed function attributes, by glVertexPointer respectively glEnableClientState( GL_VERTEX_ARRAY ).
    But since you only use one attribute, the vertex coordiante with attribute index 0, you can still define the attribute by glVertexAttribPointer and glEnableVertexAttribArray.
    See What are the Attribute locations for fixed function pipeline in OpenGL 4.0++ core profile?

    Note, in this case you have to use a compatibility OpenGL Context.