I'm developing an application in C++ using OpenGL. My problem is that when I render a cube to screen which has a rotation, it appears out of proportion (see the images).
I'm using the following NuGet packages:
When the cube is rotated at 0 degrees:
When the cube is rotated at 45 degrees:
When the cube is rotated at 90 degrees:
When the cube is rotated at 180 degrees:
When the cube is rotated at 360 degrees:
The following code is where the matrix is calculated:
glm::mat4 DrawnEntity::getMatrix() const
{
glm::mat4 translate = glm::translate(glm::mat4(1.0f), position);
glm::mat4 rotation = glm::toMat4(glm::quat(glm::radians(360.0f), 0, 1, 0));
glm::mat4 matrix = translate * rotation;
return matrix;
}
When the entity is drawn, this is called:
void DrawnEntity::render()
{
if (enabled)
mesh->render(getMatrix());
}
Which subsequently calls this:
void Mesh::render(glm::mat4 matrix)
{
glUseProgram(shaderID);
vao->render(matrix);
}
vao is a VertexArrayObject, and this is the function:
void VertexArrayObject::render(glm::mat4 matrix)
{
GLuint uModel = glGetUniformLocation(shaderID, "uModel");
glUniformMatrix4fv(uModel, 1, GL_TRUE, &matrix[0][0]);
glBindVertexArray(vao[0]);
glDrawArrays(GL_TRIANGLES, 0, mesh->vertexCount());
glBindVertexArray(0);
}
Ignoring the rotation, it appears all the vertices are being correctly loaded. For what it's worth, this is the class which generates the cube:
#include "CubeMesh.h"
#include "../VertexArrayObject.h"
CubeMesh::CubeMesh(GLuint shader)
{
shaderID = shader;
glUseProgram(shaderID);
generateFaces();
vao = new VertexArrayObject(this);
}
void CubeMesh::generateFaces()
{
// Front face
generateFace(glm::vec3(-0.5, 0.5, 0.5), glm::vec3(0.5, -0.5, 0.5));
// Left face
generateFace(glm::vec3(-0.5, -0.5, 0.5), glm::vec3(-0.5, 0.5, -0.5));
// Back face
generateFace2(glm::vec3(0.5, -0.5, -0.5), glm::vec3(-0.5, 0.5, -0.5));
// Right face
generateFace2(glm::vec3(0.5, -0.5, 0.5), glm::vec3(0.5, 0.5, -0.5));
}
void CubeMesh::generateFace(glm::vec3 point1, glm::vec3 point2)
{
glm::vec3 tl = point1;
glm::vec3 br = point2;
glm::vec3 tr = glm::vec3(br.x, tl.y, br.z);
glm::vec3 bl = glm::vec3(tl.x, br.y, tl.z);
Vertex f1v1(glm::vec3(tl.x, tl.y, tl.z));
Vertex f1v2(glm::vec3(bl.x, bl.y, bl.z));
Vertex f1v3(glm::vec3(br.x, br.y, br.z));
Triangle f1(f1v1, f1v2, f1v3);
Vertex f2v1(glm::vec3(tr.x, tr.y, tr.z));
Vertex f2v2(glm::vec3(tl.x, tl.y, tl.z));
Vertex f2v3(glm::vec3(br.x, br.y, br.z));
Triangle f2(f2v1, f2v2, f2v3);
addData(f1);
addData(f2);
}
void CubeMesh::generateFace2(glm::vec3 point1, glm::vec3 point2)
{
glm::vec3 tl = point1;
glm::vec3 br = point2;
glm::vec3 tr = glm::vec3(br.x, tl.y, br.z);
glm::vec3 bl = glm::vec3(tl.x, br.y, tl.z);
Vertex f1v1(glm::vec3(tl.x, tl.y, tl.z));
Vertex f1v2(glm::vec3(br.x, br.y, br.z));
Vertex f1v3(glm::vec3(bl.x, bl.y, bl.z));
Triangle f1(f1v1, f1v2, f1v3);
Vertex f2v1(glm::vec3(tr.x, tr.y, tr.z));
Vertex f2v2(glm::vec3(br.x, br.y, br.z));
Vertex f2v3(glm::vec3(tl.x, tl.y, tl.z));
Triangle f2(f2v1, f2v2, f2v3);
addData(f1);
addData(f2);
}
The vertex shader is as follows:
#version 430 core
uniform mat4 uModel;
uniform mat4 uView;
uniform mat4 uProjection;
in vec3 vPosition;
in vec3 vNormal;
out vec4 oColour;
void main(void)
{
oColour = vec4(vPosition, 1);
gl_Position = vec4(vPosition, 1) * uModel * uView * uProjection;
}
uModel is the matrix representing the individual model translation, rotation etc. uView is the position of the camera, and uProjection is the projection matrix. The first is fed to the shader in the VertexArrayObject shown previously, while the last two are fed to the shader in the camera object as below:
void Camera::initialise()
{
glUseProgram(shaderID);
view = glm::translate(glm::mat4(1), position);
int uView = glGetUniformLocation(shaderID, "uView");
glUniformMatrix4fv(uView, 1, GL_TRUE, &view[0][0]);
int uProjection = glGetUniformLocation(shaderID, "uProjection");
glm::mat4 projection = glm::perspective(1.0, (double)1024 / (double)1024, 0.01, 10.0);
glUniformMatrix4fv(uProjection, 1, GL_TRUE, &projection[0][0]);
}
The position of the model is 0 0 0 and the position of the camera is 0 0 -5. When the uModel position is changed, the cube is rendered where it is expected, however with the rotation it doesn't act as it should.
Can anybody see anything that I might be doing wrong? Is there anymore code you need to see?
I found that changing the following line:
glm::mat4 rotation = glm::toMat4(glm::quat(glm::radians(360.0f), 0, 1, 0));
to this:
glm::mat4 rotation = glm::rotate(translate, (float)glm::radians(0.0), glm::vec3(0.0f, 1.0f, 0.0f));
solves the issue. I can't really offer an explanation for why the first one didn't work, as I don't know enough about Quaternion's to comment on it. If anyone can explain it better, please edit my answer. Regardless, this was the best fix I could find.