Hello everyone,
I am trying to implement my own transformations in my engine. I got both translations and scaling to work but I can't seem to get rotation to work. I am new to matrices and transformations as a whole and this is my first attempt at them.
These are my 2d vector and 3x3 matrix structs and their multiplication operator functions.
union V2f32 {
struct {
f32 x;
f32 y;
};
struct {
f32 w;
f32 h;
};
};
struct Matrix {
f32 a1, a2, a3;
f32 b1, b2, b3;
f32 c1, c2, c3;
};
inline V2f32 operator*(V2f32 lhs, Matrix rhs) {
V2f32 temp = {(lhs.x * rhs.a1) + (lhs.y * rhs.a2) + (1 * rhs.a3),
(lhs.x * rhs.b1) + (lhs.y * rhs.b2) + (1 * rhs.b3)};
return temp;
}
inline void operator*=(V2f32& lhs, Matrix rhs) {
lhs.x = (lhs.x * rhs.a1) + (lhs.y * rhs.a2) + (1 * rhs.a3);
lhs.y = (lhs.x * rhs.b1) + (lhs.y * rhs.b2) + (1 * rhs.b3);
}
inline Matrix operator*(Matrix lhs, Matrix rhs) {
Matrix temp = {(lhs.a1 * rhs.a1) + (lhs.b1 * rhs.a2) + (lhs.c1 * rhs.a3),
(lhs.a1 * rhs.b1) + (lhs.b1 * rhs.b2) + (lhs.c1 * rhs.b3),
(lhs.a1 * rhs.c1) + (lhs.b1 * rhs.c2) + (lhs.c1 * rhs.c3),
(lhs.a2 * rhs.a1) + (lhs.b2 * rhs.a2) + (lhs.c2 * rhs.a3),
(lhs.a2 * rhs.b1) + (lhs.b2 * rhs.b2) + (lhs.c2 * rhs.b3),
(lhs.a2 * rhs.c1) + (lhs.b2 * rhs.c2) + (lhs.c2 * rhs.c3),
(lhs.a3 * rhs.a1) + (lhs.b3 * rhs.a2) + (lhs.c3 * rhs.a3),
(lhs.a3 * rhs.b1) + (lhs.b3 * rhs.b2) + (lhs.c3 * rhs.b3),
(lhs.a3 * rhs.c1) + (lhs.b3 * rhs.c2) + (lhs.c3 * rhs.c3)};
return temp;
}
Here is the code for a rectangle I want to rotate 45 degrees.
{
V2f32 size = {32.0f, 32.0f};
V2f32 pos = {50.0f, 100.0f};
V2f32 vertices[4] = {{-size.x / 2, -size.y / 2},
{ size.x / 2, -size.y / 2},
{ size.x / 2, size.y / 2},
{-size.x / 2, size.y / 2}};
Matrix translation = {1.0f, 0.0f, pos.x,
0.0f, 1.0f, pos.y,
0.0f, 0.0f, 1.0f};
f32 theta = 45 * (PI / 180);
Matrix rotation = {cos(theta), -sin(theta), 0.0f,
sin(theta), cos(theta), 0.0f,
0.0f, 0.0f, 1.0f};
Matrix scale = {1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f};
Matrix transform = translation * rotation * scale;
V4f32 colour = {1.0f, 0.0f, 0.0f, 1.0f};
PushRect(&renderer, &transform, verticies, &colour, true);
}
Renderer is an object that contains all the data needed for my renderer to render stuff. The last argument of PushRect(...) is filled and determines if the rectangle is filled or not.
This is a snippet from PushRect(...) which applies the transform on all the vertices, and sets the min and max value and uses those to find the center position and size of the rectangle for rendering.
V2f32 min, max;
for(i32 i = 0; i < 4; i++) {
vertices[i] *= *transform;
if (i == 0) {
min = vertices[i];
max = vertices[i];
}
if(vertices[i].x < min.x) {
min.x = vertices[i].x;
}
else if(vertices[i].x > max.x) {
max.x = vertices[i].x;
}
if(vertices[i].y < min.y) {
min.y = vertices[i].y;
}
else if(verticies[i].y > max.y) {
max.y = vertices[i].y;
}
}
V2f32 size = max - min;
V2f32 pos = min + (size / 2);
My code doesn't render the rotated rectangle yet it should render a filled axis aligned rectangle around the rotated rectangle, but it doesn't even do that. It renders the rectangle off the screen at (-35.35, 81.06) but should be rendering it at (100, 50). What am I doing wrong? I'm very confused because the translations and scaling work so why doesn't rotation work?
-- Mathew
Edit: Formatting.