Jump to content
  • Advertisement
Sign in to follow this  
Zoultrex

How to implement 6 Degrees Of Freedom

This topic is 2922 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I found this old post that explains the idea on how to do it but im stuck.
(check the second last post, by wojjyy)
http://www.gamedev.net/community/forums/topic.asp?topic_id=491391

as he describes in step 2 and 3:
2. get 3 variables like yawChange, pitchChange, rollChange. each frame get user input there
3. build quaternion rotationChange from these.

How do I get the pitch yaw and roll into the quaternion exactly.
My previous attemps failed me, I was doing something like
---------
Quaternion xQuaternion = Quaternion.AngleAxis(rotationX, Vector3.up);
Quaternion yQuaternion = Quaternion.AngleAxis(rotationY, Vector3.left);
Quaternion zQuaternion = Quaternion.AngleAxis(zRotationValue, Vector3.forward);
wantedRotation = xQuaternion * yQuaternion * zQuaternion;
transform.rotation = wantedRotation * transform.rotation
---------

But that was giving me the exact same errors as he described in the post that only 2 axis can be rotated at the same time, if a third one gets in, all the rotations get weird.


I think some more info on my game would help.
I am using unity3d to make this game, and I already have all the quaternions and everything else so I just need to know how to use them.

Unity scripting reference for all the functions can be found here:
http://unity3d.com/support/documentation/ScriptReference/index.html

like this one:
http://unity3d.com/support/documentation/ScriptReference/index.html

My game is a space shooter 6DOF is the way to go.

Part of my code to control the ship is here:
http://pastebin.com/xwkB0BXZ

Some explanation about the code:
-transform is unitys main object that inherits all the main functions and has the meshes attached to.
-Input.GetAxis("Horizontal"): returns a positive or negative value when the keyboard keys A or D are pressed
-transform.Translate(0, 0, speed): moves the object forward based on its z axis

Thanks in advance ;)

Share this post


Link to post
Share on other sites
Advertisement
Quote:
rotationX += Input.GetAxis("Mouse X") * sensitivityX;


That is already a problem. You don't want to accumulate rotationX over time. You want it to be the instantaneous rotation, so use "=", not "+=". You then compute the quaternion that represents how much you want to rotate in this frame, and you use it to modify an existing quaternion that represents current attitude.

The code should look more like this:
        // Controls
// Read the mouse input axis
rotationX = Input.GetAxis("Mouse X") * sensitivityX;
rotationY = Input.GetAxis("Mouse Y") * sensitivityY;

//roll the ship left and right
zRotationValue = (rotationSpeed * Input.GetAxis("Horizontal"));

Quaternion xQuaternion = Quaternion.AngleAxis(rotationX, Vector3.up);
Quaternion yQuaternion = Quaternion.AngleAxis(rotationY, Vector3.left);
Quaternion zQuaternion = Quaternion.AngleAxis(zRotationValue, Vector3.forward);

wantedRotation = zQuaternion * xQuaternion * yQuaternion;

attitude *= wantedRotation;

transform.localRotation = Quaternion.Slerp(transform.localRotation , attitude, Time.deltaTime * rotationDamping);
transform.Translate(0, 0, speed);


Share this post


Link to post
Share on other sites
Welll, it didnt work either.

attitude *= wantedRotation;

transform.localRotation = Quaternion.Slerp(transform.localRotation , attitude, Time.deltaTime * rotationDamping);

It looks like the quaternion attitude never gets any value, if I change it back to wantedRotation I have the same weird rotations as before.

Also the fact that I am incrementing the rotation values over time is that the press and release key values in unity goes from 0.0f to 1.0f so if I release a key or stop moving the mouse the rotation will go back to its original 0 degrees, but thats no biggie, i can get around that.

The main concerns is still the rotations that are not right.

How is a 6DOF implementation different then a normal implementation using degrees and quaternions (basically what I am currently trying to achieve)?

Share this post


Link to post
Share on other sites
Quote:
Original post by Zoultrex
transform.localRotation = Quaternion.Slerp(transform.localRotation , attitude, Time.deltaTime * rotationDamping);

I don't know if you need damping, but it complicates things, so I would use `attitude' directly.

Quote:
It looks like the quaternion attitude never gets any value, if I change it back to wantedRotation I have the same weird rotations as before.

Do you initialize attitude to 1? You should probably also renormalize it periodically (e.g., every time).

Quote:
Also the fact that I am incrementing the rotation values over time is that the press and release key values in unity goes from 0.0f to 1.0f so if I release a key or stop moving the mouse the rotation will go back to its original 0 degrees, but thats no biggie, i can get around that.

I am still not sure you understand why accumulating these values is bad. You are essentially using Euler angles to represent your rotation, and they are a bad way to parametrize rotations. That's the whole point of using "yawChange, pitchChange, rollChange" each frame and updating the rotation incrementally.

You can post code here using [source] and [/source] around it.

Share this post


Link to post
Share on other sites
Ha!

Alvaro you saved my life =)

It seems now to be perfect, here is the code (thanks for the []source tip, i always wondered how its done)

 
[initialize function]
changedRotation.w = 1.0f;
[/]

[controls function]
// Controls
// Read the mouse input axis
rotationX = Input.GetAxis("Mouse X") * sensitivityX;
rotationY = Input.GetAxis("Mouse Y") * sensitivityY;

//roll the ship left and right
zRotationValue = (rotationSpeed * Input.GetAxis("Horizontal"))*-1;

Quaternion xQuaternion = Quaternion.AngleAxis(rotationX, Vector3.up);
Quaternion yQuaternion = Quaternion.AngleAxis(rotationY, Vector3.left);
Quaternion zQuaternion = Quaternion.AngleAxis(zRotationValue, Vector3.forward);

wantedRotation = zQuaternion * xQuaternion * yQuaternion;
changedRotation *= wantedRotation;

transform.localRotation = Quaternion.Slerp(transform.localRotation, changedRotation, Time.deltaTime);
transform.Translate(0, 0, speed);
[/]



For my surprise it seems unity doesnt have a normalize function for quaternions, if it does i cant find it, but anyway there is plenty of those around the internet, this one for example should work:
http://gpwiki.org/index.php/OpenGL:Tutorials:Using_Quaternions_to_represent_rotation#Normalizing_a_quaternion

Alvaro do you see anything wrong with the code now? I kept testing and its working great. Ill make it available online once Im sure its perfect.
In regard to normalizing, its too much to normalize it every frame right? Maybe every 1 second?

Share this post


Link to post
Share on other sites
Quote:
Original post by Zoultrex
Alvaro do you see anything wrong with the code now? I kept testing and its working great.

I'm glad it's working.

Quote:
In regard to normalizing, its too much to normalize it every frame right? Maybe every 1 second?


I would do it every frame and only make it less frequent if it ever shows up in a profiler run (it won't).

Share this post


Link to post
Share on other sites
Quote:
Original post by Zoultrex
For my surprise it seems unity doesnt have a normalize function for quaternions
I haven't seen this documented anywhere, but my guess is that Unity normalizes the quaternion automatically as necessary (such as after calls to Rotate() or whenever a new value is assigned to the 'rotation' or 'localRotation' field).

Although I can't cite any references that confirm this, if you assign a value of (2, 0, 0, 0) to transform.rotation and then print the results, you get (1, 0, 0 ,0), which would seem to verify that this is in fact the case.

Share this post


Link to post
Share on other sites
Quote:
Original post by jyk
Although I can't cite any references that confirm this, if you assign a value of (2, 0, 0, 0) to transform.rotation and then print the results, you get (1, 0, 0 ,0), which would seem to verify that this is in fact the case.


Good point, that is true indeed, so Unity does normalize it by itself.
I have already seen that when I print the quaternions they are mostly 0 or when a rotation value is very different from the current, this value changes to a slightly higher value but then after a shor time it will be zero again, so I think thats whats happening, its being normalized.

I think the code for the rotation is fine, just one thing I noticed, If I apply a rotation much higher then the current rotation, I get a weird zigzag-like motion but just for like half a second and then it comes back to normal.

That wont interfere in the game really as I have now limited the mouse speed (I would have to do that anyway) and that solved the problem. Just wanted to point that out.

I will test it a bit more and will post the code here for those who in the future need a control script for a space ship.

Thank you guys for the help

Share this post


Link to post
Share on other sites
Looks like this topic never gets old. I'm also trying to implement a 6-DOF camera and I'm running into the same problems countless people seem to have run into before. Unfortunately, I have yet to find a solution that works form me. Currently, my biggest problem is unwanted z roll (this old topic has a pretty fitting description).

Basically, the control scheme that I had in mind is the following: as already mentioned, I want the camera to fly freely through the scene using 6-DOF. The position can be controlled with the "WASD" keys and the mouse wheel. If the user moves the mouse up&down/left&right while holding the left mouse button, pitch and yaw are modified. If the user moves the mouse left&right while holding the right mouse button, roll is modified.

Now, the problem is, if I hold the left mouse button and perform a cirular motion I get a LOT of unwanted roll. As long as I stick to only one axis, everything seems normal. I have pretty much worked through all the suggested remedies (such as here or here) and they either did nothing or introduced other problems. This is the version that exhibits the described unwanted roll behavior:

            if (Window.Mouse[MouseButton.Left])
{
Camera.Orientation *= Quaternion.RotateAxisAngle(new vec3(1, 0, 0), +0.01f * (float)e.YDelta) * Quaternion.RotateAxisAngle(new vec3(0, 1, 0), +0.01f * (float)e.XDelta);
}
if (Window.Mouse[MouseButton.Right])
{
Camera.Orientation *= Quaternion.RotateAxisAngle(new vec3(0, 0, 1), +0.01f * (float)e.XDelta);
}

Another thing that strikes me as odd with this version is: if I hold the left mouse down, move it left to rotate 90° around the y-axis, and then move the mouse up and down, I see roll rather than pitch. That's not supposed to happen, right?

So, another version I tried is this:

            var m = Transform.Orientate(Camera.Orientation); // matrix from quaternion

if (Window.Mouse[MouseButton.Left])
{
Camera.Orientation *= Quaternion.RotateAxisAngle(m[0].xyz, +0.01f * (float)e.YDelta) * Quaternion.RotateAxisAngle(m[1].xyz, +0.01f * (float)e.XDelta);
}
if (Window.Mouse[MouseButton.Right])
{
Camera.Orientation *= Quaternion.RotateAxisAngle(m[2].xyz, +0.01f * (float)e.XDelta);
}

In that version, pitch is always pitch, yaw is always yaw etc., but the unwanted roll still persists. At the risk of boring you, here's another one I tried:

            if (Window.Mouse[MouseButton.Left])
{
Camera.Orientation = Camera.Orientation * Quaternion.RotateAxisAngle(new vec3(1, 0, 0), +0.01f * (float)e.YDelta);
Camera.Orientation = Quaternion.RotateAxisAngle(new vec3(0, 1, 0), +0.01f * (float)e.XDelta) * Camera.Orientation;
}

Strangely enough, this one behaves pretty much exactly as the first one. I'm rather clueless what else to try at this point. As somebody mentioned in another thread: Quaternions are beautiful and easy to use as long as they work right, but not intuitive at all once you run into problems.

[Edited by - kloffy on October 21, 2010 10:57:25 PM]

Share this post


Link to post
Share on other sites
Ok, I really didn't want to post another one, but I think I have made a step in the right direction.

        private quat r = new quat(new vec3(), 1.0f);
private quat p = new quat(new vec3(), 1.0f);
private quat y = new quat(new vec3(), 1.0f);

protected void OnMove(object sender, MouseMoveEventArgs e)
{
if (Application.Mouse[MouseButton.Left])
{
p *= Quaternion.RotateAxisAngle(new vec3(1, 0, 0), +0.01f * (float)e.YDelta);
y *= Quaternion.RotateAxisAngle(new vec3(0, 1, 0), +0.01f * (float)e.XDelta);
}
if (Application.Mouse[MouseButton.Right])
{
r *= Quaternion.RotateAxisAngle(new vec3(0, 0, 1), +0.01f * (float)e.XDelta);
}
Camera.Orientation = r * p * y;
}

This has no unwanted roll *yay*, but in some orientations the axes of rotation seem switched. Kind of like in the very first version, where pitch became roll once you rotate 90° around the y axis. (Curiously, this exact case does not cause problems, but e.g. rotating 90° around x does. Maybe this has something to do with the order of multiplications?)

Anyways, the whole thing is very reminiscent of gimbal lock, which I know can happen when quaternions are used improperly. That doesn't bode well for my current code...

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!