0
\$\begingroup\$

I want to create a class in c++ that loads a model with the obj format.The model gets generated from Blender(3D modeling program).When i try do draw something on the screen without the class(all the code is in main) it works fine.But somehow my class doesnt work.It only shows a black screen.Heres my code:

main.cpp

#include "global.h"

using namespace std;

int main()
{
    glewExperimental = GL_TRUE;
    glewInit();
    glViewport(0,0,800,800);
    mesh.loadMesh("models/1/cube.obj");
    shaders.push_back(Shader("shaders/default/default.vert", "shaders/default/default.frag"));

    while (window.isOpen())
    {
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
        while (window.pollEvent(Event))
        {
            if (Event.type == sf::Event::Closed)
                window.close();
        }
        mesh.draw(shaders[0]);
        window.display();
    }
    return 0;
}

vertex shader

layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;
layout (location = 2) in vec2 texCoord;

void main()
{
    gl_Position = vec4(position.x, position.y, position.z, 1.0f);
}

fragment shader

#version 330 core

out vec4 color;

void main()
{
    color = vec4(1.0,0.0,0.0,1.0);
}

As you can see i dont use the normals and the textures yet..all i want for now is to draw something red on the screen.

The shader class its a class that i dowloaded from learnopengl.com .It just uses OpenGL standard fuctions to create a shader.Since my program works when i put everything in main,the shader class is not the problem.

and now the mesh class mesh.h

#ifndef MESH_H
#define MESH_H

#include "Includes.h"
#include "Shader.h"

struct Vertex
{
    glm::vec3 position;
    glm::vec3 normal;
    glm::vec2 texCoords;
    Vertex(glm::vec3 p,glm::vec3 n,glm::vec2 t)
    {
        position=p;
        normal=n;
        texCoords=t;
    }
};

struct Texture
{
    GLuint id;
    string type;
    string path;
};

class Mesh
{
    public:
        void draw(Shader &shader);
        void loadMesh(const char* fileName);
        void loadMaterials(const char* fileName);
    private:
        GLuint VAO, VBO, EBO;
        vector<Vertex> vertex;
        vector<GLuint> indices;
        vector<Texture> texture;
        void setupMesh();
};
#endif // MESH_H

and mesh.cpp

void Mesh::loadMesh(const char* fileName)
{
    int i,nrObj=-1,nr=0,number,number1,number2,number3;
    char text[256],matName[256];

    ifstream fin(fileName);

    vector<string>line;
    vector<glm::vec3>position;
    vector<glm::vec3>normal;
    vector<glm::vec2>texCoord;

    while(!fin.eof())
    {
        fin.getline(text,256);
        line.push_back(text);
    }
    //loadMaterials(line[2].c_str());

    glm::vec3 v;
    glm::vec2 t;

    for(i=4;line[i][0]=='v'&& line[i][1]==' ';i++)
    {
        sscanf(line[i].c_str(),"v %f %f %f",&v.x,&v.y,&v.z);
        position.push_back(v);
    }
    for(;line[i][0]=='v'&& line[i][1]=='t';i++)
    {
        sscanf(line[i].c_str(),"vt %f %f",&t.x,&t.y);
        texCoord.push_back(t);
    }
    for(;line[i][0]=='v'&& line[i][1]=='n';i++)
    {
        sscanf(line[i].c_str(),"vn %f %f %f",&v.x,&v.y,&v.z);
        normal.push_back(v);
    }
    for(;i<line.size();i++)
    {
        if(line[i][0]=='u'&&line[i][1]=='s'&&line[i][2]=='e')
            sscanf(line[i].c_str(),"usemtl %s",&matName);
        i++;
        if(line[i][0]=='s'&&line[i][1]==' ')
            i++;
        for(i;line[i][0]=='f'&&line[i][1]==' ';i++)
        {
            indices.resize(indices.size()+3);
            sscanf(line[i].c_str(),"f %d/%d/%d %d/%d/%d %d/%d/%d %d/%d/%d",&number1,&number,&number,&number2,&number,&number,&number3,&number,&number);
            indices[nr*3]=number1-1;
            indices[nr*3+1]=number2-1;
            indices[nr*3+2]=number3-1;
            nr++;
        }
    }
    for(i=0;i<position.size();i++)
        vertex.push_back(Vertex(position[i],glm::vec3(0,0,0),glm::vec2(0,0)));
    setupMesh();
    fin.close();
}

void Mesh::loadMaterials(const char* fileName)
{

}

void Mesh::setupMesh()
{
    glGenVertexArrays(1, &this->VAO);
    glGenBuffers(1, &this->VBO);
    glGenBuffers(1, &this->EBO);

    glBindVertexArray(this->VAO);

    glBindBuffer(GL_ARRAY_BUFFER, this->VBO);
    glBufferData(GL_ARRAY_BUFFER, this->vertex.size() * sizeof(Vertex), &this->vertex[0], GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->indices.size() * sizeof(GLuint), &this->indices[0], GL_STATIC_DRAW);
    // Set the vertex attribute pointers
    // Vertex Positions
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)0);
    // Vertex Normals
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, normal));
    // Vertex Texture Coords
    glEnableVertexAttribArray(2);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, texCoords));

    glBindVertexArray(0);

}

void Mesh::draw(Shader &shader)
{
    shader.Use();
    glBindVertexArray(VAO);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);
}

I checked to see if my class reads corectly the obj file and it does. Pls tell me whats wrong.

\$\endgroup\$
  • \$\begingroup\$ There's a checkbox in blender, when you export the model, saying "Triangulate faces", did you enabled that? \$\endgroup\$ – Bálint Jan 30 '16 at 10:33
  • \$\begingroup\$ yes i did..the loading part of the model works fine \$\endgroup\$ – Robert Puscasu Jan 30 '16 at 11:01
  • \$\begingroup\$ you shouldn't double post @RobertPuscasu cf : gamedev.stackexchange.com/questions/115836/… \$\endgroup\$ – Guiroux Jan 30 '16 at 14:45
1
\$\begingroup\$

In your draw call:

void Mesh::draw(Shader &shader)
{
    shader.Use();
    glBindVertexArray(VAO);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);
}

You are only specifying 6 elements to draw, it should be

glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);

Unless you have hardcoded this on purpose if you are sure your model is only specifying 6 incides for testing purposes.

And by the way, you shouldn't actually store these:

vector<Vertex> vertex;
vector<GLuint> indices;

in your class members, once you setup your mesh the model data is copied into gpu memory there is no need to store them in your mesh object (which is in your ram). And you access this data via your VAO.

You can just create those std::vectors in your load mesh function and pass them as reference to your setup mesh function. After you called your setup mesh in the load mesh function, the load mesh function will end and the vectors will go out of scope and get automatically deleted.

glBufferData: https://www.opengl.org/sdk/docs/man/html/glBufferData.xhtml

data - Specifies a pointer to data that will be copied into the data store for initialization, or NULL if no data is to be copied.

However you will still need an:

GLuint indexCount;

member in your mesh class and store the indices.size() in it. And change draw elements to:

glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, 0);
\$\endgroup\$
0
\$\begingroup\$

I think you're missing a bind to your index buffer. It's been a while, but I believe binding the VertexArray only affects the vertex data, not the index data. If I remove the glBindBuffer(GL_ELEMEN_ARRAY_BUFFER...) from my code, i get a black screen.

glBindVertexArray(VAO);
**glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);**
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);

EDIT: I have to retract that statement. The ELEMENT_ARRAY_BUFFER should be part of the VAO state. However, on my Mac Book Pro late 2014, I have to bind my ELEMENT_ARRAY_BUFFER.

\$\endgroup\$
  • \$\begingroup\$ Index buffer isn't stored in an attribute list. You really need to bind it before the render. \$\endgroup\$ – Bálint Jan 30 '16 at 17:56
  • \$\begingroup\$ Actually, he does bind it glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->EBO); \$\endgroup\$ – Bálint Jan 30 '16 at 17:57
  • \$\begingroup\$ He doesn't bind it in the render function. Only the vertex array is bound. \$\endgroup\$ – vetroxl Jan 30 '16 at 19:25
  • \$\begingroup\$ You're right. My bad. But still, it isn't a part of the vao, it is outside of it. \$\endgroup\$ – Bálint Jan 30 '16 at 20:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.