I'm trying to make a visual "simulation" of the solar system using OpenGL and am using this function to orbit a planet around the sun (in a circular orbit).
glm::vec3 application::orbit(glm::vec3 thisPlanet, glm::vec3 otherPlanet, float rotSpeed, const time &dt)
{
float radius = glm::distance(thisPlanet, otherPlanet);
float angle = acosf((thisPlanet.x - otherPlanet.x) / radius) - atanf(1.0f) * 4.0f;
angle += dt.as_seconds() * rotSpeed;
if (angle > 2 * atanf(1.0f) * 4.0f)
angle -= 2 * atanf(1.0f) * 4.0f;
float x = otherPlanet.x + cosf(angle) * radius;
float z = otherPlanet.z + sinf(angle) * radius;
return glm::vec3(x, thisPlanet.y, z);
}
The function is called every frame like this:
void application::tick(const time &dt)
{
if (m_keyboard.key_released(GLFW_KEY_ESCAPE)) {
m_running = false;
}
m_controller.update(m_keyboard, m_mouse, dt);
m_cube_rotation += dt.as_seconds();
m_mercury_position = orbit(m_mercury_position, m_sun_position, 2.0f, dt);
// glm::mat4 world = glm::translate(glm::mat4(1.0f), m_cube_position)
// * glm::rotate(glm::mat4(1.0f), m_cube_rotation, glm::normalize(glm::vec3(1.0f, 1.0f, -1.0f)));
glm::mat4 sun = glm::translate(glm::scale(glm::mat4(1.0f), glm::vec3(2.0f, 2.0f, 2.0f)), m_sun_position)
* glm::rotate(glm::mat4(1.0f), m_cube_rotation, glm::normalize(glm::vec3(1.0f, 1.0f, -1.0f)));
glm::mat4 mercury = glm::translate(glm::scale(glm::mat4(1.0f), glm::vec3(1.0f, 1.0f, 1.0f)), m_mercury_position)
* glm::rotate(glm::mat4(1.0f), m_cube_rotation, glm::normalize(glm::vec3(1.0f, 1.0f, -1.0f)));
//m_crate.set_transform(world);
m_sun.set_transform(sun);
m_mercury.set_transform(mercury);
const int frames_per_second = int(1.0f / dt.as_seconds());
const int frame_timing_ms = int(dt.as_milliseconds());
m_overlay.pre_frame(m_width, m_height);
m_overlay.push_line("FPS: %d (%dms)", frames_per_second, frame_timing_ms);
}
Why doesn't the planet move?
This is how I would construct the model matrix:
mat4 model_mat;
const vec3 n_forward = dir.x;
const vec3 n_up = vec3(0, 1, 0);
const vec3 n_left = dir.z;
// construct a basis and a translation
model_mat[0] = normalize(vec4(n_left, 0.0f));
model_mat[1] = normalize(vec4(n_forward, 0.0f));
model_mat[2] = normalize(vec4(n_up, 0.0f));
model_mat[3] = vec4(p, 1.0f);
The position (e.g. p) is given by the parametric circle equation p = r cos(t) + r sin(t), where t is the elapsed time and r is the circular orbit radius. Also see: https://www.mathopenref.com/coordparamcircle.html
Does this help at all?
So I've been trying to re-implement shadow mapping in my engine using directional lights, but I have to throw shade on my progress so far (see what I did there?).
I had it working in a previous commit a while back but refactored my engine and I'm trying to redo some of the shadow mapping. Wouldn't say I'm the best in terms of drawing shadows so thought I'd try and get some help.
Basically my issue seems to stem from the calculation of the light space matrix (seems a lot of people have the same issue). Initially I had a hardcoded projection matrix and simple view matrix for the light like this
void ZLight::UpdateLightspaceMatrix()
{
// …
if (type == ZLightType::Directional) {
auto lightDir = glm::normalize(glm::eulerAngles(Orientation()));
glm::mat4 lightV = glm::lookAt(lightDir, glm::vec3(0.f), WORLD_UP);
glm::mat4 lightP = glm::ortho(-50.f, 50.f, -50.f, 50.f, -100.f, 100.f);
lightspaceMatrix_ = lightP * lightV;
}
// …
}
This then gets passed unmodified as a shader uniform, with which I multiply the vertex world space positions by. A few months ago this was working but with the recent refactor I did on the engine it no longer shows anything. The output to the shadow map looks like this
And my scene isn't showing any shadows, at least not where it matters
Aside from this, after hours of scouring posts and articles about how to implement a dynamic frustrum for the light that will encompass the scene's contents at any given time, I also implemented a simple solution based on transforming the camera's frustum into light space, using an NDC cube and transforming it with the inverse camera VP matrix, and computing a bounding box from the result, which gets passed in to glm::ortho to make the light's projection matrix
void ZLight::UpdateLightspaceMatrix()
{
static std::vector <glm::vec4> ndcCube = {
glm::vec4{ -1.0f, -1.0f, -1.0f, 1.0f },
glm::vec4{ 1.0f, -1.0f, -1.0f, 1.0f },
glm::vec4{ -1.0f, 1.0f, -1.0f, 1.0f },
glm::vec4{ 1.0f, 1.0f, -1.0f, 1.0f },
glm::vec4{ -1.0f, -1.0f, 1.0f, 1.0f },
glm::vec4{ 1.0f, -1.0f, 1.0f, 1.0f },
glm::vec4{ -1.0f, 1.0f, 1.0f, 1.0f },
glm::vec4{ 1.0f, 1.0f, 1.0f, 1.0f }
};
if (type == ZLightType::Directional) {
auto activeCamera = Scene()->ActiveCamera();
auto lightDir = normalize(glm::eulerAngles(Orientation()));
glm::mat4 lightV = glm::lookAt(lightDir, glm::vec3(0.f), WORLD_UP);
lightspaceRegion_ = ZAABBox();
for (const auto& corner : ndcCube) {
auto invVPMatrix = glm::inverse(activeCamera->ProjectionMatrix() * activeCamera->ViewMatrix());
auto transformedCorner = lightV * invVPMatrix * corner;
transformedCorner /= transformedCorner.w;
lightspaceRegion_.minimum.x = glm::min(lightspaceRegion_.minimum.x, transformedCorner.x);
lightspaceRegion_.minimum.y = glm::min(lightspaceRegion_.minimum.y, transformedCorner.y);
lightspaceRegion_.minimum.z = glm::min(lightspaceRegion_.minimum.z, transformedCorner.z);
lightspaceRegion_.maximum.x = glm::max(lightspaceRegion_.maximum.x, transformedCorner.x);
lightspaceRegion_.maximum.y = glm::max(lightspaceRegion_.maximum.y, transformedCorner.y);
lightspaceRegion_.maximum.z = glm::max(lightspaceRegion_.maximum.z, transformedCorner.z);
}
glm::mat4 lightP = glm::ortho(lightspaceRegion_.minimum.x, lightspaceRegion_.maximum.x,
lightspaceRegion_.minimum.y, lightspaceRegion_.maximum.y,
-lightspaceRegion_.maximum.z, -lightspaceRegion_.minimum.z);
lightspaceMatrix_ = lightP * lightV;
}
}
What results is the same output in my scene (no shadows anywhere) and the following shadow map
I've checked the light space matrix calculations over and over, and tried tweaking values dozens of times, including all manner of lightV matrices using the glm::lookAt function, but I never get the desired output.
For more reference, here's my shadow vertex shader
#version 450 core
#include "Shaders/common.glsl" //! #include "../common.glsl"
layout (location = 0) in vec3 position;
layout (location = 5) in ivec4 boneIDs;
layout (location = 6) in vec4 boneWeights;
layout (location = 7) in mat4 instanceM;
uniform mat4 P_lightSpace;
uniform mat4 M;
uniform mat4 Bones[MAX_BONES];
uniform bool rigged = false;
uniform bool instanced = false;
void main()
{
vec4 pos = vec4(position, 1.0);
if (rigged) {
mat4 boneTransform = Bones[boneIDs[0]] * boneWeights[0];
boneTransform += Bones[boneIDs[1]] * boneWeights[1];
boneTransform += Bones[boneIDs[2]] * boneWeights[2];
boneTransform += Bones[boneIDs[3]] * boneWeights[3];
pos = boneTransform * pos;
}
gl_Position = P_lightSpace * (instanced ? instanceM : M) * pos;
}
my soft shadow implementation
float PCFShadow(VertexOutput vout, sampler2D shadowMap) {
vec3 projCoords = vout.FragPosLightSpace.xyz / vout.FragPosLightSpace.w;
if (projCoords.z > 1.0)
return 0.0;
projCoords = projCoords * 0.5 + 0.5;
// PCF
float shadow = 0.0;
float bias = max(0.05 * (1.0 - dot(vout.FragNormal, vout.FragPosLightSpace.xyz - vout.FragPos.xzy)), 0.005);
for (int i = 0; i < 4; ++i) {
float z = texture(shadowMap, projCoords.xy + poissonDisk[i]).r;
shadow += z < (projCoords.z - bias) ? 1.0 : 0.0;
}
return shadow / 4;
}
...
...
float shadow = PCFShadow(vout, shadowSampler0);
vec3 color = (ambient + (1.0 - shadow) * (diffuse + specular)) + materials[materialIndex].emission;
FragColor = vec4(color, albd.a);
and my camera view and projection matrix getters
glm::mat4 ZCamera::ProjectionMatrix()
{
glm::mat4 projectionMatrix(1.f);
auto scene = Scene();
if (!scene) return projectionMatrix;
if (cameraType_ == ZCameraType::Orthographic)
{
float zoomInverse_ = 1.f / (2.f * zoom_);
glm::vec2 resolution = scene->Domain()->Resolution();
float left = -((float)resolution.x * zoomInverse_);
float right = -left;
float bottom = -((float)resolution.y * zoomInverse_);
float top = -bottom;
projectionMatrix = glm::ortho(left, right, bottom, top, -farClippingPlane_, farClippingPlane_);
}
else
{
projectionMatrix = glm::perspective(glm::radians(zoom_),
(float)scene->Domain()->Aspect(),
nearClippingPlane_, farClippingPlane_);
}
return projectionMatrix;
}
glm::mat4 ZCamera::ViewMatrix()
{
return glm::lookAt(Position(), Position() + Front(), Up());
}
Been trying all kinds of small changes but I still don't get correct shadows. Don't know what I'm doing wrong here. The closest I've gotten is by scaling lightspaceRegion_ bounds by a factor of 10 in the light space matrix calculations (only in X and Y) but the shadows are still no where near correct.
The camera near and far clipping planes are set at reasonable values (0.01 and 100.0, respectively), camera zoom is 45.0 degrees and scene→Domain()→Aspect() just returns the width/height aspect ratio of the framebuffer's resolution. My shadow map resolution is set to 2048x2048.
Any help here would be much appreciated. Let me know if I left out any important code or info.
I'm attempting to rotate a cube around an axis and it's definitely behaving incorrectly. I'm assuming the problem lies in my matrix rotation code as everything else seems to be working. I can translate the model correctly along the x, y or z axis, as well as scale. My camera view matrix is working as expected as well and so is my projection matrix. If I remove the view matrix and or the projection matrix implementations the problem remains.
If you wish to see what result I'm getting, it's the exact same output as the gif shown on this stackoverflow post: Rotating a cube in modern opengl... looks strange
The cube appears to fold in on itself while rotating, then returns to normal after a full rotation and seems to rotate fine for about 20 degrees until folding in on itself again and repeating. My issue is the same as that in the linked to article, however my matrix class is not the same, so my problem, though the same, seemingly has a different solution.
Here's my stripped matrix declaration with possibly relevant operators
math.h
typedef struct matrix4x4
{
//Elements stored in ROW MAJOR ORDER
GLfloat matrix[16];
void translate(Vector3f translation);
void rotateX(GLfloat angle);
void rotateY(GLfloat angle);
void rotateZ(GLfloat angle);
void rotate(Vector3f angles);
void scale(Vector3f scales);
void scale(GLfloat scale);
inline matrix4x4& operator*=(const matrix4x4& rhs)
{
this->matrix[0] = this->matrix[0] * rhs.matrix[0] + this->matrix[1] * rhs.matrix[4] + this->matrix[2] * rhs.matrix[8] + this->matrix[3] * rhs.matrix[12];
this->matrix[1] = this->matrix[0] * rhs.matrix[1] + this->matrix[1] * rhs.matrix[5] + this->matrix[2] * rhs.matrix[9] + this->matrix[3] * rhs.matrix[13];
this->matrix[2] = this->matrix[0] * rhs.matrix[2] + this->matrix[1] * rhs.matrix[6] + this->matrix[2] * rhs.matrix[10] + this->matrix[3] * rhs.matrix[14];
this->matrix[3] = this->matrix[0] * rhs.matrix[3] + this->matrix[1] * rhs.matrix[7] + this->matrix[2] * rhs.matrix[11] + this->matrix[3] * rhs.matrix[15];
this->matrix[4] = this->matrix[4] * rhs.matrix[0] + this->matrix[5] * rhs.matrix[4] + this->matrix[6] * rhs.matrix[8] + this->matrix[7] * rhs.matrix[12];
this->matrix[5] = this->matrix[4] * rhs.matrix[1] + this->matrix[5] * rhs.matrix[5] + this->matrix[6] * rhs.matrix[9] + this->matrix[7] * rhs.matrix[13];
this->matrix[6] = this->matrix[4] * rhs.matrix[2] + this->matrix[5] * rhs.matrix[6] + this->matrix[6] * rhs.matrix[10] + this->matrix[7] * rhs.matrix[14];
this->matrix[7] = this->matrix[4] * rhs.matrix[3] + this->matrix[5] * rhs.matrix[7] + this->matrix[6] * rhs.matrix[11] + this->matrix[7] * rhs.matrix[15];
this->matrix[8] = this->matrix[8] * rhs.matrix[0] + this->matrix[9] * rhs.matrix[4] + this->matrix[10] * rhs.matrix[8] + this->matrix[11] * rhs.matrix[12];
this->matrix[9] = this->matrix[8] * rhs.matrix[1] + this->matrix[9] * rhs.matrix[5] + this->matrix[10] * rhs.matrix[9] + this->matrix[11] * rhs.matrix[13];
this->matrix[10] = this->matrix[8] * rhs.matrix[2] + this->matrix[9] * rhs.matrix[6] + this->matrix[10] * rhs.matrix[10] + this->matrix[11] * rhs.matrix[14];
this->matrix[11] = this->matrix[8] * rhs.matrix[3] + this->matrix[9] * rhs.matrix[7] + this->matrix[10] * rhs.matrix[11] + this->matrix[11] * rhs.matrix[15];
this->matrix[12] = this->matrix[12] * rhs.matrix[0] + this->matrix[13] * rhs.matrix[4] + this->matrix[14] * rhs.matrix[8] + this->matrix[15] * rhs.matrix[12];
this->matrix[13] = this->matrix[12] * rhs.matrix[1] + this->matrix[13] * rhs.matrix[5] + this->matrix[14] * rhs.matrix[9] + this->matrix[15] * rhs.matrix[13];
this->matrix[14] = this->matrix[12] * rhs.matrix[2] + this->matrix[13] * rhs.matrix[6] + this->matrix[14] * rhs.matrix[10] + this->matrix[15] * rhs.matrix[14];
this->matrix[15] = this->matrix[12] * rhs.matrix[3] + this->matrix[13] * rhs.matrix[7] + this->matrix[14] * rhs.matrix[11] + this->matrix[15] * rhs.matrix[15];
return *this;
}
}matrix4x4;
matrix4x4 createTransformationMatrix(Vector3f translation, Vector3f rotation, Vector3f scale);
matrix4x4 createPerspectiveProjectionMatrix(GLfloat width, GLfloat height, GLfloat fov, GLfloat nearPlane, GLfloat farPlane);
matrix4x4 createViewMatrix(Vector3f cameraPosition, GLfloat cameraPitch, GLfloat cameraYaw, GLfloat cameraRoll);
and it's relevant implementations
math.cpp
matrix4x4::matrix4x4(GLfloat elements[])
{
//Elements stored in ROW MAJOR ORDER
for (unsigned int i = 0; i <= elementCount; i++)
{
matrix[i] = elements[i];
}
}
void matrix4x4::setIdentity()
{
std::fill(matrix, matrix + sizeof(matrix) / sizeof(GLfloat), 0.0f);
matrix[0] = 1;
matrix[5] = 1;
matrix[10] = 1;
matrix[15] = 1;
}
/*/////////////////////////////////////////////////////
math
/////////////////////////////////////////////////////*/
void matrix4x4::translate(Vector3f translation)
{
GLfloat transformElements[16] =
{
1.0f, 0.0f, 0.0f, translation.x,
0.0f, 1.0f, 0.0f, translation.y,
0.0f, 0.0f, 1.0f, translation.z,
0.0f, 0.0f, 0.0f, 1.0f
};
matrix4x4 transform = matrix4x4(transformElements);
*this *= transform;
}
void matrix4x4::rotateX(GLfloat angle)
{
angle = degreesToRadians(angle);
GLfloat transformElements[16] =
{
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, std::cos(-angle), -std::sin(-angle), 0.0f,
0.0f, std::sin(-angle), std::cos(-angle), 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
};
matrix4x4 transform = matrix4x4(transformElements);
*this *= transform;
}
void matrix4x4::rotateY(GLfloat angle)
{
angle = degreesToRadians(angle);
GLfloat transformElements[16] =
{
std::cos(-angle), 0.0f, std::sin(-angle), 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
-std::sin(-angle), 0.0f, std::cos(-angle), 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
};
matrix4x4 transform = matrix4x4(transformElements);
*this *= transform;
}
void matrix4x4::rotateZ(GLfloat angle)
{
angle = degreesToRadians(angle);
GLfloat transformElements[16] =
{
std::cos(-angle), -std::sin(-angle), 0.0f, 0.0f,
std::sin(-angle), std::cos(-angle), 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
};
matrix4x4 transform = matrix4x4(transformElements);
*this *= transform;
}
void matrix4x4::rotate(Vector3f angles)
{
matrix4x4 transform = matrix4x4();
transform.setIdentity();
transform.rotateX(angles.x);
transform.rotateY(angles.y);
transform.rotateZ(angles.z);
*this *= transform;
}
void matrix4x4::scale(Vector3f scales)
{
GLfloat transformElements[16] =
{
scales.x, 0.0f, 0.0f, 0.0f,
0.0f, scales.y, 0.0f, 0.0f,
0.0f, 0.0f, scales.z, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
};
matrix4x4 transform = matrix4x4(transformElements);
*this *= transform;
}
matrix4x4 createTransformationMatrix(Vector3f translation, Vector3f rotation, Vector3f scale)
{
matrix4x4 transformationMatrix;
transformationMatrix.setIdentity();
//I've tried changing the order of these around, as well as only
//doing one operation (skipping translate and scale, or everything but a single axis rotation
transformationMatrix.translate(translation);
transformationMatrix.rotate(rotation);
transformationMatrix.scale(scale);
return transformationMatrix;
}
matrix4x4 createPerspectiveProjectionMatrix(GLfloat width, GLfloat height, GLfloat fov, GLfloat nearPlane, GLfloat farPlane)
{
matrix4x4 projectionMatrix;
projectionMatrix.setIdentity();
GLfloat aspectRatio = width / height;
projectionMatrix.matrix[0] = (1.0f / std::tan((degreesToRadians(fov)) / 2.0f) / aspectRatio);
projectionMatrix.matrix[5] = 1.0f / std::tan((degreesToRadians(fov)) / 2.0f);
projectionMatrix.matrix[10] = (farPlane + nearPlane) / (nearPlane - farPlane);
projectionMatrix.matrix[11] = (2.0f * farPlane * nearPlane) / (nearPlane - farPlane);
projectionMatrix.matrix[14] = -1.0f;
return projectionMatrix;
}
I know my matrix/vector implementations are quick and dirty, but I'm just trying to get something set up. I've got plans to make the math methods (scale, translate, etc) static methods that don't affect the contents of the matrix, but instead accept a matrix as input and return a new one... but that's not the issue right now.
Here's my vertex shader
#version 330 core
//declare inputs
in vec3 position;
in vec2 textureCoords;
//declare output
out vec2 pass_textureCoords;
//uniforms
uniform mat4 transformationMatrix;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
void main(void)
{
//tell OpenGL where to render the vertex on screen
gl_Position = projectionMatrix * viewMatrix * transformationMatrix * vec4(position.x, position.y, position.z, 1.0);
pass_textureCoords = textureCoords;
}
My render method...
void Renderer::render(Entity entity, Shader* shader)
{
...
RawModel* rawModel = texturedModel->getRawModel();
glBindVertexArray(rawModel->getVaoID());
...
matrix4x4 transformationMatrix = createTransformationMatrix(entity.getPosition(), entity.getRotation(), entity.getScale());
shader->loadTransformationMatrix(transformationMatrix);
...
glDrawElements(GL_TRIANGLES, rawModel->getVertexCount(), GL_UNSIGNED_INT, 0);
...
}
And finally the relevant pieces from my main. The cube definitions and so on
//This is a simple cube
std::vector<GLfloat> vertices =
{
-0.5f,0.5f,-0.5f,
-0.5f,-0.5f,-0.5f,
0.5f,-0.5f,-0.5f,
0.5f,0.5f,-0.5f,
-0.5f,0.5f,0.5f,
-0.5f,-0.5f,0.5f,
0.5f,-0.5f,0.5f,
0.5f,0.5f,0.5f,
0.5f,0.5f,-0.5f,
0.5f,-0.5f,-0.5f,
0.5f,-0.5f,0.5f,
0.5f,0.5f,0.5f,
-0.5f,0.5f,-0.5f,
-0.5f,-0.5f,-0.5f,
-0.5f,-0.5f,0.5f,
-0.5f,0.5f,0.5f,
-0.5f,0.5f,0.5f,
-0.5f,0.5f,-0.5f,
0.5f,0.5f,-0.5f,
0.5f,0.5f,0.5f,
-0.5f,-0.5f,0.5f,
-0.5f,-0.5f,-0.5f,
0.5f,-0.5f,-0.5f,
0.5f,-0.5f,0.5f
};
std::vector<GLfloat> textureCoords =
{
...
};
std::vector<GLuint> indices =
{
0,1,3,
3,1,2,
4,5,7,
7,5,6,
8,9,11,
11,9,10,
12,13,15,
15,13,14,
16,17,19,
19,17,18,
20,21,23,
23,21,22
};
//parameters are (model, pos, rotation, scale)
Entity entity = Entity(&texturedModel, Vector3f(0.0f, 0.0f, -2.0f), Vector3f(0.0f, 0.0f, 0.0f), 1.0f);
//SHADER STUFF
Shader textureShader = Shader("uniformVarTextureShader");
textureShader.loadProjectionMatrix(display.getProjectionMatrix());
Camera cam;
//draw in wireframe mode
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
//glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
while (display.checkForClose() == 0)
{
glfwPollEvents();
//TO DO: update logic here
//entity.varyPosition(+0.005f, 0.0f, -0.002f); //this works, as does scaling and camera movement
//entity.varyRotation(0.25f, 0.18f, 0.0f);
entity.setYRotation(entity.getYRotation() + 0.25f); //any sort of rotation operation ends up with the strange behaivor
//rendering commands here
display.prepare();
textureShader.bind();
textureShader.loadViewMatrix(cam);
display.render(entity, &textureShader);
textureShader.stop();
display.swapBuffers();
}
So, to recap; I'm not having any issues with translating, scaling, "camera movement" and the projection matrix appears to work as well. Any time I attempt to rotate however, I get the exact same behavior as the linked to article above.
Final notes: I have depth testing enabled and clear the depth buffer each frame. I also pass GL_TRUE to transpose any matrix data I give to glUniformMatrix4fv. I've checked the locations of each of the uniforms and they are passing correctly; 0, 1 and 2 respectively. No -1.
I'm stumped, any help would be appreciated. I can post more code if need be, but I'm pretty sure this covers the entirety of where the problem most likely lies. Thanks again
The major issue is the matrix multipolication operation.
Since you manipulate the matrix (you read from the matrix and you write to it), are some elements already manipulated, before you read it.
e.g. In the first line this->matrix[0] is written to
this->matrix[0] = this->matrix[0] * rhs.matrix[0] + this->matrix[1] * rhs.matrix[4] + this->matrix[2] * rhs.matrix[8] + this->matrix[3] * rhs.matrix[12];
and in the second line this->matrix[0] is read again:
this->matrix[1] = this->matrix[0] * rhs.matrix[1] + this->matrix[1] * rhs.matrix[5] + this->matrix[2] * rhs.matrix[9] + this->matrix[3] * rhs.matrix[13];
Copy the matrix array to a local variable, to solve the issue:
matrix4x4& operator*=(const matrix4x4& rhs)
{
matrix4x4 act( this->matrix );
this->matrix[0] = act.matrix[0] * rhs.matrix[0] + act.matrix[1] * rhs.matrix[4] + act.matrix[2] * rhs.matrix[8] + act.matrix[3] * rhs.matrix[12];
this->matrix[1] = act.matrix[0] * rhs.matrix[1] + act.matrix[1] * rhs.matrix[5] + act.matrix[2] * rhs.matrix[9] + act.matrix[3] * rhs.matrix[13];
....
return *this;
}
By the way, since you multiply a vector to the matrix from the right, in the shader
gl_Position = projectionMatrix * viewMatrix * transformationMatrix * vec4(position.x, position.y, position.z, 1.0);
the matrix has to be initilized in column major order:
mat4 m44 = mat4(
vec4( Xx, Xy, Xz, 0.0),
vec4( Yx, Xy, Yz, 0.0),
vec4( Zx Zy Zz, 0.0),
vec4( Tx, Ty, Tz, 1.0) );
Note your matrices are initialized in row major order e.g. matrix4x4::translate:
GLfloat transformElements[16] =
{
1.0f, 0.0f, 0.0f, translation.x,
0.0f, 1.0f, 0.0f, translation.y,
0.0f, 0.0f, 1.0f, translation.z,
0.0f, 0.0f, 0.0f, 1.0f
};
So you have to transpose the matrix when you set it to the uniform glUniformMatrix4fv:
glUniformMatrix4fv( ..., ..., GL_TRUE, ... );