|
This tutorial is under construction (as of Dec. 19, 2007).
One section (probably the most important one) is missing.
|
Goal:
This tutorial wants to give some hints about how to successfully handle rotations in the context of X3D (and VRML).
Target Audience:
Content authors of X3D or VRML content who need to write scripts for bringing their applications to live and ask themselves,
how to specify and handle rotations.
This tutorial is not suitable for poeple who can get along with WYSIWIG modelling tools like 3ds Max or blender.
Opinion:
Sometimes the opinion of the author is expressed.
In that cases the word 'I' is marked with '(hst)', which is an acronym for "Herbert Stocker".
The SFRotation data type in X3D
The SFRotation data type specifies a rotation. However, it is often used for orientations.
In that case it specifies the rotation that brings an unrotated object into a desired orientation.
This is similar to points and vectors. Like a vector is a shift operation that when applied to
the O vector (0, 0, 0) describes a point in space, a rotation is a rotate operation that when
applied to an object in default orientation, describes its orientation in space.
Now enough of that abstract theory things.
In the following we will see how to handle the SFRotation type,
see that Euler angles are not usefull,
and see how to convert yaw-pitch-roll into SFRotations.
What does Axis-Angle mean?
The Axis-Angle representation of an SFRotation means that you specify 3 values (floating point values)
to specify a rotation axis, and one value (a floating point value) to specify the angle (in rad).
This sounds simple and understandible, but actually is not very intuitive. So my advice is, to see SFRotations
as opaque objects that you use only via their operators. This means that you don't look at the numbers
in an SFRotation and use only methods like .multVec(.) to apply them to an SFVec3f or .multiply(.) to combine
two SFRotations, or you send them to a Transform node.
|
|
|
Consider SFRotations as opaque objects.
I.e. don't look at the numbers they contain.
Only access them via methods like .multVec(.), .multiply(.), etc.
|
|
There is one exception:
There are some rotations that are simple enough, so that you can specify them via their numbers intuitively.
These are the rotations around the axes, and maybe a little more.
X-Axis: var OriX= new SFRotation(1, 0, 0, Angle);
Y-Axis: var OriY= new SFRotation(0, 1, 0, Angle);
Z-Axis: var OriZ= new SFRotation(0, 0, 1, Angle);
|
Other SFRotations you build as combinations of them. There is also a very handy constructor that you can
give two SFVec3f vectors and it calculates the rotation from the first to the second:
var VecA= new SFvec3f(1, 2, 3); // just some numbers.
var VecB= new SFVec3f(4, 5, 6); // just some numbers.
var Ori= new SFRotation(VecA, VecB);
|
Other representations
Euler Angles
There is a misconception with Euler Angles. These are not yaw-pitch-roll angles. Wikipedia says:
To add to the confusion, flight and aerospace engineers, when using yaw, pitch and roll to refer
to rotations about moving frames, often call these Euler angles. These angles in moving frames
are properly known as the Tait-Bryan angles, also
called Cardan angles or nautical angles.
From: Wikipedia → Euler angles
Euler angles have multiple representations, problems like gimbal locks and I don't find them inutitive (hst). But if you want
to know more about them, have a look at Euler Angles at Wikipedia and Euler Angles at Mathworld.
Yaw-Pitch-Roll
Yaw, pitch and roll are also known as 'Tait-Bryan angles' or 'Cardan' angles, and are often confused with 'Euler angles'.
This picture has been authored by ZeroOne and is licensed under the GNU Free Documentation License
and under a Createive Commons license. See the pictures homepage for details.
If applied in this order, yaw, pitch and roll angles can be understood as an instruction list to orient an object in space.
It is easier to described with an object that has a kind of viewing direction, e.g. an aeroplane or a television camera.
- Yaw rotates the object horizontally, i.e. makes it point into the desirect compass direction.
- Pitch then elevates the viewing direction of the object either up (positive pitch) or down (negative pitch)
Yaw and pitch are actually enough to describe the viewing direction of the object. However we still have
one degree of freedom, and this is the rotation about that viewing direction.
See Isn't a Direction enough to specify an SFRotation? for details.
- Roll rotates around the viewing direction defined by yaw and pitch.
Matrices
Matrices are a combination of 3 x 3 or 4 x 4 numbers that can be used to describe (affine) transformations in 3D space.
One matrix can hold all numbers that are required to perform rotations, scale, shears and (in case of 4 x 4 matrices) also translations
in one step. Matrices are good if you want to transform a large number of vectors (vertice coordinates) with the same combination of these base
transformations. Then you calculate the matrix and multiply it with all the vectors.
However, except for
some simple forms, matrices are not very intuitive for authoring a 3D scene becuase their features are distributed among almost all the numbers.
Quaternions
Quaternions are similar to axis-angle representations. 3 numbers describe the direction of the axis, and one number describes the angle.
However, some sin and cos of the angle are already incorporated into these numbers, so that calculations with them are as easy as with matrices.
Quaternions can be seen as an extension of complex numbers to 4D, but that's not so important for us as VRML/X3D authors.
Conclusion
|
|
|
For us VRML/X3D authors, euler angles, matrices and quaternions and are difficult to handle and axis-angle is used in SFRotations but are still little intuitive.
We would like to specify orientations in terms of yaw-pitch-roll angles, or by just specifying a viewing direction.
Therefore we should see SFRotations as opaque objects, and develop some algorithms that convert from yaw-pitch-roll or viewing-direction to SFRotations.
|
|
Why is a Direction not enough?

Click the above image to see a live, interactive demo.
Poeple often intuitively think that specifying a viewing direction, or a target point should be enough to specify how to orient a camera.
This is right in real live where you just need to know where an object is, and then you can target your head, a camera or maybe an aeroplane
towards that object.
But it assumes that the head, camera or aeroplane is always aligned up-right. To generally specify an orientation, this is not enough.
It is the rotation about the viewing direction, which is the missing point.
Imagine somebody who is laying in bed looking to the side towards a person in the neighbouring bed.
The person would see something different than if she would sit up-right on her bed. (though her brain
is compensating this.)
Also in case of a car that is overturning because of an accident, specifying only the viewing
direction is not enough to describe what the poor driver sees.
But when i do have only a viewing direction
No problem, you're assuming that your object is oriented up-right. See Orienting a Camera Towards an Object for the necessary calculations.
Orienting a Camera Towards an Object
You have the position CamPos of a camera (or a gun, or a space ship, or whatever) and the position ObjPos of an object that you want to orient the
camera towards.
Then you can calculate the difference of both vectors and have the viewing direction Dir for the camera.
Now one could say, we have the viewing direction DirNull of the unrotated camera, and a constructor that constructs an SFRotation out of two vectors.
function TargetCameraToObject(/*SFVec3f*/ CamPos, /*SFVec3f*/ ObjPos)
{
var Dir= ObjPos.subtract(CamPos);
var DirNull= new SFVec3f(0, 0, -1);
// This applies for the default viewing direction of Viewpoint nodes.
// Use whatever you like here.
var CamOri= new SFRotation(DirNull, Dir);
return CamOri;
}
|
This is right, and the SFRotation constructor will perfectly target your camera at the object. But it will do only that.
I.e. it will not do anything to keep your camera aligned up-right. It will just find the shortest rotation between the default viewing
direction and the desired one.
Viewing an object through such a camera may feel like riding a roller coaster. See example.
So we need to find a better algorithm to calculate the camera orientation.
We do this by first rotating the camera horizontally and then elevating it. Both rotations keep the up-right alignment if it was there initially.
// Preconditions: The unrotated camera must be modeled so that it looks into
// negative Z direction and is aligned up-right.
function TargetCameraToObject(/*SFVec3f*/ CamPos, /*SFVec3f*/ ObjPos)
{
var Dir= ObjPos.subtract(CamPos);
var DirNull= new SFVec3f(0, 0, -1);
// first, we remove the elevation of our direction vector, but store it for later use.
var Y= Dir.y;
Dir.y= 0;
// Dir is horizontal now and for this we can use the two-vector constructor of SFRotation.
var OriHorz= new SFRotation(DirNull, Dir);
// To elevate our camera up or down towards the object, we need to calculate an
// apropriate SFRotation. We can calculate the elevation angle from the saved
// Y coordinate of our direction vector, and the axis to rotate about is the X-axis of
// the camera, which has already been rotated horizontal.
var ElevAngle= Math.atan(Y / Dir.length());
var ElevAxis= OriHorz.multVec(new SFVec3f(1, 0, 0));
var OriElevation= new SFRotation(ElevAxis, ElevAngle);
// Now we just need to compbine both orientations to one and have the desired
// camera orientation.
var CamOri= OriHorz.multiply(OriElevation);
// NOTE: There's a pitfall. At least with VRML97, the standard did not specify
// in which order two orientations have to be multiplied. So some VRML players
// need the line var CamOri= OriElevation.multiply(OriHorz);
// instead. :-(
return CamOri;
}
|
For calculating OriElevation this function uses (1, 0, 0) as the right-vector of the unrotated camera.
This applies to a camera that looks into negative Z direction and is aligned up-right.
Therefore the statement in the preconditions.
A shorter version of the function is this:
// Preconditions: The unrotated camera must be modeled so that it looks into
// negative Z direction and is aligned up-right.
function TargetCameraToObject(/*SFVec3f*/ CamPos, /*SFVec3f*/ ObjPos)
{
var Dir= ObjPos.subtract(CamPos);
var Y= Dir.y;
Dir.y= 0;
var OriHorz= new SFRotation(new SFVec3f(0, 0, -1),
new SFVec3f(Dir.x, 0, Dir.z));
return CamOri= OriHorz.multiply(new SFRotation(OriHorz.multVec(
new SFVec3f(1, 0, 0)), Math.atan(Y / Dir.length())));
}
|
__.-.__ end of document
|