I am not familiar with Metal's API so I can't be 100% sure on the usage correctness but mathematically what must happen is the following:
- Create a model matrix by applying scaling, rotation then translation, in that order (you are doing the reverse)
- Apply the resulting matrix to each point of the model (that is what the vertex shader does)
Code-wise this would look like:
var modelMatrix: matrix_float4x4 {
var modelMatrix = matrix_identity_float4x4
modelMatrix.scale(_scale)
modelMatrix.rotate(_orientation)
modelMatrix.translate(_position)
return modelMatrix
}
Also the rotation method might need to change to
mutating func rotate(_ quat: quaternion) {
let quatMatrix = matrix_float4x4(simd_normalize(quat))
self = matrix_multiply(quatMatrix, self) // the rotation matrix must be multiplied from the LEFT
}
For the rotation, you must make sure that the quatMatrix
value ends up being
$$C=\begin{pmatrix}
0 & -1 & 0 & 0 \\
1 & 0 & 0 & 0 \\
0 & 0 & 1 & 0 \\
0 & 0 & 0 & 1
\end{pmatrix}.$$
or something very close to it (i.e. the 1x1 and 2x2 cells should be very small values). This is for clockwise 90 degree rotation.
As mentioned, I am not familiar with the API at all so the fixes I've suggested might be incorrect or not needed but that's the theory at least.
The vertex shader looks correct to me, again with assumptions on Metal's shader language.
Finally, remember that since vertex shaders output normalized device coordinates (that is, all coordinates range from \$[-1, 1]\$) you have to compensate for the viewport aspect ratio distortion. What this means is that if you have a square in the vertex shader for example with the top left corner at \$(-200,-200)\$ and bottom right at \$(200,200)\$, these must not be mapped to something like \$(-0.2, -0.2)\$ and \$(0.2, 0.2)\$. Instead the x coordinate must be divided by the viewport's aspect ratio \$(-0.2 / aspectRatio, -0.2)\$ in order for a square to be rendered on the screen. This can be easily done by applying an orthographic projection matrix after the model matrix (view this page https://en.wikipedia.org/wiki/Orthographic_projection on how to create it).