0
\$\begingroup\$

I have a terrain class like so:

class Terrian  {
    public:
        Terrian(int width, int height);
        virtual ~Terrian();

        GLuint get_vertexbuffer();
        GLuint get_colorbuffer();
        GLuint get_elementbuffer();
    protected:
    private:
        Vector3 **terrian_vertices;
        Color **terrian_colors;
        GLushort *terrian_elements;

        GLuint vbo_terrian_vertices;
        GLuint vbo_terrian_colors;
        GLuint ibo_terrian_elements;

        GLint width;
        GLint height;

        void construct_vertices();
        void construct_buffers();
        void construct_elements();
};

My problem is that the terrain simply never shows, I don't know if I am doing anything incorrectly but here is how the vertices are generated (I commented out the actual code and create a box instead).

void Terrian::construct_vertices()  {
    terrian_vertices = new Vector3*[8];
    terrian_colors = new Color*[8];

    /* actual code ...*/

    GLfloat cube_vertices[] =  {
        -1.0, -1.0,  1.0,
         1.0, -1.0,  1.0,
         1.0,  1.0,  1.0,
        -1.0,  1.0,  1.0,
        // back
        -1.0, -1.0, -1.0,
         1.0, -1.0, -1.0,
         1.0,  1.0, -1.0,
        -1.0,  1.0, -1.0,
    };

    GLfloat cube_colors[] = {
        // front colors
        1.0, 0.0, 0.0,
        0.0, 1.0, 0.0,
        0.0, 0.0, 1.0,
        1.0, 1.0, 1.0,
        // back colors
        1.0, 0.0, 0.0,
        0.0, 1.0, 0.0,
        0.0, 0.0, 1.0,
        1.0, 1.0, 1.0,
    };

    int index = 0;

    for (int i = 0; i < 8; i++)  {
        terrian_vertices[i] = new Vector3(cube_vertices[index], cube_vertices[index+1], cube_vertices[index+2]);
        terrian_colors[i] = new Color(cube_colors[index], cube_colors[index+1], cube_colors[index+2]);

        index+=3;
    }
}

void Terrian::construct_elements()  {
    int index = 0;

    GLushort cube_elements[] = {
        // front
        0, 1, 2,
        2, 3, 0,
        // top
        1, 5, 6,
        6, 2, 1,
        // back
        7, 6, 5,
        5, 4, 7,
        // bottom
        4, 0, 3,
        3, 7, 4,
        // left
        4, 5, 1,
        1, 0, 4,
        // right
        3, 2, 6,
        6, 7, 3,
    };

    terrian_elements = new GLushort[36];

    for (int i = 0; i < 36; i++)  {
        terrian_elements[i] = cube_elements[i];
    }

    /* actual code ...*/
}

void Terrian::construct_buffers()  {
    glGenBuffers(1, &vbo_terrian_vertices);
    glBindBuffer(GL_ARRAY_BUFFER, vbo_terrian_vertices);
    glBufferData(GL_ARRAY_BUFFER, sizeof(terrian_vertices), terrian_vertices, GL_STATIC_DRAW);

    glGenBuffers(1, &vbo_terrian_colors);
    glBindBuffer(GL_ARRAY_BUFFER, vbo_terrian_colors);
    glBufferData(GL_ARRAY_BUFFER, sizeof(terrian_colors), terrian_colors, GL_STATIC_DRAW);

    glGenBuffers(1, &ibo_terrian_elements);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_terrian_elements);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(terrian_elements), terrian_elements, GL_STATIC_DRAW);
}

My Vector3 and Color structure look like the following:

struct Vector3  {
    GLfloat xyz[3];

    Vector3(GLfloat x, GLfloat y, GLfloat z)  {
        this->xyz[0] = x;
        this->xyz[1] = y;
        this->xyz[2] = z;
    }

    Vector3()  {
    }

    void set_x(GLfloat x);
    void set_y(GLfloat y);
    void set_z(GLfloat z);

    GLfloat get_x();
    GLfloat get_y();
    GLfloat get_z();

    Vector3 operator=(Vector3 param);

    void normalise();
};

Color:

struct Color  {
    GLfloat rgb[3];

    // Storing a one byte value in four bytes FTW

    Color(GLfloat r, GLfloat g, GLfloat b) {
        this->rgb[0] = r / 255.0;
        this->rgb[1] = g / 255.0;
        this->rgb[2] = b / 255.0;
    }

    Color()  {
    }

    GLfloat get_r();
    GLfloat get_g();
    GLfloat get_b();

    void set_r(GLfloat r);
    void set_b(GLfloat g);
    void set_g(GLfloat b);
};

I render the terrain like:

void render(sf::Window *app, Terrian *terrian)  {
    app->SetActive();

    glClearColor(0.0, 0.0, 0.0, 1.0);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glUseProgram(program);
    glEnableVertexAttribArray(attribute_coord3d);

    // Describe our vertices array to OpenGL (it can't guess its format automatically)
    glBindBuffer(GL_ARRAY_BUFFER, terrian->get_vertexbuffer());

    glVertexAttribPointer(
        attribute_coord3d, // attribute
        3,                 // number of elements per vertex, here (x,y,z)
        GL_FLOAT,          // the type of each element
        GL_FALSE,          // take our values as-is
        0,                 // no extra data between each position
        0                  // offset of first element
    );

    glEnableVertexAttribArray(attribute_v_color);

    glBindBuffer(GL_ARRAY_BUFFER, terrian->get_colorbuffer());

    glVertexAttribPointer(
        attribute_v_color, // attribute
        3,                 // number of elements per vertex, here (R,G,B)
        GL_FLOAT,          // the type of each element
        GL_FALSE,          // take our values as-is
        0,                 // no extra data between each position
        0                  // offset of first element
    );

    /* Push each element in buffer_vertices to the vertex shader */
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, terrian->get_elementbuffer());

    int size;
    glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_SIZE, &size);

    glDrawElements(GL_TRIANGLES, size / sizeof(GLushort), GL_UNSIGNED_SHORT, 0);

    glDisableVertexAttribArray(attribute_coord3d);
    glDisableVertexAttribArray(attribute_v_color);
}

I really have no idea what is wrong, and why nothing is being drawn, I've checked my code against numerous examples but still can't find the issue, in the case that my world transformations may be a problem here they are:

void update(sf::Window *app, sf::Clock *clock)  {
    float angle = clock->GetElapsedTime() * 45;

    glm::vec3 axis_y(0, 1, 0);
    glm::mat4 anim = glm::rotate(glm::mat4(1.0f), angle, axis_y);

    glm::mat4 model = glm::translate(glm::mat4(1.0f), glm::vec3(0.0, 0.0, -4.0));
    // position, centre, up
    glm::mat4 view = glm::lookAt(glm::vec3(0.0, 2.0, 0.0), glm::vec3(0.0, 0.0, -4.0), glm::vec3(0.0, 1.0, 0.0));
    glm::mat4 projection = glm::perspective(45.0f, 1.0f * 800 / 600, 0.1f, 100.0f);

    glm::mat4 mvp = projection * view * model * anim;

    glUseProgram(program);
    glUniformMatrix4fv(uniform_mvp, 1, GL_FALSE, glm::value_ptr(mvp));
}

Edit

Updated code according to Viclund's answer:

#ifndef TERRIAN_H
#define TERRIAN_H

#include "Vector3.h"
#include "Color.h"

#include <GL/glew.h>
#include <GL/glu.h>
#include <GL/gl.h>
#include <stdlib.h>
#include <vector>

class Terrian  {
    public:
        Terrian(int width, int height);
        virtual ~Terrian();

        GLuint get_vertexbuffer();
        GLuint get_colorbuffer();
        GLuint get_elementbuffer();
    protected:
    private:
        Vector3 *terrian_vertices;
        Color *terrian_colors;
        GLushort *terrian_elements;

        GLuint vbo_terrian_vertices;
        GLuint vbo_terrian_colors;
        GLuint ibo_terrian_elements;

        GLint width;
        GLint height;

        void construct_vertices();
        void construct_buffers();
        void construct_elements();
};

#endif // TERRIAN_H

...

void Terrian::construct_vertices()  {
    terrian_vertices = new Vector3[8];
    terrian_colors = new Color[8];

    GLfloat cube_vertices[] =  {
        -1.0, -1.0,  1.0,
         1.0, -1.0,  1.0,
         1.0,  1.0,  1.0,
        -1.0,  1.0,  1.0,
        // back
        -1.0, -1.0, -1.0,
         1.0, -1.0, -1.0,
         1.0,  1.0, -1.0,
        -1.0,  1.0, -1.0,
    };

    GLfloat cube_colors[] = {
        // front colors
        1.0, 0.0, 0.0,
        0.0, 1.0, 0.0,
        0.0, 0.0, 1.0,
        1.0, 1.0, 1.0,
        // back colors
        1.0, 0.0, 0.0,
        0.0, 1.0, 0.0,
        0.0, 0.0, 1.0,
        1.0, 1.0, 1.0,
    };

    int index = 0;

    for (int i = 0; i < 8; i++)  {
        terrian_vertices[i] = Vector3(cube_vertices[index], cube_vertices[index+1], cube_vertices[index+2]);
        terrian_colors[i] = Color(cube_colors[index], cube_colors[index+1], cube_colors[index+2]);

        index+=3;
    }
}

void Terrian::construct_elements()  {
    int index = 0;

    GLushort cube_elements[] = {
        // front
        0, 1, 2,
        2, 3, 0,
        // top
        1, 5, 6,
        6, 2, 1,
        // back
        7, 6, 5,
        5, 4, 7,
        // bottom
        4, 0, 3,
        3, 7, 4,
        // left
        4, 5, 1,
        1, 0, 4,
        // right
        3, 2, 6,
        6, 7, 3,
    };

    terrian_elements = new GLushort[36];

    for (int i = 0; i < 36; i++)  {
        terrian_elements[i] = cube_elements[i];
    }
}

void Terrian::construct_buffers()  {
    glGenBuffers(1, &vbo_terrian_vertices);
    glBindBuffer(GL_ARRAY_BUFFER, vbo_terrian_vertices);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Vector3) * 8, terrian_vertices, GL_STATIC_DRAW);

    glGenBuffers(1, &vbo_terrian_colors);
    glBindBuffer(GL_ARRAY_BUFFER, vbo_terrian_colors);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Color) * 8, terrian_colors, GL_STATIC_DRAW);

    glGenBuffers(1, &ibo_terrian_elements);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_terrian_elements);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * 36, terrian_elements, GL_STATIC_DRAW);
}

Edit 2

X: 5.69408e-039 Y: 5.745e-039 Z: 5.745e-039
X: 4.12098e+021 Y: 4.74227e+030 Z: 4.74227e+030
X: 1.93472e-019 Y: 1.80569e+028 Z: 1.80569e+028
X: 1.35662e-019 Y: 1.3556e-019 Z: 1.3556e-019
X: 2.79324e+020 Y: 1.15701e+027 Z: 1.15701e+027
X: 4.23282e+021 Y: 1.65846e+019 Z: 1.65846e+019
X: 3.52687e-012 Y: 4.12098e+021 Z: 4.12098e+021
X: 1.46091e-019 Y: 7.03684e+028 Z: 7.03684e+028
\$\endgroup\$
1
  • 1
    \$\begingroup\$ I think you need to seriously strip down the code to the bare minimum before anyone can help much. remove all the transforms, colors, program. and just draw a triangle. \$\endgroup\$
    – Jake
    Jul 21, 2012 at 7:03

2 Answers 2

1
\$\begingroup\$

There's two core problems here that I have seen.

  • You've got the wrong type for your terrian_vertices and terrian_colors arrays.
  • You're passing in the wrong sizes for your glBufferData calls.

First, your arrays contains pointers to Vector3 and Color, which you provide as-is into the call to glBufferData. Interpreting pointer addresses as floating point numbers does not make sense, and will not result in uploading the attributes they point to

Compare your index array to your position and color arrays, and see how it has one less indirection.

What you have is a pointer to an array, whose elements point to objects of Vector3 or Color type. What you need is a pointer to an array, whose elements are of Vector3 or Color type.

In crude ASCII art, you have:

colors -> [ pt0   pt1  .. ptN ]
             |     |       |
             v     v       v
           (rgb) (rgb)   (rgb)

and want

colors -> [ (rgb) (rgb) ... (rgb) ]

Turn this

Vector3 **terrian_vertices;
terrian_vertices = new Vector3*[8];

terrian_vertices[i] =
    new Vector3(cube_vertices[index], cube_vertices[index+1], cube_vertices[index+2]);

into

Vector3 *terrian_vertices;
terrian_vertices = new Vector3[8];

terrian_vertices[i] =
    Vector3(cube_vertices[index], cube_vertices[index+1], cube_vertices[index+2]);

Secondly, your glBufferData call uses a size you probably did not intend to use.

sizeof(object-of-pointer-type) is the size of that pointer type, not whatever array it may point to. You need to pass in the byte size of the whole buffer, which is the size of a single element multiplied by the number of elements, sizeof(Vertex3)*NumberOfVertices.

As a final note, you might want to correct the spelling to "terrain" from "terrian".

\$\endgroup\$
3
  • \$\begingroup\$ Haha, I can't believe I spelled that wrong O_o. Anyhow, I've changed the code according to your answer and the cube is still not displaying... Any other ideas? (updated code in the edit) \$\endgroup\$
    – Darestium
    Jul 22, 2012 at 1:06
  • \$\begingroup\$ Oh.. Also, when I print out the X value of the vector it prints out some random numbers in scientific notation.... \$\endgroup\$
    – Darestium
    Jul 25, 2012 at 0:07
  • \$\begingroup\$ I've added the program output in the second edit. \$\endgroup\$
    – Darestium
    Jul 25, 2012 at 0:14
0
\$\begingroup\$

I reluctantly used the std::vector type to store my vertices, colours, and elements.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .