Advertisement

Moving around a sphere with quaternions

Started by June 05, 2015 03:12 AM
12 comments, last by Sobe118 9 years, 8 months ago

I am trying to move a object around a sphere.

The object has its own rotation and forward speed. Then it also has its location.

The location can be used for the creation of the first quaternion but, I do not know how to make the target quaternion from the objects rotation and forward speed.

Almost all of the examples for this type of math are for a camera looking at the origin. I cant figure out how to convert these examples. Because my object doesn't have a target that it is looking at.


Because my object doesn't have a target that it is looking at.

Unless I'm misunderstanding your problem, the target is the center of your sphere.

Advertisement

Maybe I'm not sure how to use quaternions. I assumed the "target" was there the object was going to or looking at.

The object is rotating around the origin, not going to it or looking at it.

What I have is a movement vector in relation to the object x,y,z. But z is always zero because that would be moving away or towards the origin.

Then I have a location vector from the origin to the objects center.

How do I change the location vector based on the movement vector that is from the perspective of the object.

Since a quaternion can encode any orientation, you can actually let it define both the position of an object moving around a sphere, and its direction.

I made a tiny demo once with a bunch of guys walking around a sphere, and my code to update them looks like this:

(math should be possible to simplify further, and the math library is our in-house one, but this is hopefully easy to read, to show the principle:)

//Turn, yaxis of quat is up-vector of object

Vec3 yaxis = minion->pos.yaxis();

minion->pos *= Quat(yaxis,turnSpeed*dt);

//Then move forward, xaxis of quat is the right vector of object

Vec3 xaxis = minion->pos.xaxis();

minion->pos *= Quat(xaxis,walkSpeed*dt);

pos is a quaternion, and both turnSpeed and walkSpeed is in radians/s

The Quat constructors create a new quaternion with a rotation around the specified axis, that I then rotate the pos quaternion with.

Then when building the matrix for drawing them, I just first translate with Vec3(0,sphereRadius,0) (rasing the model up along y-axis in model space) before applying the quat.

You could also pre-translate all your models vertices, and then just apply the quat.

This way, all you need to store in your object i a single quat (plus the two speed floats to make it move), no need for position, direction vector, nor rotation.

If you need the position in world space of your object, you can take the y-axis of the quat and scale it with the radius.

The z-axis is your direction vector.

Distance along the sphere between two objects can be calculated from the smallest angle between the two quats defining the pos/rotation of the two objects.

So everyone can see the answer, I'll answer this PM here:

I searched for these methods, and found it was Java?

//Turn, yaxis of quat is up-vector of object
Vec3 yaxis = minion->pos.yaxis();
minion->pos *= Quat(yaxis,turnSpeed*dt);

Trying to understand the syntax.

"Vec3 yaxis = minion->pos.yaxis();"
My guess at the result of the above code?

if pos = (x, y, z, w);
then after that line of code: yaxis = (0, y, 0);


Thanks

They are C++, but it is our own non-public library.
I assumed those functions are common for quaternion libraries, but now I think they are not.
The axis methods in our library return the axises of the orientation the quaternion defines.
Those are the same values that would be put into a rotation matrix columns when converting the quaternion to a matrix.
(column 0 being x-axis, column 1 y-axis, and column 2 z-axis)
That does include a bunch of multiplications, thats why I said the math probably can be simplified further, I suspect you can get rid of a few by combining the axis-extraction with creating the new rotation-change quaternion, and the rotation.
Since it is basically modifying itself, there is probably some redundancy in the calculations as they are shown...

Still a bit confused if pos.yaxis() returns the y value of pos, that is just a single value.

Then the single value is used to set a Vec3? Doses the y pos magically end up in vec3's y?
Or does vec3 look like {pos.y, pos.y, pos.y}

I further expanded the code (not working for me):

float3 yaxis = {0, pos.y, 0};
float4 yq = quatFromVectAngel(yaxis, turnSpeed);
pos = multiplyQuat(pos, yq);
float3 xaxis = {pos.x, 0, 0};
float4 xq = quatFromVectAngel(xaxis, walkSpeed);
float4 result = multiplyQuat(pos, xq);
-----------------------------------------------------------------------

This code is working for me to make a nice slightly off-set rotation.
But when using the code below the movement from the objects perspective is not clear.

float4 q2 = quatFromVectAngel(make_float3(0, 1, 0.4f), angleRadian);
float4 r = multiplyQuat(pos, q2);
Advertisement

No, its not just the y-value of the quaternion, its the yaxis of the rotation matrix you would get if converting the quaternion to a rotation matrix.

Do you have a way to create a rotation matrix from a quaternion?

I'm guessing you do, you should need it for creating the model to world matrix for drawing your object.

After creating the rotation matrix for the current frame, you could save the axises from that one, and use them as xaxis and yaxis in the next frame.

The xaxis is column 0 of the rotation matrix, yaxis is column 1 and zaxis is column 2.

you could save them as "right", "up" and "forward", maybe those names makes more sense smile.png

That should save some calculations per frame instead of re-calculating them each frame as my demo did, at the cost of a little more memory per entity.

Note:

Realized while writing the above, you can't save both axises from the last frame, then the object should "slide" a bit in the turns, you need to recalculate the xaxis after applying the yaxis rotation... That might look good enough though, or even be desirable depending on what you do, so feel free to experiment smile.png

Quaternion multiplication is not a rotation. Quaternions rotate a vector through conjugation qvq-1. Your function multiplyQuat is thus either named wrong or it has been used in the wrong way.

multiplying two unit quaternions representing two rotations, means combining the rotations of them, and that is what we try to do here.

we have one unit quaternion representing the orientation on the sphere, and multiply it with another unit quaternion representing the change in orientation.

I think he uses it right.

Since the name of the variable was pos (which I usually only use for positions) I assumed he was trying to rotate a point. If the use was different, feel free to ignore my previous comment.

This topic is closed to new replies.

Advertisement