How to calculate direction vectors from axis-angle rotation? - math

I'm representing rotations for actors in my rendering engine using a vec4 with axis-angle notation. The first 3 components (x, y, z) represent the (normalized) axis of rotation, and the last component (w) represents the angle (in radians) we have rotated about this axis.
For example,
With axis (0, 1, 0) and angle 0, up is (0, 1, 0) and forward is (0, 0, -1).
With axis (0, 0, 1) and angle 180, up is (0, 0, 1) and forward is (0, -1, 0).
My current solution (which doesn't work), looks like this:
// glm::vec4 Movable::getOrientation();
// glm::vec3 FORWARD(0.0f, 0.0f, -1.0f);
glm::vec3 Movable::getForward() {
return glm::vec3(glm::rotate(
this->getOrientation().w, glm::vec3(this->getOrientation())) *
glm::vec4(FORWARD, 1.0f));
}
I've defined the up direction to be the same as the rotational axis, but I'm having trouble calculating the forward directional vector for an arbitrary axis. What is the easiest way to do this? I'd like to take advantage of glm functions wherever possible.

One thing to keep in mind about axis-angle is that "up" should mean the same thing for all rotations with an angle of 0, as that represents no rotation no matter which direction the axis is pointed ... you can't just say up is in the direction of the axis. The proper way to calculate forward and up is to start with two vectors which represent them, say (1,0,0) for forward and (0,1,0) for up, and then apply the rotation to both those vectors to obtain the new forward and up.

Related

Scale 3D-Points in Plane

I have some points (3D) all on the same (known) plane. Now I want to scale these points within the plane as opposed to the whole 3D space.
Is there some quick solution for this e.g. a modified scaling matrix?
Can someone help me?
Thanks.
EDIT: I'm more looking for an idea/pseudocode how to do this. If you want use MatLab or some convenient language
Your plane can be known by three non-collinear points P0, P1, P2, or by its implicit equation,
A.x + B.y + C.z + D = 0
In the first case, consider the vector P0P1 and normalize it (U = P0P1/|P0P1|). Then compute a second vector orthogonal with the first, V = P0P2 - (P0P2.U).U and normalize it.
In the second case you can take the three intersection points with the axes, (-D/A, 0, 0), (0, -D/B, 0), (0, 0, -D/C) and you are back in the first case (but mind degenerate cases).
Use the two vectors to compute the desired 2D coordinates of any point P = (X, Y, Z) by the dot products
(x, y) = (P.U, P.V)
(This transform is a rotation that makes P0P1 parallel to the x axis and brings P0P1P2 in the plane xy.)

Forward, right, up vectors - Replace up, but keep relation of forward / right

Let's say I have 3 vectors, forward = Vector(1,0,0), up = Vector(0,1,0), right = Vector(0,0,1).
Now I replace the up vector by something else, but forward and right should stay in relation to the new up vector as they have to the old one.
e.g. if the new up vector is Vector(1,0,0), forward should be Vector(0,-1,0) and right should still be Vector(0,0,1).
What mathematical formula can be used for this?
You can not do it without a rotation axis. Even in your simplified (axis aligned) case where one vector is changed to the opposite direction you need a rotation axis:
Both (actually there are four)
forward( 0,-1, 0), up(1,0,0), right(0, 0, 1) and
forward( 0, 1, 0), up(1,0,0), right(0, 0,-1)
are valid solutions.
However having the rotation from Vector(0,1,0) to Vector(1,0,0), it (may) implicitly defines the rotation axis(0, 0, 1) and angle PI/2. Hence you can build a rotation matrix and multiply that matrix with the two other vectors.

How can I calculate a multi-axis SCNVector4 rotation for a SCNNode?

The SCNNode take a rotation using a SCNVector4, which has an angle (w) and a magnitude how that angle applies to each axis (x, y, z). For example, to rotate 45 degrees around the x-axis I'd create a SCNVector4 like this:
SCNVector4Make(1.0f, 0, 0, DEG2RAD(45))
What I'd like to do is rotate it across all three axis, for example: 45 degrees on the x-axis, 15 degrees on the y-axis and -135 degress across the z-axis. Does anyone know the math to calculate the final SCNVector4?
Instead of rotation property, use eulerAngles and specify angle for each axis
You'll need to generate an SCNVector4 for each of the rotations, and then multiply them. Note that the order of operations matters!
http://www.cprogramming.com/tutorial/3d/rotationMatrices.html has a pretty good writeup of the math. Any OpenGL reference that deals with rotation matrices is worth a look too.
If you're not animating the rotation, it might be cleaner to just set the transform matrix directly, like:
node.transform = CATransform3DRotate(CATransform3DRotate(CATransform3DRotate(node.transform, xAngle, 1, 0, 0), yAngle, 0, 1, 0), zAngle, 0, 0, 1);
Do you ask for rotation matrix or how to simply rotate in general? If the second is correct then for example:
[node runAction:[SCNAction rotateByX:0 y:M_PI z:0 duration:0]];

What is the best way to calculate an element's angle when multiple rotates are applied to it

If you do a rotateX(180deg) rotateY(180deg) it's upside down now. So if the mouse is set to move a child element up on drag that child element will now be moving down (depending on how you have things set up).
-webkit-transform: rotateX(?deg) rotateY(?deg) rotateZ(?deg); // where does it point?
ONLY SETUP FOR WEBKIT
Take a look at the fiddle (code is a mess, stripped down). Draw 360 tic marks, arranged in a circle, on your computer monitor. How can you tell what tic mark the arrow is pointing to (assuming the box is at the exact center of the circle)?
A tutorial that covers the basics is here, here.
*edit - the transform-origin being used is at the center of the cube
Note: Everything that follows assumes you are using a vector that passes through the origin, as in this example. In your original example the vector is additionally offset from the origin by the vector [0, 0, 60]. This complicates calculations slightly, so I have used the simplified version in my explanation.
Your vector is currently defined by spherical coordinates Euler angles consecutively applied rotations to a predefined vector. Here is how you can use your rotations to determine the cartesian coordinates of the final vector:
Let us say your vector is [0, 1, 0] (assuming the arrow is 1 unit long and starts at the origin)
Apply x, y and z rotations by multiplying your vector by the rotation matrices described here in any order, replacing θ with the corresponding angle in each case:
                                             
The resulting vector is your original vector transformed by the specified x, y and z rotations
Once you have obtained the rotated vector, finding the projection of the vector on the x-y plane becomes easy.
For example, considering the vector [10, 20, 30] (cartesian coordinates), the projection on the x-y plane is the vector [10, 20, 0]. The angle of this vector from the horizontal can be calculated as:
tan-1(20/10) = 1.107 rad (counter clockwise from the positive x axis)
                    = 63.43 deg (counter clockwise from the positive x axis)
This means the arrow points between the 63rd and 64th "tick marks" counting counter clockwise from the one pointing directly to the right.

How to calculate azimut & elevation relative to a camera direction of view in 3D ...?

I'm rusty a bit here.
I have a vector (camDirectionX, camDirectionY, camDirectionZ) that represents my camera direction of view.
I have a (camX, camY, camZ) that is my camera position.
Then, I have an object placed at (objectX, objectY, objectZ)
How can I calculate, from the camera point of view, the azimut & elevation of my object ??
The first thing I would do, to simplify the problem, is transform the coordinate space so the camera is at (0, 0, 0) and pointing straight down one of the axes (so the direction is say (0, 0, 1)). Translating so the camera is at (0, 0, 0) is pretty trivial, so I won't go into that. Rotating so that the camera direction is (0, 0, 1) is a little trickier...
One way of doing it is to construct the full orthonormal basis of the camera, then stick that in a rotation matrix and apply it. The "orthonormal basis" of the camera is a fancy way of saying the three vectors that point forward, up, and right from the camera. They should all be at 90 degrees to each other (which is what the ortho bit means), and they should all be of length 1 (which is what the normal bit means).
You can get these vectors with a bit of cross-product trickery: the cross product of two vectors is perpendicular (at 90 degrees) to both.
To get the right-facing vector, we can just cross-product the camera direction vector with (0, 1, 0) (a vector pointing straight up). You'll need to normalise the vector you get out of the cross-product.
To get the up vector of the camera, we can cross product the camera direction vector with the right-facing vector we just calculated. Assuming both input vectors are normalised, this shouldn't need normalising.
We now have the orthonormal basis of the camera. If we stick these vectors into the rows of a 3x3 matrix, we get a rotation matrix that will transform our coordinate space so the camera is pointing straight down one of the axes (which one depends on the order you stick the vectors in).
It's now fairly easy to calculate the azimuth and elevation of the object.
To get the azimuth, just do an atan2 on the x/z coordinates of the object.
To get the elevation, project the object coordinates onto the x/z plane (just set the y coordinate to 0), then do:
acos(dot(normalise(object coordinates), normalise(projected coordinates)))
This will always give a positive angle -- you probably want to negate it if the object's y coordinate is less than 0.
The code for all of this will look something like:
fwd = vec3(camDirectionX, camDirectionY, camDirectionZ)
cam = vec3(camX, camY, camZ)
obj = vec3(objectX, objectY, objectZ)
# if fwd is already normalised you can skip this
fwd = normalise(fwd)
# translate so the camera is at (0, 0, 0)
obj -= cam
# calculate the orthonormal basis of the camera
right = normalise(cross(fwd, (0, 1, 0)))
up = cross(right, fwd)
# rotate so the camera is pointing straight down the z axis
# (this is essentially a matrix multiplication)
obj = vec3(dot(obj, right), dot(obj, up), dot(obj, fwd))
azimuth = atan2(obj.x, obj.z)
proj = vec3(obj.x, 0, obj.z)
elevation = acos(dot(normalise(obj), normalise(proj)))
if obj.y < 0:
elevation = -elevation
One thing to watch out for is that the cross-product of your original camera vector with (0, 1, 0) will return a zero-length vector when your camera is facing straight up or straight down. To fully define the orientation of the camera, I've assumed that it's always "straight", but that doesn't mean anything when it's facing straight up or down -- you need another rule.

Resources