Advertisement

Is there any problem with my camera rotation logic using quaternions?

Started by August 23, 2021 08:29 AM
8 comments, last by Gnollrunner 3 years, 2 months ago

Hi.

I'm implementing a first person camera.
Actually, I already implemented the camera using Euler angle but I'm changing rotation way.

btw this is in the DirectX.

D3D11 Coordinate System - Stack Overflow

(z: Forward Vector, x: Right Vector, y: Up Vector)
I write my logic, but the result something wrong.
Can you guys check the logic?

1. Get x axis(right vector) from cross product between UP vector and FORWARD vector.
2. Create quaternion based the axis from (1) and constant angle.
3. Rotate forward and up vector with the quaternion from (2) (Calculate qpq*)
4. Create quaternion based the UP vector updated in (3).
5. Rotate forward vector with the quaternion from (4) (also qpq*)

Maybe this logic is right and other things in my code could be wrong.
But I need to be sure if this logic is fine.

First you can definitely use quaternions for rotations directly. Some people only use them for storage and convert them to matrixes first, but they do work the other way and I sometimes do that myself. I haven't really benchmarked it though. I'm not 100% sure what you are doing, but I would think you should rotate around the up axis first (i.e. look right / left) and then rotate around the updated right axis after (look up / down). Either that or don't use the updated up axis for right left rotation. Use the original one instead.

Advertisement

@Gnollrunner

Thank you.

But I'm still getting wrong result. I think there is another problem.

And can I ask you something more?

In the below, are the two way all makes sense? Because the second way gives me more wrong result.

1. Accumulate pitch and yaw. And rotate original vector with pitch and yaw accumulated.

ex. (pseudo code)

m_fPitch += (+ or -)fMouseRotationPerFrame;
rotate(OrignalVector, Quaternion(axis, m_fPitch));

2. Rotate the vector accumulated in previous frame.

ex.

rotate(prevVector, Quaternion(axis, (+ or -)fMouseRotationPerFrame);

In my case I deal with 3rd person cameras and I have to support any orientation since my planets are spherical so there's no strict up direction. There is an up, forward and right for the target (character, ship, whatever) of the camera, and I base camera movement solely on that. I guess It's closer to your 2nd case. I also have springs on the camera which complicates things further.

There is also the question of what frame of reference your camera working in. If you are simply looking the way you are facing, the camera controller is pretty much the same as the character controller with the addition of look up and look down. There is more than one way to do it. That being said you likely do NOT want to have a rotation per frame value unless it can be guaranteed that your frame rate is constant. It's typically better to base it on time since even if your frame rate changes the rotation rates will stay the same.

What exactly is not working? Did you write your own quaternion library or is this a library you downloaded from somewhere?

@Gnollrunner

I'm sorry I was confused, mine is 3rd person camera too.

And I used Direct3D API. The thing about the frame rate, actually I do in real code.

And about the result, can you watch my youtube video?
There are two coordinate systems. The one in the cube is cube's orientation. and the other is camera's orientation.

If you take a look camera's axis, it seems like normal.
But rendered objects seems unnormal.

eu5 said:

Hi.

I'm implementing a first person camera.
Actually, I already implemented the camera using Euler angle but I'm changing rotation way.

btw this is in the DirectX.

D3D11 Coordinate System - Stack Overflow

(z: Forward Vector, x: Right Vector, y: Up Vector)
I write my logic, but the result something wrong.
Can you guys check the logic?

1. Get x axis(right vector) from cross product between UP vector and FORWARD vector.
2. Create quaternion based the axis from (1) and constant angle.
3. Rotate forward and up vector with the quaternion from (2) (Calculate qpq*)
4. Create quaternion based the UP vector updated in (3).
5. Rotate forward vector with the quaternion from (4) (also qpq*)

Maybe this logic is right and other things in my code could be wrong.
But I need to be sure if this logic is fine.

Point 1 is incorrect, cross product between UP vector and FORWARD vector is negative x axis (-X).

UP x FORWARD = -X

FORWARD x UP = +X

The result will be that the rotation angle applied to that quaternion (-X instead of expected +X) is in the opposite direction.

quaternion(angle, -X) = quaternion(-angle, +X)

That could be the issue with the pitch expected rotation.

None

Advertisement

@Gotanod

Thank you for your answer!

But in DirectX using left hand coordinate system, isn't "UP X FORWARD" x axis(right vector)?

@eu5 yes, with a left-handed system, up x forward = +X (as shown in your picture).

Please, do a little test, use q*pq instead of qpq* that will invert the rotations.

None

It looks like you are rotating your camera around it's position. For a 3rd person camera you want to rotate it around your targets position. Forget the math for a second and think of what you actually need to do. You have an object in space and a camera pointing to it as if it's on a pole, that has the camera at one end and and the object at the other. No matter where you move the pole, the camera always points to the object.

Now we give our object an up vector. For a character this points from his feet to his head. We also have a forward vector pointing the way he's facing and a right vector. This defines a coordinate system for our camera with the origin at the target (not where the camera is). Now things should work assuming you did the math right. As long as we keep the camera in this coordinate system, no matter how the character moves the camera will track him. If we want to move the camera around the character we do it in that coordinate system not the global coordinate system.

There are also some variations. What I do is I still keep the camera and the character in the same parent coordinate system. The camera also has an azimuth, elevation and distance ( (let's call them AED) from the character. When the character moves I have a few options. I can reposition the camera so the AED hasn't changed. However I generally want the camera to move smoothly so I generate a target position for the camera and I accelerate the camera towards that position over several frames. I also have to keep a running update of everything as the character will likely still be moving. I can have separate settings for AE and D, so for instance A can move smoothly but E and D can track the character directly.

So there's a lot ways to do this but start simple and get it working first.

@Gotanod @gnollrunner

Thank you guys! I'm late. I've been figured out my code for a few days.
I think the order of multiplying quaternions and setting base axis were the problem..
I don't understand all now, but I'll refer you guys answers.

This topic is closed to new replies.

Advertisement