Rather than applying the rotations separately, you can create a transformation from three initial base vectors to three destination base vectors.
For example:
// Transform the base vectors.
transform := BaseVecTrans(
[3]mgl32.Vec3{
{1, 0, 0},
{0, 1, 0},
{0, 0, 1}},
[3]mgl32.Vec3{
{longitudinal.X, longitudinal.Y, longitudinal.Z},
{upward.X, upward.Y, upward.Z},
{normal.X, normal.Y, normal.Z},
},
)
The returned transform
variable is a 4x4 transformation matrix.
The implementation in Go is:
func BaseVecTrans(initVecs, destVecs [3]mgl32.Vec3) mgl32.Mat4 {
// Create a 3x3 matrix from the initial vectors and its inverse.
A := mgl32.Mat3FromCols(initVecs[0], initVecs[1], initVecs[2])
AInv := A.Inv()
// Create a 3x3 matrix from the destination vectors.
B := mgl32.Mat3FromCols(destVecs[0], destVecs[1], destVecs[2])
// Compute the rotation matrix that transforms A to B.
R := B.Mul3(AInv)
// Create a 4x4 transformation matrix from the rotation matrix and a translation vector.
transform := mgl32.Ident4()
transform.SetRow(0, mgl32.Vec4{R.At(0, 0), R.At(0, 1), R.At(0, 2), 0})
transform.SetRow(1, mgl32.Vec4{R.At(1, 0), R.At(1, 1), R.At(1, 2), 0})
transform.SetRow(2, mgl32.Vec4{R.At(2, 0), R.At(2, 1), R.At(2, 2), 0})
transform.SetRow(3, mgl32.Vec4{0, 0, 0, 1})
return transform
}