2
votes

So I watched a little intro course on youtube to learn the basics of OpenGL and learnt things like making a triangle and a simple camera class, etc. I've wanted to try and work towards making a voxel engine so obviously the first thing that I thought to make was a simple cube that I could eventually replicate. My problem is though that when I go to render the vertices and triangles they seem to be in a mess that doesn't resemble what I hard coded in the cube class. I know that 0,0 is the centre of the screen; 1 in the x axis is the right; -1 is the left; 1 in the y axis is the top and -1 is the bottom. Yet when I send through my vertices and triangles to the vertex buffer it seems to be doing something completely different. It's most likely a really stupid mistake on my part.

Cube::Cube()
{
m_vertices[0] = Vertex(glm::vec3(-0.5, -0.5, 0));
m_vertices[1] = Vertex(glm::vec3(-0.5, 0.5, 0));
m_vertices[2] = Vertex(glm::vec3(0.5, 0.5, 0));
m_vertices[3] = Vertex(glm::vec3(0.5, -0.5, 0));
m_vertices[4] = Vertex(glm::vec3(-0.5, -0.5, 1));
m_vertices[5] = Vertex(glm::vec3(-0.5, 0.5, 1));
m_vertices[6] = Vertex(glm::vec3(0.5, 0.5, 1)); 
m_vertices[7] = Vertex(glm::vec3(0.5, -0.5, 1));

m_triangles[0] = Triangle(0, 1, 2); //Front
//m_triangles[1] = Triangle(0, 2, 3); //Front

//m_triangles[2] = Triangle(1, 5, 6); //Top
//m_triangles[3] = Triangle(1, 6, 2); //Top

//m_triangles[4] = Triangle(3, 5, 4); //Left
//m_triangles[5] = Triangle(3, 5, 4); //Left

//m_triangles[6] = Triangle(3, 2, 7); //Right
//m_triangles[7] = Triangle(3, 3, 7); //Right

//m_triangles[8] = Triangle(7, 6, 4); //Back
//m_triangles[9] = Triangle(5, 6, 7); //Back

//m_triangles[10] = Triangle(0, 4, 7); //Bottom
//m_triangles[11] = Triangle(0, 3, 7); //Bottom
}

void Cube::Render()
{
   Draw(m_vertices, sizeof(m_vertices) / sizeof(m_vertices[0]), m_triangles, (sizeof(m_triangles) / sizeof(m_triangles[0])));
}

The draw function inherited from my mesh class

void Mesh::Draw(Vertex* vertices, unsigned int numVertices, Triangle* triangles, unsigned int numTriangles)
{
//Array of indices
std::vector<unsigned int> indices;
for (int i = 0; i < numTriangles; i++)
{
    indices.push_back(triangles[i].GetTriangle()[0]);
    indices.push_back(triangles[i].GetTriangle()[1]);
    indices.push_back(triangles[i].GetTriangle()[2]);
}

//How many vertices to draw
m_drawCount = indices.size();

//Generate and bind vertex array
glGenVertexArrays(1, &m_vertexArrayObject);
glBindVertexArray(m_vertexArrayObject);

//Generate and bind buffers
glGenBuffers(NUM_BUFFERS, m_vertexArrayBuffers);
glBindBuffer(GL_ARRAY_BUFFER, m_vertexArrayBuffers[POSITION_VB]);
//Write vertex data to the buffer
glBufferData(GL_ARRAY_BUFFER, numVertices * sizeof(vertices[0]), &vertices[0], GL_STATIC_DRAW);

//Only one attribute for the vertex data
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_vertexArrayBuffers[INDEX_VB]);
//Write vertex data to the buffer
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices[0]) * indices.size(), &indices[0], GL_STATIC_DRAW);

//Unbind vertex array
glBindVertexArray(0);

glBindVertexArray(m_vertexArrayObject);

glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glDrawElements(GL_TRIANGLES, m_drawCount, GL_UNSIGNED_INT, 0);

glBindVertexArray(0);
}

Vertex and Triangle structs in mesh.h

struct Vertex
{
public:
//Constructor
Vertex()
{

}
//Constructor
Vertex(const glm::vec3& pos)
{
    //Set vertex position
    this->m_pos = pos;
}
protected:

private:
//Vertex position
glm::vec3 m_pos;
};

struct Triangle
{
public:
//Constructor
Triangle()
{

}

//Constructor
Triangle(int point1, int point2, int point3)
{
    SetTriangle(point1, point2, point3);
}

int* GetTriangle()
{
    return m_points;
}

void SetTriangle(int point1, int point2, int point3)
{
    m_points[0] = point1;
    m_points[1] = point2;
    m_points[2] = point3;
}
protected:

private:
int m_points[3];
};

Camera functions

Camera::Camera(const glm::vec3 pos, float fov, float aspect, float zNear, float zFar)
{
m_perspectiveMatrix = glm::perspective(fov, aspect, zNear, zFar);
m_pos = pos;
m_forward = glm::vec3(0, 0, 1);
m_up = glm::vec3(0, 1, 0);
}

glm::mat4 Camera::GetViewProjection() const
{
 return m_perspectiveMatrix * glm::lookAt(m_pos, m_pos + m_forward, m_up);
}

Note that in the cube constructor I'm only creating one triangle which should be bottom left, top left, top right yet this is the result:

The triangle isn't where I specified it

Another note is that my camera rotation seems to be off as well. Changing the y rotation actually rotates it on the x axis and the changing the x rotation rotates on the y axis.

Also if anyone had a better way of creating and rendering the cube I would be grateful. Once I can do that I'll most likely look into letsmakeavoxelengine tutorials.

Edit: It feels like the x and y axis are inverted. I could just invert all my functions to counter that but that's kind of a hacky way around it and it still doesn't fix the underlying issue which could cause more trouble later on.

Edit2: Transform.h

#pragma once
#include <glm\glm.hpp>
#include <glm\gtx\transform.hpp>
#include "Camera.h"

struct Transform
{
public:
//Constructor
Transform(const glm::vec3& pos = glm::vec3(), const glm::vec3& rot = glm::vec3(), const glm::vec3& scale = glm::vec3(1.0f, 1.0f, 1.0f))
{
    this->m_pos = pos;
    this->m_rot = rot;
    this->m_scale = scale;
}

//Get the model matrix
inline glm::mat4 GetModelMatrix() const
{
    //Create all the transform matrices

    //Position matrix
    glm::mat4 posMatrix = glm::translate(m_pos);
    //Scale matrix
    glm::mat4 scaleMatrix = glm::scale(m_scale);
    //Rotation matrix X
    glm::mat4 rotXMatrix = glm::rotate(m_rot.x, glm::vec3(1.0f, 0.0f, 0.0f));
    //Rotation matrix Y
    glm::mat4 rotYMatrix = glm::rotate(m_rot.y, glm::vec3(0.0f, 1.0f, 0.0f));
    //Rotation matrix Z
    glm::mat4 rotZMatrix = glm::rotate(m_rot.z, glm::vec3(0.0f, 0.0f, 1.0f));
    //Combined rotation matrix
    glm::mat4 rotMatrix = rotXMatrix * rotYMatrix * rotZMatrix;

    return posMatrix * rotMatrix * scaleMatrix;
}

inline glm::mat4 GetMVP(const Camera& camera) const
{
    glm::mat4 ViewProjection = camera.GetViewProjection();
    glm::mat4 ModelMatrix = GetModelMatrix();

    return ViewProjection * ModelMatrix;//camera.GetViewProjection() * GetModel();
}

//Get position
inline glm::vec3* GetPosition() { return &m_pos; }
//Get rotation
inline glm::vec3* GetRotation() { return &m_rot; }
//Get scale
inline glm::vec3* GetScale() { return &m_scale; }

//Set Position
inline void SetPosition(const glm::vec3& pos) { this->m_pos = pos; }
//Set Rotation
inline void SetRotation(const glm::vec3& rot) { this->m_rot = rot; }
//Set Scale
inline void SetScale(const glm::vec3& scale) { this->m_scale = scale; }

private:
//Transform position
glm::vec3 m_pos;
//Transform rotation
glm::vec3 m_rot;
//Transform scale
glm::vec3 m_scale;
};

Cube, Transform and Camera calls in main.cpp:

Cube cube;
Transform transform;
Camera camera(glm::vec3(0.0f, 0.0f, -3.0f), 70.0f, (float)display.GetWidth()/(float)display.GetHeight(), 0.01f, 100.0f);

Edit3: 100% inverted on X Axis. New cube.cpp code:

m_vertices[0] = Vertex(glm::vec3(-0.5, -0.5, 0)); //BottomLeftFront
m_vertices[1] = Vertex(glm::vec3(-0.5, 0.5, 0)); //TopLeftFront
m_vertices[2] = Vertex(glm::vec3(0.5, 0.5, 0)); //TopRightFront
m_vertices[3] = Vertex(glm::vec3(0.5, -0.5, 0)); //BottomRightFront
m_vertices[4] = Vertex(glm::vec3(-0.5, -0.5, 1)); //BottomLeftBack
m_vertices[5] = Vertex(glm::vec3(-0.5, 0.5, 1)); //TopLeftBack
m_vertices[6] = Vertex(glm::vec3(0.5, 0.5, 1)); //TopRightBack
m_vertices[7] = Vertex(glm::vec3(0.5, -0.5, 1)); //BottomRightBack

m_triangles[0] = Triangle(0, 1, 2); //Front
m_triangles[1] = Triangle(0, 2, 3); //Front

//m_triangles[2] = Triangle(1, 5, 6); //Top
//m_triangles[3] = Triangle(1, 6, 2); //Top

m_triangles[4] = Triangle(3, 5, 4); //Left //BottomLeftFront, TopRightBack, BottomRightBack
//m_triangles[5] = Triangle(3, 5, 4); //Left

//m_triangles[6] = Triangle(3, 2, 7); //Right
//m_triangles[7] = Triangle(3, 3, 7); //Right

//m_triangles[8] = Triangle(7, 6, 4); //Back
//m_triangles[9] = Triangle(5, 6, 7); //Back

//m_triangles[10] = Triangle(0, 4, 7); //Bottom
//m_triangles[11] = Triangle(0, 3, 7); //Bottom

I've put a comment next to the new triangle that tells you what the actual resulting triangle points were. The triangle that I set should have been BottomRightFront, TopLeftBack, BottomLeftBack according to the code. I'll also add a screenshot of what it looks like.

Triangle was supposed to be BottomRightFront, TopLeftBack, BottomLeftBack

1
Can you provide a complete sample that compiles? Conventionally we use a right-handed system, so if the x axis points right and the y axis points up then the z axis points backwards (towards the camera); but your zNear and zFar are positive, and your m_forwards is (0 0 1) rather than (0 0 -1); is that a glm thing?Buster
Does your "pos" have a negative z-coordinate? If not, then perhaps that's the problem. But then again perhaps not, because if the problem is just that, then I'd expect the image to be flipped horizontally and vertically.Buster
Sorry, I didn't notice your question earlier, about the best way to send the project. Ideally, all the code would be in the question, but I do understand that "OpenGL" and "small, complete sample" don't go together very well! I wish I knew what the recommended solution is for StackOverflow.Buster
The call to glm::lookAt in Camera::GetViewProjection looks suspicious; in particular you have "centre" (the second argument) behind "eye" (the first argument), since "m_forwards" points backwards.Buster
My pleasure! Try lookAt with (0 0 0) for "eye", m_pos for "centre" and (0 1 0) for "up"?Buster

1 Answers

3
votes

Your description of the X and Y axes sounds right, but the Z axis seems to be reversed. For example, in the code you posted there's a variable m_forward whose value is (0, 0, 1); that could be right, but I usually call that direction "backwards".

Conventionally, OpenGL programs use a right-handed coordinate system, so if X points right and Y points up then Z points out of the screen, towards the eye. If you keep that in mind and review your code, checking the sign of the Z component of each position and direction vector, you should find the mistake(s). Good luck!