I've been trying to get rotations with quaternions to work for a while now, and I feel I am very close to it actually working but I just can't get it to work.
I do not have a view matrix yet and am just working in 2D space to make this slightly easier to set at the moment. So I'm only rotating around the Z axis.
My model matrix is calculated like this
var modelMatrix: matrix_float4x4 {
var modelMatrix = matrix_identity_float4x4
modelMatrix.translate(_position)
modelMatrix.rotate(_orientation)
modelMatrix.scale(_scale)
return matrix_multiply(matrix_identity_float4x4, modelMatrix)
}
_orientation is defined as
private var _orientation: quaternion = quaternion(angle: toRadians(0), axis: float3(0, 0, 1))
quaternion is just a typedef of simd_quatf
my rotate function is
mutating func rotate(_ quat: quaternion) {
let quatMatrix = matrix_float4x4(simd_normalize(quat))
self = matrix_multiply(self, quatMatrix)
}
I also tried to do it with the .act method
mutating func rotate(_ quat: quaternion, _ vec: float3) {
let rotatedVec = quat.act(vec)
self.translate(rotatedVec)
}
This did the seemingly same thing as the first rotate function.
When I initialize _orientation with a rotation of 0, the program acts as normal but when I initialize it with 45, it warps the rectangle:
and when I do it with 90, it produces the same result as with 0, which shouldn't happen. I'm assuming the problem lies somewhere in the way I'm applying the rotation to the object, but I have no clue what it is.
Edit:
Also A thought, maybe it is because of the way I am applying the modelMatrix to the shader positions. I'm pretty sure this is the right way but it might be slightly wrong.
vertex RastData vertexShader(const VertexIn vIn [[stage_in]],
constant ModelMat &modelMatrix [[buffer(1)]]) {
RastData rd;
rd.position = modelMatrix.modelMatrix * float4(vIn.position, 1.0);
rd.color = vIn.color;
return rd;
}
Edit 2: I Have tried to do it with the math described in this answer https://gamedev.stackexchange.com/a/188776/157187 but that did nothing
mutating func rotate(_ angle: Float, _ axis: float3, _ pQuat: quaternion) {
let newQ = quaternion(vector: float4(axis, cos(angle / 2)))
let newPQ = newQ * pQuat * newQ.conjugate
let newVec = float3(newPQ.vector.x, newPQ.vector.y, newPQ.vector.z)
var mat = matrix_identity_float4x4
mat.columns = (
float4(1, 0, 0, 0),
float4(0, 1, 0, 0),
float4(0, 0, 1, 0),
float4(newVec.x, newVec.y, newVec.z, 1)
)
self = matrix_multiply(self, mat)
}
Edit 3: Alright I think the problem lies in my lack of a view and projection matrix, so I have defined some quick ones, not really implemented a camera system, just having the functionality of the view and projection matracies.
I have a function that makes an orthographic projection:
func makeOrthographicMatrix(tooManyArgsLol) {
return float4x4(
float4(2 / (right - left), 0, 0, 0),
float4(0, 2 / (top - bottom), 0, 0),
float4(0, 0, 1 / (far - near), 0),
float4((left + right) / (left - right), (top + bottom) / (bottom - top), near / (near - far), 1)
)
}
This uses the Column constructor so it looks weird but it's correct.
And a view matrix that should be -3 on the Z axis:
var viewMatrix: float4x4 {
var viewMat = matrix_identity_float4x4
viewMat.translate(float3(0, 0, -3))
return viewMat
}
but now all I get is the clearColor I set.
In my vertex shader I do the multiplication like this
cameraMats.projectionMatrix * cameraMats.viewMatrix * modelMatrix.modelMatrix * float4(vIn.position, 1.0);
When I debug using the Metal debugger, it shows that all the data is going through to the shader correctly, so it's definitely some sort of math issue, I just don't really know where to look now.