Sign in to follow this  
Viik

Matrix from direction and position

Recommended Posts

Viik    252
I need to construct motion matrix of an object knowing only direction where it looks at and position. Right now I'm using this routine:

float3 forward = normalize(light_dir);
float3 up = float3(0,1,0);
float3 v_right = normalize(cross(up, forward));
float dotRP = dot(v_right, light_pos);
float dotUP = dot(up, light_pos);
float dotFP = dot(forward, light_pos);

float4x4 parab_matrix = {
v_right.x, up.x, forward.x, 0.0f,
v_right.y, up.y, forward.y, 0.0f,
v_right.z, up.z, forward.z, 0.0f,
-dotRP, -dotUP, -dotFP, 1.0f};


It works pretty fine except cases when objects direction and "up" vectors are almost the same, so it gives a gimbal lock. Is there any other way how this can be achived?
I was thinking to use quaternions for this but it looks like it will hit performance too much.

Share this post


Link to post
Share on other sites
RobTheBloke    2553
Quote:
Original post by Viik
It works pretty fine except cases when objects direction and "up" vectors are almost the same, so it gives a gimbal lock. Is there any other way how this can be achived?


Change your up vector when abs(dot(up, forward)) is close to 1.

Share this post


Link to post
Share on other sites
jyk    2094
Quote:
It works pretty fine except cases when objects direction and "up" vectors are almost the same, so it gives a gimbal lock.
It seems to be pretty common to refer to any rotation-related artifact as 'gimbal lock', but no, that's not gimbal lock.
Quote:
I was thinking to use quaternions for this but it looks like it will hit performance too much.
You don't need to use quaternions for this (in fact, this particular problem is more easily solved using matrices/vectors, IMO).

You can just handle the case you described separately, as RobTheBloke suggested. My own preferred solution though is to use as the reference vector the cardinal basis vector corresponding to the element of the input vector that has the least magnitude; this ensures a valid result, and also ensures maximum stability.

Share this post


Link to post
Share on other sites
The calculation is missing a step. You should add this line after the line computing v_right. (Otherwise up and forward may not be perpendicular to each other.)

>>> up = cross(forward, v_right);

Also, your v_right is actually v_left, but perhaps you are using a left-handed coordinate system.

This problem actually has no solution which is continuous in the inputs. In other words, no matter what you do, there will be some direction near which the solution changes suddenly.

The suggestions given in this thread will work, in the sense that you won't get division by zero during the 'normalize', but they won't be stable.

If you know a "previous" value --- for instance if you are tracking this object over time --- then you can achieve stability. Use the previous value of up as the seed for the next value of up.

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