I am developing a controller in WPF 3D (using C#) to be able to easily move and rotate a ProjectionCamera
using Move()
- and Pitch()
-functions. My controller will become a Behavior<ProjectionCamera>
that can be attached to a ProjectionCamera
. In order to initialize the controller, I want to calculate the current rotation of the camera by looking at its current Up
and Forward
-vectors and compare them to the default camera orientation (Up = [0 1 0]
, Forward = [0 0 -1]
). In other words, I want to calculate a rotation that will transform the camera default's orientation to its current one.
Ultimately, I want to express the rotation as a single Quaternion
, but as an intermediate step I first calculate the Proper Euler Angle rotations of the form z-N-Z expressed as AxisAngleRotation3D
-values, following the default definition of Wikipedia:
var alphaRotation = CalculateRotation(z, x, N);
var betaRotation = CalculateRotation(N, z, Z);
var gammaRotation = CalculateRotation(Z, N, X);
with
CalculateRotation(Vector3D axisOfRotation, Vector3D from, Vector3D to) : AxisAngleRotation3D
The Euler Angle Rotations seem to be calculated correctly, based on some unit tests. However, when I convert these rotations to a single Quaternion
, the resulting Quaternion
represents a rotation that differs from the Euler Angle Rotations, and I don't know why.
This is how I convert the Euler Angles to a single Quaternion:
var rotation =
new Quaternion(alphaRotation.Axis, alphaRotation.Angle) *
new Quaternion(betaRotation.Axis, betaRotation.Angle) *
new Quaternion(gammaRotation.Axis, gammaRotation.Angle);
For example, when I initialize a ProjectionCamera
with an UpDirection
of [1 0 0]
, meaning it's been rotated 90 degrees around its LookDirection
axis ([0 0 -1]
), the calculated Euler Angle Rotations are as follows:
alphaRotation --> 90 deg. around [0 1 0]
betaRotation --> 90 deg. around [0 0 -1]
gammaRotation --> -90 deg. around [1 0 0]
My test verifies that, when applied in order, these rotations will transform the default Up
-vector ([0 1 0]
) into the current Up
-vector ([1 0 0]
), effectively rotating it 90 deg. around the [0 0 -1]
axis. (It's also reasonable straightforward to verify this by hand.)
However, when I apply the calculated QuaternionRotation
to the default Up
-vector, it is transformed to the vector [-1 0 0]
, which is obviously wrong. I have hard-coded these results within a Unit Test and got the same results:
[TestMethod]
public void ConversionTest()
{
var vector = new Vector3D(0, 1, 0);
var alphaRotation = new AxisAngleRotation3D(new Vector3D(0, 1, 0), 90);
var betaRotation = new AxisAngleRotation3D(new Vector3D(0, 0, -1), 90);
var gammaRotation = new AxisAngleRotation3D(new Vector3D(1, 0, 0), -90);
var a = new Quaternion(alphaRotation.Axis, alphaRotation.Angle);
var b = new Quaternion(betaRotation.Axis, betaRotation.Angle);
var c = new Quaternion(gammaRotation.Axis, gammaRotation.Angle);
var combinedRotation = a * b * c;
var x = Apply(vector, alphaRotation, betaRotation, gammaRotation);
var y = Apply(vector, combinedRotation);
}
When you run the test above, you will see that x
gives you the expected vector ([1 0 0]
) but y
will be different, where it should be exactly the same rotation.
What am I missing?