• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
yezu666

Direction Vector to Rotation Matrix

16 posts in this topic

Hello!
I've been trying to solve a (rather simple?) problem lately. I'm surprised I haven't been able to find anything really useful on the net so far.

The thing is I have 3d direction vector. Use it to set the direction of an object in 3d space. To do that I need of course a transformation matrix.
I have a function that properly calculates the LookAt matrix. However it is correct for the view transformation. I had no success in using it to calculate the rotation of the object.

I have also tried using trigonometry using (assuming Y is up):
[code]
if(dir.getY() != 0.0f)
xAngle = (float)Math.toDegrees(Math.atan((dir.getZ()*dir.getZ()+dir.getX()*dir.getX())/dir.getY()));

if(dir.getZ() != 0.0f)
yAngle = (float)Math.toDegrees(Math.atan(dir.getX()/dir.getZ()));

TransformationMatrix.calculateRotationMatrix(xAngle, yAngle, 0.0f);
[/code]
However this does produce proper results only in certain situations.

Can anybody suggest a solution?

Thanks a lot :)
0

Share this post


Link to post
Share on other sites
[quote name='Yezu666' timestamp='1305888899' post='4813414']
...
The thing is I have 3d direction vector. Use it to set the direction of an object in 3d space. To do that I need of course a transformation matrix.
I have a function that properly calculates the LookAt matrix. However it is correct for the view transformation. I had no success in using it to calculate the rotation of the object.
...
[/quote]
The difference between the view transformation (a global-to-local transformation) and its camera transformation (a local-to-global transformation) is that the one is the inverse of the other. So, if your implementation actually computes a view transformation, then invert the resulting matrix and you're done.

Because the view transformation usually is composed of a translation and a rotation only, like so
[b]T[/b]( [b]p[/b] ) * [b]R[/b]
for column vectors, its inverse is probably computed simply as
( [b]T[/b]( [b]p[/b] ) * [b]R[/b] )[sup]-1[/sup] = [b]R[/b][sup]-1[/sup] * [b]T[/b]( [b]p[/b] )[sup]-1[/sup] = [b]R[/b][sup]t[/sup] * [b]T[/b]( -[b]p[/b] )
where the t denotes the transpose operation, so you may avoid a full-fledged matrix inversion implementation. (You have to reorder the matrices if you use row vectors, of course.)
1

Share this post


Link to post
Share on other sites
[quote name='haegarr' timestamp='1305889342' post='4813416']
( [b]T[/b]( [b]p[/b] ) * [b]R[/b] )[sup]-1[/sup] = [b]R[/b][sup]-1[/sup] * [b]T[/b]( [b]p[/b] )[sup]-1[/sup] = [b]R[/b][sup]t[/sup] * [b]T[/b]( -[b]p[/b] )
[/quote]

Thanks for the answer :)
I'm trying to experiment with the transpose of the rotational part of the LookAt matrix, without much success unfortunately.
However the weird thing is that with the transposed matrix I get some scaling effects when applied to a mesh. Should that happen?
0

Share this post


Link to post
Share on other sites
Ok. Solved. Sort of :)

I've managed to implement a function using hybrid method. It seems to work. However is not very elegant.
For anyone interested:

[code]
public static TransformationMatrix calculateDirectionalMatrix(Vector3d dir, Vector3d up)
{
float [] matrix = new float[16];

//Calculating as if a normal LookAt function:
Vector3d forward = new Vector3d(dir);

//Only with inverted direction and no height component.
forward.setX(-forward.getX());
forward.setY(0.0f);

forward.normalize();

Vector3d side = Vector3d.cross(forward , up);
side.normalize();

Vector3d plane_up = Vector3d.cross(side , forward);
plane_up.normalize();

matrix[0] = side.getX();
matrix[1] = plane_up.getX();
matrix[2] = -forward.getX();
matrix[3] = 0.0f;

matrix[4] = side.getY();
matrix[5] = plane_up.getY();
matrix[6] = -forward.getY();
matrix[7] = 0.0f;

matrix[8] = side.getZ();
matrix[9] = plane_up.getZ();
matrix[10] = -forward.getZ();
matrix[11] = 0.0f;

matrix[12] = 0.0f;
matrix[13] = 0.0f;
matrix[14] = 0.0f;
matrix[15] = 1.0f;

//Complete directional matrix for the XZ part of the direction.
TransformationMatrix ret = new TransformationMatrix(matrix);

//Now if relevant we calculate the height component of the direction using the trigonometry function.
if(dir.getY() != 0.0f)
{
float angle = (float)Math.toDegrees(Math.asin(dir.getY()));
TransformationMatrix Y = TransformationMatrix.calculateRotationMatrix(angle, 0.0f, 0.0f);

//We multiply matrices as D = XZ * Y;
ret.multiply(Y);
}

//TADA!
return ret;
}
[/code] Edited by Yezu666
0

Share this post


Link to post
Share on other sites
If you have a direction vector (I'm assuming this means your "forward" vector), then all you need to do to create the transformation matrix is create a basis using that vector.

Pseudocode:

vector3 tempUp = [0, 1, 0]
vector3 right = forward.cross(tempUp)
vector3 up = right.cross(forward)

matrix3x3 rotationMat =

[ right.x forward.x up.x ]
[ right.y forward.y up.y ]
[ right.z forward.z up.z ]

(haven't double checked but i'm almost sure this is correct)


EDIT: this all depends on whether you're using a right-handed or left-handed system (column-major or row-major matrices)
0

Share this post


Link to post
Share on other sites
[quote name='Yezu666' timestamp='1305893865' post='4813440']
I'm trying to experiment with the transpose of the rotational part of the LookAt matrix, without much success unfortunately.
However the weird thing is that with the transposed matrix I get some scaling effects when applied to a mesh. Should that happen?
[/quote]
Definitely not.

[quote name='Yezu666' timestamp='1305900613' post='4813467']
Ok. Solved. Sort of :)

I've managed to implement a function using hybrid method. It seems to work. However is not very elegant.
For anyone interested:

[code]
public static TransformationMatrix calculateDirectionalMatrix(Vector3d dir, Vector3d up)
{
float [] matrix = new float[16];

//Calculating as if a normal LookAt function:
Vector3d forward = new Vector3d(dir);

//Only with inverted direction and no height component.
forward.setX(-forward.getX());
forward.setY(0.0f); // <<< setY
forward.setY(-forward.getY()); // <<< setY

forward.normalize();

...[/code]
[/quote]
That code snippet is probably wrong: It negates the x component of the local forward vector variable, sets the y component to 0 and afterwards negates it, and does nothing with the z component. However, the method is ... abstruse. Why do you suppress the y component first and later consider it by rotation?

[quote name='gsamour' timestamp='1305901794' post='4813475']
If you have a direction vector (I'm assuming this means your "forward" vector), then all you need to do to create the transformation matrix is create a basis using that vector.

Pseudocode:

vector3 tempUp = [0, 1, 0]
vector3 right = forward.cross(tempUp)
vector3 up = right.cross(forward)

matrix3x3 rotationMat =

[ right.x forward.x up.x ]
[ right.y forward.y up.y ]
[ right.z forward.z up.z ]

(haven't double checked but i'm almost sure this is correct)


EDIT: this all depends on whether you're using a right-handed or left-handed system (column-major or row-major matrices)
[/quote]
Well, not to be offending, but ...

1. A rotation matrix must be orthonormal. I.e. the length of each column / row vector must be 1. The cross product gives you a vector with the length
| [b]a[/b] x [b]b[/b] | = | [b]a[/b] | * | [b]b[/b] | * sin( <[b]a[/b],[b]b[/b]> )
that is generally not 1 due to the sine, even if the participating vectors are of unit length. So some re-normalization is missed in your code!

E.g.

vector3 tempUp = [0, 1, 0]
forward.normalize();
vector3 right = forward.cross(tempUp)
right.normalize();
vector3 up = right.cross(forward)
up.normalize(); // (should not be necessary)

2. You've forgotten to mention that the matrix is for column vector use. "column-major" and "row-major" are terms that describe how the elements of a 2D matrix construct are arranged in linear (i.e. 1D) memory. Your code does no deal with this aspect in any way. Instead you meant "column vector use" vs. "row vector use".

3. How does "this all depends on whether you're using a right-handed or left-handed system" ?

4. Right-/left-handedness and matrix layout has absolutely nothing in common.
1

Share this post


Link to post
Share on other sites
Not offended in any way :)


1. Oops... I forgot to normalize the vectors... Thanks!

2. The handedness affects the order in which you do the cross product

3. By row-major and column-major I meant the same thing as row-vectors and column-vectors (I've always heard of the term row-major and column-major referred to matrices)
0

Share this post


Link to post
Share on other sites
[quote name='gsamour' timestamp='1305903872' post='4813488']
Not offended in any way :)
[/quote]
Thanks :)

[quote name='gsamour' timestamp='1305903872' post='4813488']
2. The handedness affects the order in which you do the cross product
[/quote]
Assuming you compute the cross-product of [b]e[/b][sub]x[/sub] and [b]e[/b][sub]y[/sub], i.e. the unit vectors in x and y direction.
[b]e[/b][sub]x[/sub] x [b]e[/b][sub]y[/sub] = [ 1 0 0 ][sup]t[/sup] x [ 0 1 0 ][sup]t[/sup] = [ 0 0 1 ][sup]t[/sup]
what give you the unit vector in z direction. No dependency of a handedness, because [ 0 0 1 ][sup]t[/sup] is correct in both systems!

If you would instead compute it in reverse order
[b]e[/b][sub]y[/sub] x [b]e[/b][sub]x[/sub] = [ 0 1 0 ][sup]t[/sup] x [ 1 0 0 ][sup]t[/sup] = [ 0 0 -1 ][sup]t[/sup]
you would get a wrong result!

[quote name='gsamour' timestamp='1305903872' post='4813488']
3. By row-major and column-major I meant the same thing as row-vectors and column-vectors (I've always heard of the term row-major and column-major referred to matrices)
[/quote]
Using column or else row vectors is important for the matrix product. The correspondence between 2 matrices is the transpose:
( [b]M[/b] * [b]v[/b] )[sup]t[/sup] = [b]v[/b][sup]t[/sup] * [b]M[/b][sup]t[/sup]
where the left side uses a column vector [b]v[/b] and the right side its row vector equivalent. Notice that the order is reverse, and notice that the vector / matrix is transposed compared to the original one.

On the other hand, row major layout means that a matrix
[ a b ]
[ c d ]
is stored number sequence
{ a b c d }
in memory, while the same matrix stored using column major layout looks like
{ a c b d }
This issue has nothing to do with matrix math but simply with the need for computer programs and/or file formats to serialize the 2D data of a matrix.
0

Share this post


Link to post
Share on other sites
[quote name='haegarr' timestamp='1305903601' post='4813485']
That code snippet is probably wrong: It negates the x component of the local forward vector variable, sets the y component to 0 and afterwards negates it, and does nothing with the z component. However, the method is ... abstruse. Why do you suppress the y component first and later consider it by rotation?
[/quote]
Well Indeed I made a typo. The part:
[code]forward.setY(-forward.getY());[/code]is not needed. (Fixed it BTW :P)

I remove the Y component, because the upper method didn't provide proper rotation for it. So effectively I've split the operation into two rotations and then I multiply the resulting matrices. The method is not very straight forward but provides correct results. I'd gladly change it I if could find something simpler that calculates correctly.

Although I haven't noticed so far, I think there are errors in my LookAt function. AFAIK the resulting matrix should be orthonormal and the scaling effect after transposition suggests it is not. I must look into it. However I would be very happy if You could help me. :) Here is the code:

[code]
public static TransformationMatrix calculateLookAtMatrix(Vector3d eye, Vector3d center, Vector3d up)
{
float [] matrix = new float[16];

Vector3d forward = Vector3d.sub(center , eye);
forward.normalize();

Vector3d side = Vector3d.cross(forward , up);
side.normalize();

Vector3d plane_up = Vector3d.cross(side , forward);
plane_up.normalize();

matrix[0] = side.getX();
matrix[1] = plane_up.getX();
matrix[2] = -forward.getX();
matrix[3] = 0.0f;

matrix[4] = side.getY();
matrix[5] = plane_up.getY();
matrix[6] = -forward.getY();
matrix[7] = 0.0f;

matrix[8] = side.getZ();
matrix[9] = plane_up.getZ();
matrix[10] = -forward.getZ();
matrix[11] = 0.0f;

matrix[12] = 0.0f;
matrix[13] = 0.0f;
matrix[14] = 0.0f;
matrix[15] = 1.0f;

Vector3d neweye = new Vector3d(eye);
neweye.reverse();

TransformationMatrix ret = new TransformationMatrix(matrix);

ret.multiply(TransformationMatrix.calculateTranslationMatrix(neweye));

return ret;
}
[/code]
thanks a lot for the help :)
0

Share this post


Link to post
Share on other sites
[quote name='gsamour' timestamp='1305901794' post='4813475']
vector3 tempUp = [0, 1, 0]
vector3 right = forward.cross(tempUp)
vector3 up = right.cross(forward)

matrix3x3 rotationMat =

[ right.x forward.x up.x ]
[ right.y forward.y up.y ]
[ right.z forward.z up.z ]
[/quote]
Thanks for the suggestion. I've tried this method but I don't seem to get a correct transformation from it. I'll keep trying, though :)
0

Share this post


Link to post
Share on other sites
I definitely need to brush up on this stuff to have it clear in my head. Thanks haegarr, hopefully we've helped the OP
0

Share this post


Link to post
Share on other sites
@Yezu666,

make sure you follow what haegarr said about normalizing the vectors.
0

Share this post


Link to post
Share on other sites
[quote name='Yezu666' timestamp='1305905991' post='4813501']
Although I haven't noticed so far, I think there are errors in my LookAt function. AFAIK the resulting matrix should be orthonormal and the scaling effect after transposition suggests it is not. I must look into it. However I would be very happy if You could help me. :) Here is the code:
[/quote]
Please bear in mind that some aspects of the implementation are not clear yet. So I must guess some things...

[code]public static TransformationMatrix calculateLookAtMatrix(Vector3d eye, Vector3d center, Vector3d up)
{
float [] matrix = new float[16];

Vector3d forward = Vector3d.sub(center , eye);
forward.normalize();
[/code]
I assume that Vector3d.sub(a, b) computes a-b (in this order).

[code] Vector3d side = Vector3d.cross(forward , up);
side.normalize();

Vector3d plane_up = Vector3d.cross(side , forward); plane_up.normalize();
[/code]
Normalizing "plane_up" is not strictly necessary, because both arguments "side" and "forward" have unit length and "side" is guaranteed to be orthogonal to "forward".

[code] matrix[0] = side.getX();
matrix[1] = plane_up.getX();
matrix[2] = -forward.getX();
matrix[3] = 0.0f;

matrix[4] = side.getY();
matrix[5] = plane_up.getY();
matrix[6] = -forward.getY();
matrix[7] = 0.0f;

matrix[8] = side.getZ();
matrix[9] = plane_up.getZ();
matrix[10] = -forward.getZ();
matrix[11] = 0.0f;

matrix[12] = 0.0f;
matrix[13] = 0.0f;
matrix[14] = 0.0f;
matrix[15] = 1.0f;
[/code]
Now things become a bit complicated.

1. You're negating (solely) the forward direction, so your camera is defined to look along its local negative z direction, right?

2. Because you're about to compute the transposed matrix, from the indexing I conclude that you're using the column major layout, right? I mean that the matrix indices are arranged like so:
[ 0 4 8 12 ]
[ 1 5 9 13 ]
[ 2 6 10 14]
[ 3 7 11 15]

If that is right it would further mean that you are using column vectors.

[code]
Vector3d neweye = new Vector3d(eye);
neweye.reverse();

TransformationMatrix ret = new TransformationMatrix(matrix);
ret.multiply(TransformationMatrix.calculateTranslationMatrix(neweye));
[/code]
The ret.multiply computes probably [b]R[/b][sup]t[/sup] * [b]T[/b]( -eye ) here. This order would be correct if and only if you're using column vectors. Do you do so? Unfortunately, nothing in the shown code gives a clear criterion whether you do so.

[code]
return ret;
}
[/code]
Nothing to say here ;)
0

Share this post


Link to post
Share on other sites
It looks like it's already been addressed, but:

[quote name='gsamour' timestamp='1305903872' post='4813488']
2. The handedness affects the order in which you do the cross product[/quote]
Actually, (spatial) handedness has no effect on how the cross product is computed or how the arguments should be ordered.

[quote]3. By row-major and column-major I meant the same thing as row-vectors and column-vectors (I've always heard of the term row-major and column-major referred to matrices)[/quote]
Although these terms are commonly conflated, they refer to two completely different and unrelated things (as haegarr explained above).
0

Share this post


Link to post
Share on other sites
Thanks jyk and haegarr for clearing this up :)

EDIT: can you go into a little more detail please?

From Wolfram Mathworld... [url="http://mathworld.wolfram.com/CrossProduct.html"]http://mathworld.wolfram.com/CrossProduct.html[/url]

It says that the way the cross-product is computed there assumes the right-hand rule. Now I'm confused.
0

Share this post


Link to post
Share on other sites
[quote name='gsamour' timestamp='1305926383' post='4813633']
EDIT: can you go into a little more detail please?

From Wolfram Mathworld... [url="http://mathworld.wolfram.com/CrossProduct.html"]http://mathworld.wol...ossProduct.html[/url]

It says that the way the cross-product is computed there assumes the right-hand rule. Now I'm confused.
[/quote]
I'm not sure why that specification is made (perhaps it's because the example in the diagram is with respect to a right-handed system).

In any case, the cross product is computed in the same way regardless of handedness; the 'right-hand rule' and 'left-hand rule' are just mnemonics to remember in which direction the cross product will point in a coordinate system with a given handedness.
0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0