Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 6 of 6

Thread: [OpenGL and C++] Problems with Mesh class

  1. #1
    Junior Member Newbie
    Join Date
    Jul 2017
    Posts
    7

    [OpenGL and C++] Problems with Mesh class

    Hi all!

    This is my first post on the forum
    I am a PhD student in Physics, passionate in videogames, and I am trying to experiment a bit with OpenGL and C++ to build from scratch a very basic and naive ''game engine'' for some very small application.
    After managing to write correctly working shaders and draw a triangle and rotate it in space in the simplest possible way, I wanted to start to build a class framework to automatize some of the procedures.

    For instance, I wrote the following class for meshes to be drawn on screen:
    Code :
    class Mesh
    {
        private:
            int Nv;
            GLfloat *Positions;
            GLfloat *Colors;
     
            bool OnDraw;
     
        protected:
            GLuint vao;
            GLuint vbo;
     
        public:
            //Constructors
            Mesh(void);
            Mesh(int nv);
            Mesh(int nv, GLfloat positions[][4], GLfloat colors[][4]);
     
            //Set methods
            void SetPositions(GLfloat positions[][4]);
            void SetColors(GLfloat colors[][4]);
            void setOnDraw(bool onDraw);
     
            //Get methods
            bool getOnDraw(void);
     
            //Methods to vary positions and colors
     
            //Methods to output positions and colors
            void PrintPositions(void);
            void PrintColors(void);
     
            //Drawing methods
            void Initialize(void);
            void Draw(void);
            void Update(void);
     
            //Destructor
            ~Mesh(void);
    };

    whose these are the full declarations of the interesting methods:

    Code :
    Mesh::Mesh(int nv, GLfloat positions[][4], GLfloat colors[][4])
    {
        int i, j;
     
        //Set the number of vertices of the mesh
        this->Nv = nv;
     
        //And consequently allocate the memory for the positions and the colors
        //For the positions
        if((this->Positions = (GLfloat*)std::malloc(this->Nv * 4 * sizeof(GLfloat))) == NULL)
        {
            printf("Error allocating the memory for the vertices' position of the mesh, program will be arrested.\n");
            exit(EXIT_FAILURE);
        }
        //And for the colors
        if((this->Colors = (GLfloat*)std::malloc(this->Nv * 4 * sizeof(GLfloat))) == NULL)
        {
            printf("Error allocating the memory for the vertices' position of the mesh, program will be arrested.\n");
            exit(EXIT_FAILURE);
        }
     
     
        //Then, set the positions and the colors
        for(i=0;i<this->Nv;i++)
        {
            for(j=0;j<4;j++)
            {
                this->Positions[4*i+j] = positions[i][j];
                this->Colors[4*i+j] = colors[i][j];
            }
        }
     
     
        //And set the mesh not to be drawn
        OnDraw = false;
    }
     
     
     
     
    void Mesh::Initialize(void)
    {
        GLuint VertexPosition, VertexColor;
     
     
        //Generate the vertex array object
        glGenVertexArrays(1, &(this->vao));
        //And select it
        glBindVertexArray(this->vao);
     
        //Then generate the buffer for the verteces' data
        glGenBuffers(1, &(this->vbo));
        //And select it
        glBindBuffer(GL_ARRAY_BUFFER, this->vbo);
     
     
        //Let's then allocate in the buffer the memory for the data
        glBufferData(GL_ARRAY_BUFFER, ((this->Nv * 4 * sizeof(GLfloat)) + (this->Nv * 4 * sizeof(GLfloat))), NULL, GL_STATIC_DRAW);
        //And send the data to the buffer
        glBufferSubData(GL_ARRAY_BUFFER, 0, (this->Nv * 4 * sizeof(GLfloat)), this->Positions);
        glBufferSubData(GL_ARRAY_BUFFER, (this->Nv * 4 * sizeof(GLfloat)), (this->Nv * 4 * sizeof(GLfloat)), this->Colors);
     
     
        //Then, associate shader variables with buffer's positions
        //For vertex positions
        VertexPosition = glGetAttribLocation(ShaderProgram, "vPosition");
        glEnableVertexAttribArray(VertexPosition);
        glVertexAttribPointer(VertexPosition, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
     
        //And vertex colors
        VertexColor = glGetAttribLocation(ShaderProgram, "vColor");
        glEnableVertexAttribArray(VertexColor);
        glVertexAttribPointer(VertexColor, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET((this->Nv * 4 * sizeof(GLfloat))));
     
     
        //Then, unset the vertex array object and vertex buffer objects
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glBindVertexArray(0);
     
     
        //In the end, set this mesh to be drawn
        OnDraw = true;
    }
     
     
     
     
    void Mesh::Draw(void)
    {
        //Select the vertex array of the mesh
        glBindVertexArray(this->vao);
     
        //Draw the data stored in this vertex array
        glDrawArrays(GL_TRIANGLES, 0, this->Nv);
     
        //And unbind the vertex array object
        glBindVertexArray(0);
    }
     
     
     
     
    void Mesh::Update(void)
    {
        //Select the mesh's vertex array object
        glBindVertexArray(this->vao);
     
     
        //Select the mesh's vertex buffer object
        glBindBuffer(GL_ARRAY_BUFFER, this->vbo);
     
     
        //And send the updated data to the buffer
        glBufferSubData(GL_ARRAY_BUFFER, 0, (this->Nv * 4 * sizeof(GLfloat)), this->Positions);
        glBufferSubData(GL_ARRAY_BUFFER, (this->Nv * 4 * sizeof(GLfloat)), (this->Nv * 4 * sizeof(GLfloat)), this->Colors);
     
     
        //And unbind the vertex array object and vertex buffer object
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glBindVertexArray(0);
    }

    So, the idea of the class is that after having instanced an object of the class, having specified the positions and colors of the vertices, calling its Initialize() method a vertex array object and vertex buffer object for the mesh are created, and the data of the vertices are sent to the correct buffers. Then, by calling the Draw() method (typically in the onDisplay callback) the mesh is drawn on the screen. The method Update allows to change the data about the vertices in the buffer after having changed the positions and colors of the mesh's colors.
    If I just represent one single mesh with this method, it correctly works. However, as soon as I try to create more meshes, I get weird behaviours that I do not fully understand. Here they are.


    A) If I try to create a std::vector of Meshes in the main.cpp file of the OpenGL application, adding (for example) two meshes and initializing them with the following code:

    Code :
    //Initialize the first (coloured) triangle
    GLfloat MyTriangle_Positions[3][4] = {{1.f,-1.f,-0.5f,1.f}, {1.f,1.f,-0.5f,1.f}, {1.f,0.f,0.5f,1.f}};
    GLfloat MyTriangle_Colors[3][4] = {{1.f,0.f,0.f,1.f}, {0.f,1.f,0.f,1.f}, {0.f,0.f,1.f,1.f}};
    Meshes.push_back(Mesh(3, MyTriangle_Positions, MyTriangle_Colors));
    Meshes[0].Initialize();
     
    //Initialize the second (white) triangle
    GLfloat MyTriangle_Positions2[3][4] = {{-1.f,-1.f,-0.5f,1.f}, {-1.f,1.f,-0.5f,1.f}, {-1.f,0.f,0.5f,1.f}};
    GLfloat MyTriangle_Colors2[3][4] = {{1.f,1.f,1.f,1.f}, {1.f,1.f,1.f,1.f}, {1.f,1.f,1.f,1.f}};
    Meshes.push_back(Mesh(3, MyTriangle_Positions2, MyTriangle_Colors2));
    Meshes[1].Initialize();

    and then I draw them on screen with the following code in the onDisplay callback:

    Code :
    for(int i=0;i<Meshes.size();i++)
    {
        Meshes[i].Draw();
    }

    only the second one of the declared meshes (the white one) is represented, and both of the mesh objects have vao (the vertex array object index) equal to one (so I guess that somehow what is happening is that I use the same vertex array object for both, and so when initializing the second one I overwrite the vertex data of the first one and I only represent the second one).
    However, if I initialize them with the following code

    Code :
    //Initialize the first (coloured) triangle
    GLfloat MyTriangle_Positions[3][4] = {{1.f,-1.f,-0.5f,1.f}, {1.f,1.f,-0.5f,1.f}, {1.f,0.f,0.5f,1.f}};
    GLfloat MyTriangle_Colors[3][4] = {{1.f,0.f,0.f,1.f}, {0.f,1.f,0.f,1.f}, {0.f,0.f,1.f,1.f}};
    Meshes.push_back(Mesh(3, MyTriangle_Positions, MyTriangle_Colors));
     
    //Initialize the second (white) triangle
    GLfloat MyTriangle_Positions2[3][4] = {{-1.f,-1.f,-0.5f,1.f}, {-1.f,1.f,-0.5f,1.f}, {-1.f,0.f,0.5f,1.f}};
    GLfloat MyTriangle_Colors2[3][4] = {{1.f,1.f,1.f,1.f}, {1.f,1.f,1.f,1.f}, {1.f,1.f,1.f,1.f}};
    Meshes.push_back(Mesh(3, MyTriangle_Positions2, MyTriangle_Colors2));
     
    Meshes[0].Initialize();
    Meshes[1].Initialize();

    both the meshes are perfectly represented :O Why is this happening?


    B) If instead of using a std::vector of meshes I just declare two spare meshes as:

    Code :
    Mesh1 = Mesh(3, MyTriangle_Positions, MyTriangle_Colors);
    Mesh1.Initialize();
    Mesh2 = Mesh(3, MyTriangle_Positions2, MyTriangle_Colors2);
    Mesh2.Initialize();

    and I draw them like this:

    Code :
    Mesh1.Draw();
    Mesh2.Draw();

    both the meshes are displayed. However, no matter how I rotate the camera, and which is the relative position of the meshes one with respect to the other and with respect to the camera, the Mesh2 is always displayed on top of the Mesh1. If I draw them in inverted order, namely with the code:

    Code :
    Mesh2.Draw();
    Mesh1.Draw();

    the Mesh1 is always represented on top of mesh 1.


    So, in the end, I would really like not only to solve this problems, but to really understand where they originate. Can you help me guys?
    For instance, these are the very basic vertex and fragment shaders I am using:

    - Vertex shader:
    Code :
    # version 410
     
    uniform mat4 ProjectionMatrix;
    uniform mat4 ModelViewMatrix;
    in vec4 vPosition;
    in vec4 vColor;
     
    out vec4 color;
     
    void main()
    {
        color = vColor;
        //gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * vPosition;
        gl_Position = ProjectionMatrix * ModelViewMatrix * vPosition;
    }

    - Fragment shader:
    Code :
    # version 410
     
    in vec4 color;
     
    out vec4 fColor;
     
    void main()
    {
        fColor = color;
    }
    Last edited by Charogne; 07-26-2017 at 12:52 AM.

  2. #2
    Member Regular Contributor
    Join Date
    Jul 2012
    Posts
    420
    For A, try to store pointers to your meshes in the std vector.
    For B, enable depth testing in your OpenGL initialization function.

  3. #3
    Junior Member Newbie
    Join Date
    Jul 2017
    Posts
    7
    Quote Originally Posted by Silence View Post
    For A, try to store pointers to your meshes in the std vector.
    For B, enable depth testing in your OpenGL initialization function.
    Thanks a lot for your answer!
    Your solution for A indeed worked But could you be so gentle to also give me an idea of which was the problem, or some reference for it? Thanks in advance

    However, I have not solved the B problem yet. Indeed, if - just before initializing the meshes and starting the GL main loop - I use the code
    Code :
    glEnable(GL_DEPTH_TEST)
    I have the exact same problem

  4. #4
    Junior Member Newbie
    Join Date
    Jul 2017
    Posts
    7
    Quote Originally Posted by Silence View Post
    For A, try to store pointers to your meshes in the std vector.
    For B, enable depth testing in your OpenGL initialization function.
    Googling a bit I found a solution. It works as soon as I add the option GLUT_DEPTH in glut initialization.

  5. #5
    Member Regular Contributor
    Join Date
    Jul 2012
    Posts
    420
    Quote Originally Posted by Charogne View Post
    But could you be so gentle to also give me an idea of which was the problem, or some reference for it?
    I simply guessed that you were expecting to play directly with the variables in the vector while in fact you were working with a copy (returned by a function or so), at some points of your code. This can be a common issue with C++. Using pointers in common C++ containers will avoid such issues.

  6. #6
    Junior Member Newbie
    Join Date
    Jul 2017
    Posts
    7
    Okay
    Thanks a lot for your help!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •