Finding absolute coordinates from relative coordinates in 3D space - math

My question is fairly difficult to explain, so please bear with me. I have a random object with Forward, Right, and Up vectors. Now, imagine this particular object is rotated randomly across all three axis randomly. How would I go about finding the REAL coordinates of a point relative to the newly rotated object?
Example:
How would I, for instance, find the forward-most corner of the cube given its Forward, Right, and Up vectors (as well as its coordinates, obviously) assuming that the colored axis is the 'real' axis.
The best I could come up with is:
x=cube.x+pointToFind.x*(forward.x+right.x+up.x)
y=cube.y+pointToFind.y*(forward.y+right.y+up.y)
z=cube.z+pointToFind.z*(forward.z+right.z+up.z)
This worked sometimes, but failed when one of the coordinates for the point was 0 for obvious reasons.
In short, I don't know what do to, or really how to accurately describe what I'm trying to do... This is less of a programming questions and more of a general math question.

In general, you would have to project all corners of the object, one after the other, on the target direction (i.e., compute the scalar or dot product of both vectors) and remember the point delivering the maximum value.
Because of the special structure of the cube, several simplifications are possible. You can rotate the target direction vector into the local frame. Then the determination of the maximal projection can be read off the signs of its local coordinates. If the sign of the coordinate is positive the scalar product is maximized by maximizing the cube coordinate to 1. If the sign is negative, then the scalar product is maximized by minimizing the cube coordinate to 0.
Inverse rotation is the same as forming dot products with the columns of the rotation matrix (forward, right, up), so
result = zero-vector; //zero corner of the cube
if( dot( target, forward ) > 0 )
result += forward;
if( dot( target, up ) > 0 )
result += up;
if( dot( target, right ) > 0 )
result += right;

Related

OpenGL : equation of the line going through a point defined by a 4x4 matrix ? (camera for example)

I would like to know what is the set of 3 equations (in the world coordinates) of the line going through my camera (perpendicular to the camera screen). The position and rotation of my camera in the world coordinates being defined by a 4x4 matrix.
Any idea?
parametric line is simple just extract the Z axis direction vector and origin point O from the direct camera matrix (see the link below on how to do it). Then any point P on your line is defined as:
P(t) = O + t*Z
where t is your parameter. The camera view direction is usually -Z for OpenGL perspective in such case:
t = (-inf,0>
Depending on your projection you might want to use:
t = <-z_far,-z_near>
The problem is there are many combinations of conventions. So you need to know if you have row major or column major order of your matrix (so you know if the direction vectors and origins are in rows or columns). Also camera matrix in gfx is usually inverse one so you need to invert it first. For more info about this see:
Understanding 4x4 homogenous transform matrices

Align IMU orientations and then get relative rotations

I am using two IMUs of the same type (BHI160, i.e. orientation is relative to the north and on alignment with north, the IMU's local y-axis points into the north direction) on two objects, let's say pens, with the added difficulty that if I place the two objects in parallel, both IMUs' z-axes point upwards, but one IMU is rotated 180° around the z-axis relative to the other.
Now, if I understand the math here correctly, the quaternion data I receive from an IMU is the half-angle-rotation relative to the north direction, so that q * north_dir * q_inv = IMU_y_axis (with north_dir and IMU_y_axis being 3D vectors in global space, or pure quaternions for the sake of this computation).
Due to the rotation of the IMUs, I would assume that when both pens are pointing in the same direction, I should be able to compute the second pen's orientation as q_2 = q_rot_z * q_1, where q_rot_z equals a 90° rotation around the z-axis -- following the intuition that if I point both pens towards the north, I would obtain the global direction of pen 2's y-axis (i.e. pen 1's y-axis rotated around the z-axis by 180°) by computing q_rot_z * north_dir * q_rot_z_inv
Is it thus correct that if I want to know the relative rotation of the pen tips (say, the rotation I need to go from the first pen's tip to the tip of the second one), I need to compute q_r = q_2 * q_rot_z_inv * q_1_inv in order to get from tip 1 to tip 2 by computing q_r * q_1? Or does the "prior" rotation around the z-axis not matter in this case and I only need to compute q_r = q_2 * q_1_inv as usual?
Edit:
this is basically an extension of this question, but I would like to know if the same answer also applies in my case or whether the known relative IMU rotation would in my case need to be included as well
Let's go through this step by step. You have a global coordinate system G, which is aligned to the north direction. It does not really matter how it is aligned or if it is aligned at all.
Then we have to IMUs with their respective coordinate systems I1 and I2. The coordinate systems are given as the rotation from the global system to the local systems. In the following, we will use the notation R[G->I1] for that. This represents a rotation from G to I1. If you transform any vector in G with this rotation, you will get the same vector in I1 expressed in the coordinate system G. Let's denote the transformation of a vector v with transform T by T ° v. The following figure illustrates this:
In this figure, I have added a translation to the transform (which quaternions can of course not represent). This is just meant to make the point clearer. So, we have a vector v. The same vector can lie in either coordinate system G or I. And the transformed vector R[G->I] ° v represents the v of I in the coordinate system of G. Please make sure that this is actually the rotation that you get from the IMUs. It is also possible that you get the inverse transform (this would be the system transform view, whereas we use the model transform view). This changes little in the following derivations. Therefore, I will stick to this first assumption. If you need the inverse, just adjust the formulas accordingly.
As you already know, the operation R ° v can be done by turning v into a pure quaternion, calculating R * v * conjugate(R), and turning it into a vector again (or work with pure quaternions throughout the process).
Now the pens come into play. The pen has an intrinsic coordinate system, which you can define arbitrarily. From your descriptions, it seems as if you want to define it such that the pen's local y-axis points towards the tip. So, we have an additional coordinate system per pen with the according rotation R[I1->P1] and R[I2->P2]. We can concatenate the rotations to find the global orientations (* is quaternion multiplication):
R[G->P1] = R[G->I1] * R[I1->P1]
R[G->P2] = R[G->I2] * R[I2->P2]
In the way that you defined the pen's local coordinate system, we know that R[I1->P1] is the identity (the local coordinate system is aligned with the IMU) and that R[I2->P2] is a rotation of 180° about the z-axis. So, this simplifies to:
R[G->P1] = R[G->I1]
R[G->P2] = R[G->I2] * RotateZ(180°)
Note that the z-rotation is performed in the local coordinate system of the IMU (it is multiplied at the right side). I don't know why you think that it should be 90°. It is really a rotation of 180°.
If you want to find the relative rotation between the tips, you first need to define in which coordinate system the rotation should be expressed. Let's say we want to express the rotation in the coordinate system of P1. Then, what you want to find is a rotation R[P1->P2], such that
R[G->P1] * R[P1->P2] = R[G->P2]
This solves to
R[P1->P2] = conjugate(R[G->P1]) * R[G->P2]
If you plug the above definitions in, you would get:
R[P1->P2] = conjugate(R[G->I1]) * R[G->I2] * RotateZ(180°)
And that's it.
It is pretty likely that you want something slightly different. That's why I explained it in such detail, so you will be able to modify the calculations accordingly.

Normal Mapping on procedural sphere

I am a student in video games, and we are working on a raytracer in C++. We are using our teachers' library.
We create procedural objects (in our case a sphere), the Camera sends a ray for each pixel of the screen and the ray send back information on what it hit.
Some of us decided to integrate Normal Maps. So, at first, we sent ray on the object, looked at the value of the Normal map texel where we hit the sphere, converted it in a vector, normalized it and sent it back in place of the normal of the object. The result was pretty good, but of course, it didn't take the orientation of the "face" (it's procedural, so there is no face, but it gives the idea) into account anymore, so the render was flat.
We still don't really know how to "blend" the normal of the texture (in tangent space) and the normal of the object together. Here is our code:
// TGfxVec3 is part of our teachers library, and is a 3d vector like this:
// TGfxVec3( 12.7f, -13.4f, 52.0f )
// The sphere being at the origin and of radius 1, and tHit.m_tPosition being the
// exact position at the surface of the sphere where the ray hit, the normal of this
// point is the position hit by the ray.
TGfxVec3 tNormal = tHit.m_tPosition;
TGfxVec3 tTangent = Vec3CrossProduct( tNormal , m_tAxisZ );
TGfxVec3 tBiNormal = Vec3CrossProduct( tNormal , tTangent );
TGfxVec3 tTextureNorm = 2*(TGfxVec3( pNorm[0], pNorm[1], pNorm[2] )/255)-TGfxVec3( -1.0f, -1.0f, -1.0f );
// pNorm[0], pNorm[1], pNorm[2] are respectively the channels Red, Green,
// and Blue of the Normal Map texture.
// We put them in a 3D vector, divid them by 255 so their value go from 0 to 1,
// multiply them by 2, and then substract a vector, so their rang goes from -1 to +1.
tHit.m_tNorm = TGfxVec3( tTangente.x*tTextNorm.x + tCoTangente.x*tTextNorm.x +
tNorm.x*tTextNorm.x, tTangente.y*tTextNorm.y + tCoTangente.y*tTextNorm.y +
tNorm.y*tTextNorm.y, tTangente.z*tTextNorm.z + tCoTangente.z*tTextNorm.z +
tNorm.z*tTextNorm.z ).Normalize();
// Here, after some research, I came across this : http://www.txutxi.com/?p=316 ,
// that allow us to convert the normal map tangent space to the object space.
The results are still not good. My main concern are the Tangent and Binormals. The Axis taken in reference (here: m_tAxisZ, the Z Axis of the Sphere), is not right. But I don't know what to take, or even if what I am doing is really good. So I came here for help.
So, we finally did it. :D Ok, I will try to be clear. For this, two images :
(1) : http://i.imgur.com/cHwrR9A.png
(2) : http://i.imgur.com/mGPH1RW.png
(My drawing skill has no equal, I know).
So, the main problem was to find the Tangent "T" and the Bi-tangent "B". We already have the Normal "N". Our circle always being at the origin with a radius of 1, a point on its surface is equal to the Normal to that point (black and red vector on the first image). So, we have to find the tangent to that point (in green). For this, we just have to rotate the vector from PI/2 rad :
With N( x, y ) :
T = ( -N.y , N.x )
However, we are in 3D. So the point will not always be at the equator. We can easily solve this problem by ignoring the position in Y of our point and normalize the vector with only the two other component. So, on the second image, we have P (we set its Y value to 0), and we normalize the new vector to get P'.
With P( x, y, z ) :
P' = ( P.x, 0, P.z).Normalize();
Then, we go back to my first message to find the T. Finally, we get the B with a cross product between the N en the T. Finally, we calculate the normal to that point by taking the normal map into account.
With the variable "Map" containing the three channels (RGB) of the normal Map, each one clamped from -1 to 1, and T, N and B all being 3D vectors :
( Map.R*T + Map.G*B + Map.B*N ).Normalize();
And that's it, you have the normal to the point taking your normal map into account. :) Hope this will be usefull for others.
You are mostly right and completely wrong at the same time.
Tangent space normal mapping use a transformation matrix to convert the tangent space normal from the texture to another space, like object or world space, or transform the light in the tangent space to compute the lighting with everything in the same space.
Bi-normal is a common mistake and should be named bi-tangent.
It is sometime possible to compute the TBN at the fly on simple geometry, like on a height-map as it is easy to deduce the tangent and the bi-tangent on a regular grid. But on a sphere, the cross trick with a fixed axis will result to a singularity at the pole where the cross product give a zero length vector.
Last, even if we ignore the pole singularity, the TBN must be normalized before you apply the matrix to the tangent space normal. You may also miss a transpose, as a 3x3 orthonormal matrix inverse is the transpose, and what you need is the inverse of the original TBN matrix if you go from tangent to object.
Because of all this, we most often store the TBN as extra information in the geometry, computed from the texture coordinate ( the url you referenced link to that computation description ) and interpolate at runtime with the other values.
Rem : there is a rough simplification to use the geometry nornal as the TBN normal but there is no reason in the first place that they match.

Angle, which way to rotate to

For a game i'm trying to calculate the angle between where i'm looking at and the position of another object in the scene. I got the angle by using the following code:
Vec3 out_sub;
Math.Subtract(pEnt->vOrigin, pLocalEnt->vOrigin, out_sub);
float angle = Math.DotProductAcos(out_sub, vec3LookAt);
This code does give me the angle between where im looking at and an object in the scene. But there's a small problem.
When i don't directly look at the object but slightly to the left of it, then it says i have to rotate 10 degrees in order to directly look at the object. Which is perfectly correct.
But, when i look slightly to the right of the object, it also says i have to rotate 10 degrees in order to look directly to the object.
The problem here is, the i have no way to tell which way to rotate to. I only know its 10 degrees. But do i have to rotate to the left or right? That's what i need to find out.
How can i figure that out?
I feel the need to elaborate on Ignacio's answer...
In general, your question is not well-founded, since "turn left" and "turn right" only have meaning after you decide which way is "up".
The cross product of two vectors is a vector that tells you which way is "up". That is, A x B is the "up" that you have to use if you want to turn left to get from A to B. (And the magnitude of the cross product tells you how far you have to turn, more or less...)
For 3D vectors, the cross product has a z component of x1 * y2 - y1 * x2. If the vectors themselves are 2D (i.e., have zero z components), then this is the only thing you have to compute to get the cross product; the x and y components of the cross product are zero. So in 2D, if this number is positive, then "up" is the positive z direction and you have to turn left. If this number is negative, then "up" is the negative z direction and you have to turn left while upside-down; i.e., turn right.
You also need to perform the cross product on the vectors. You can then get the direction of the rotate by the direction of the resultant vector.

Calculating a LookAt matrix

I'm in the midst of writing a 3d engine and I've come across the LookAt algorithm described in the DirectX documentation:
zaxis = normal(At - Eye)
xaxis = normal(cross(Up, zaxis))
yaxis = cross(zaxis, xaxis)
xaxis.x yaxis.x zaxis.x 0
xaxis.y yaxis.y zaxis.y 0
xaxis.z yaxis.z zaxis.z 0
-dot(xaxis, eye) -dot(yaxis, eye) -dot(zaxis, eye) 1
Now I get how it works on the rotation side, but what I don't quite get is why it puts the translation component of the matrix to be those dot products. Examining it a bit it seems that it's adjusting the camera position by a small amount based on a projection of the new basis vectors onto the position of the eye/camera.
The question is why does it need to do this? What does it accomplish?
Note the example given is a left-handed, row major matrix.
So the operation is: Translate to the origin first (move by -eye), then rotate so that the vector from eye to At lines up with +z:
Basically you get the same result if you pre-multiply the rotation matrix by a translation -eye:
[ 1 0 0 0 ] [ xaxis.x yaxis.x zaxis.x 0 ]
[ 0 1 0 0 ] * [ xaxis.y yaxis.y zaxis.y 0 ]
[ 0 0 1 0 ] [ xaxis.z yaxis.z zaxis.z 0 ]
[ -eye.x -eye.y -eye.z 1 ] [ 0 0 0 1 ]
[ xaxis.x yaxis.x zaxis.x 0 ]
= [ xaxis.y yaxis.y zaxis.y 0 ]
[ xaxis.z yaxis.z zaxis.z 0 ]
[ dot(xaxis,-eye) dot(yaxis,-eye) dot(zaxis,-eye) 1 ]
Additional notes:
Note that a viewing transformation is (intentionally) inverted: you multiply every vertex by this matrix to "move the world" so that the portion you want to see ends up in the canonical view volume.
Also note that the rotation matrix (call it R) component of the LookAt matrix is an inverted change of basis matrix where the rows of R are the new basis vectors in terms of the old basis vectors (hence the variable names xaxis.x, .. xaxis is the new x axis after the change of basis occurs). Because of the inversion, however, the rows and columns are transposed.
I build a look-at matrix by creating a 3x3 rotation matrix as you have done here and then expanding it to a 4x4 with zeros and the single 1 in the bottom right corner. Then I build a 4x4 translation matrix using the negative eye point coordinates (no dot products), and multiply the two matrices together. My guess is that this multiplication yields the equivalent of the dot products in the bottom row of your example, but I would need to work it out on paper to make sure.
The 3D rotation transforms your axes. Therefore, you cannot use the eye point directly without also transforming it into this new coordinate system. That's what the matrix multiplications -- or in this case, the 3 dot-product values -- accomplish.
That translation component helps you by creating an orthonormal basis with your "eye" at the origin and everything else expressed in terms of that origin (your "eye") and the three axes.
The concept isn't so much that the matrix is adjusting the camera position. Rather, it is trying to simplify the math: when you want to render a picture of everything that you can see from your "eye" position, it's easiest to pretend that your eye is the center of the universe.
So, the short answer is that this makes the math much easier.
Answering the question in the comment: the reason you don't just subtract the "eye" position from everything has to do with the order of the operations. Think of it this way: once you are in the new frame of reference (i.e., the head position represented by xaxis, yaxis and zaxis) you now want to express distances in terms of this new (rotated) frame of reference. That is why you use the dot product of the new axes with the eye position: that represents the same distance that things need to move but it uses the new coordinate system.
Just some general information:
The lookat matrix is a matrix that positions / rotates something to point to (look at) a point in space, from another point in space.
The method takes a desired "center" of the cameras view, an "up" vector, which represents the direction "up" for the camera (up is almost always (0,1,0), but it doesn't have to be), and an "eye" vector which is the location of the camera.
This is used mainly for the camera but can also be used for other techniques like shadows, spotlights, etc.
Frankly I'm not entirely sure why the translation component is being set as it is in this method. In gluLookAt (from OpenGL), the translation component is set to 0,0,0 since the camera is viewed as being at 0,0,0 always.
Dot product simply projects a point to an axis to get the x-, y-, or z-component of the eye. You are moving the camera backwards so looking at (0, 0, 0) from (10, 0, 0) and from (100000, 0, 0) would have different effect.
The lookat matrix does these two steps:
Translate your model to the origin,
Rotate it according to the orientation set up by the up-vector and the looking
direction.
The dot product means simply that you make a translation first and then rotate. Instead of multiplying two matrices the dot product just multiplies a row with a column.
A transformation 4x4 matrix contains two-three components:
1. rotation matrix
2. translation to add.
3. scale (many engine do not use this directly in the matrix).
The combination of the them would transform a point from space A to Space B, hence this is a transformation matrix M_ab
Now, the location of the camera is in space A and so it is not the valid transformation for space B, so you need to multiply this location with the rotation transform.
The only open question remains is why the dots?
Well, if you write the 3 dots on a paper, you'd discover that 3 dots with X, Y and Z is exactly like multiplication with a rotation matrix.
An example for that forth row/column would be taking the zero point - (0,0,0) in world space. It is not the zero point in camera space, and so you need to know what is the representation in camera space, since rotation and scale leave it at zero!
cheers
It is necessary to put the eye point in your axis space, not in the world space. When you dot a vector with a coordinate unit basis vector, one of the x,y,z, it gives you the coordinates of the eye in that space. You transform location by applying the three translations in the last place, in this case the last row. Then moving the eye backwards, with a negative, is equivalent to moving all the rest of the space forwards. Just like moving up in an elevator makes you feel lke the rest of the world is dropping out from underneath you.
Using a left-handed matrix, with translation as the last row instead of the last column, is a religious difference which has absolutely nothing to do with the answer. However, it is a dogma that should be strictly avoided. It is best to chain global-to-local (forward kinematic) transforms left-to-right, in a natural reading order, when drawing tree sketches. Using left-handed matrices forces you to write these right-to-left.

Resources