Skip to main content
GameDev.net gamedev.net
🔒 Locked

orienting quad perpendicular to given vector

Started by mancubit May 21, 2010 at 12:31 PM 5 replies 1.2k views
Original Post
mancubit
mancubit
i am trying to orient an quad perpendicular to a given vector, but dont know exactly how i can achieve this. All i have is a vector where the quad should face to. the problem is quite similar to spherical billboarding, but there i have access to an additional vector (up vector of camera). is it possible at all, when i only know a single vector? Can you give me some hints how i can solve this problem?
Zakwayda
Zakwayda
Quote:
Original post by mancubit
i am trying to orient an quad perpendicular to a given vector, but dont know exactly how i can achieve this. All i have is a vector where the quad should face to.

the problem is quite similar to spherical billboarding, but there i have access to an additional vector (up vector of camera).

is it possible at all, when i only know a single vector? Can you give me some hints how i can solve this problem?
A fairly standard solution:

1. The direction vector is the first basis vector.

2. Cross the direction vector with the cardinal basis vector corresponding to the element of the direction vector with the least magnitude and normalize the result to yield the second basis vector.

3. Cross the first and second basis vectors to yield the third basis vector.

If the direction vector changes dynamically in real time this can result in discontinuities in the orientation, so if that's a problem you may have to use another method. For generating a 'billboard' transform from scratch with no additional references though, the above algorithm is a good choice.
mancubit
mancubit
thanks! that helps a lot, but i am not completely sure if i am understanding your explanation in step 2 correctly.

lets assume the front vector of the quad (parallel to quad normal) is called N
and the vector where this quad should face is called L.

is it correct that you meant i should calculate cross(L,N) (or cross(N,L) if this magnitude is less..), normalize it, and take this as the second basis vector?

and regarding your comments of discontinuities in orientation - whats the reason for this?
Zakwayda
Zakwayda
Quote:
lets assume the front vector of the quad (parallel to quad normal) is called N
and the vector where this quad should face is called L.

is it correct that you meant i should calculate cross(L,N) (or cross(N,L) if this magnitude is less..), normalize it, and take this as the second basis vector?
By 'front vector of the quad', do you mean its direction vector in local space?

If so, then no, that's not exactly what I'm talking about. Here are the steps in a little more detail:

1. Take the absolute values of the elements (x, y, and z) of the desired direction vector.

2. If |x| is <= both |y| and |z|, cross the direction vector with (1, 0, 0).

3. Else if |y| is <= both |x| and |z|, cross the direction vector with (0, 1, 0).

4. Else if |z| is <= both |x| and |y|, cross the direction vector with (0, 0, 1).

5. Normalize the result (this is the second basis vector - the direction vector is the first).

6. Cross the result with the direction vector to yield the last basis vector.

7. Build the rotation matrix for the quad from the three basis vectors.

Note that the order of the terms in the cross product and the order in which the basis vectors are assigned to the matrix rows/columns depends on how your quad is oriented in local space (assuming that it lies in one of the cardinal planes).
Quote:
and regarding your comments of discontinuities in orientation - whats the reason for this?
As the direction vector changes, which element has the least magnitude may also change. This in turn causes a different cardinal axis to be selected for the cross product, which can cause the 'roll' of the quad about its direction vector to change suddenly. This will only matter though if the quad orientation is changing dynamically and if the graphic itself is not radially symmetrical (or has imperfections which might cause a change in orientation to be noticeable).
mancubit
mancubit
thanks a lot! i guess i got it now.

The rolling wont be a problem cause it doesnt change dynamically. Just out of curiosity, why do i take the vector coresponding to where the element has least magnitude in direction vector? Is there any explanation on this?
Zakwayda
Zakwayda
Quote:
Just out of curiosity, why do i take the vector coresponding to where the element has least magnitude in direction vector? Is there any explanation on this?
Basically what we're doing is crossing the direction vector with an arbitrary vector to yield a vector perpendicular to the direction vector (which we need in order to build a coordinate basis).

Now, we could just use the same vector every time - say, (1, 0, 0). However, if the direction vector is parallel or nearly parallel to this vector, the cross product will be the zero vector or at best have very small magnitude, meaning that it can't be normalized (not reliably at least).

To work around that, we could just check and see if the direction vector is 'parallel or nearly parallel' to (1, 0, 0), and if it is, use (0, 1, 0) or some other vector instead. I prefer the 'least magnitude' method though (which serves the same purpose), since it's less arbitrary and doesn't involve any fiddly tolerances or epsilons. (If you work through a few examples using the 'least magnitude' method, you should see why it guarantees that the cross product will always be 'valid'.)
mancubit
mancubit
Quote:
Original post by jyk
Now, we could just use the same vector every time - say, (1, 0, 0). However, if the direction vector is parallel or nearly parallel to this vector, the cross product will be the zero vector or at best have very small magnitude, meaning that it can't be normalized (not reliably at least).


yes, thats a problem i ran into when i first tried to implement it..

Quote:
Original post by jyk
To work around that, we could just check and see if the direction vector is 'parallel or nearly parallel' to (1, 0, 0), and if it is, use (0, 1, 0) or some other vector instead. I prefer the 'least magnitude' method though (which serves the same purpose), since it's less arbitrary and doesn't involve any fiddly tolerances or epsilons. (If you work through a few examples using the 'least magnitude' method, you should see why it guarantees that the cross product will always be 'valid'.)


checking for (nearly) parallelism was something i already thought about, but i didnt really know which vector i should choose then. Your method seems very elegant to overcome this problem.

anyway - thanks again for your explanations - they were truly helpful.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.