Random Perpendicular 3D Vector

Started by
17 comments, last by Kest 17 years, 5 months ago
Is there a way to compute a random perp vector to an original 3D vector without crossing? I want to apply random outward velocity to particles in a situation where I only have a forward vector. Any advice? My instinct tells me to obtain a right and up vector and multiply them with a random scaler (-1 to +1). Vector forward = original_vector; Vector whacko( -forward.z, -forward.y, forward.x ); Vector right = Cross( forward, whacko ); Vector up = Cross( forward, right ); Velocity += right * random_x_scaler; Velocity += up * random_y_scaler; But that's a bit of math to pound onto hundreds of individual particles. And since the result will be random anyway, I was wondering if there wouldn't be a quick and dirty way to reach the same conclusion?
Advertisement
Starting with your forward vector, it's possible to generate a random vector and then orthogonalize it:
Vector random(rand(), rand(), rand());Velocity = random - forward * dot(random, forward) / dot(forward, forward);

Doesn't really take into account the (non-)uniformity of the random distribution or anything like that, I just wanted to demonstrate the orthogonalization code. It's possible that you generate a random vector that's parallel to the forward vector, in which case the velocity will be zero, but the odds are quite slim and in the worst case you have a particle with no sideways velocity. Also note that forward / dot(forward, forward) can be computed once and reused for each particle (until the forward direction changes of course).
So in a sense, we're creating a random vector and smashing it onto the forward vector's zero-origin plane? A perfect solution.

Is your result velocity vector normalized?

Vector random( rand(), rand(), rand() );
Velocity = random + ( forward * -dot( forward, random ) );

I'm not sure what the additional "/ dot(forward, forward);" is doing. Wouldn't dot(forward,forward) always be 1?

Thanks much for your excellent advice.
Quote:Original post by Kest
So in a sense, we're creating a random vector and smashing it onto the forward vector's zero-origin plane?
Yup.
Quote:Is your result velocity vector normalized?
Nope.
Quote:I'm not sure what the additional "/ dot(forward, forward);" is doing. Wouldn't dot(forward,forward) always be 1?
If your forward vector is known to be unit length, you can drop the dot(forward,forward).
I forgot to mention the scale of forward, sorry.

And thanks for the confirmation :)
Why the cross-product aversion? Any other method is simply using simplified Gram-Schmidt orthogonalisation in a different (and probably less efficient) way. Any orthogonal vector is the cross-product of the forward vector and something else, and chances are that you spend more effort calculating it than you would crossing against a quasi-random vector.

If you're worried that cross-products are slow, then they really aren't. Certainly not when compared to anything involving normalisation or rotation (which contain sqrt, sin, cos as opposed to addition and multiplication).
If you're worried that cross-products are complicated to implement without an API, then, again, think twice.

Regards
Admiral
Ring3 Circus - Diary of a programmer, journal of a hacker.
Quote:Original post by TheAdmiral
Why the cross-product aversion?

Its an ugly hack to reach a result that was even simpler than the hack itself.

Quote:Any other method is simply using simplified Gram-Schmidt orthogonalisation in a different (and probably less efficient) way.

I'm open to suggestions.

Quote:..chances are that you spend more effort calculating it than you would crossing against a quasi-random vector.

It's all right here, so you tell me.

Quote:If you're worried that cross-products are slow, then they really aren't. Certainly not when compared to anything involving normalisation or rotation (which contain sqrt, sin, cos as opposed to addition and multiplication).

I don't think cross products are slow (a*b-b*a three times). But I don't think normalization is particularly slow either. By "a bit of math", I meant a large ugly mess. I doubt either solution is much better performance-wise than the other. But the smash-to-plane solution is much more elegant. And I like smashing things.

Quote:If you're worried that cross-products are complicated to implement without an API, then, again, think twice.

I don't understand. How does this effect the situation?
Quote:Its an ugly hack to reach a result that was even simpler than the hack itself.
It's not an ugly hack. Many would argue that the sole purpose of the cross-product's existence is to produce perpendicular vectors. If you're prepared to start off with a vector (rand(), rand(), rand()) and you don't think that's ugly, then calling rand() once and calculating a cross-product is the picture of elegance.

Quote:
Quote:Any other method is simply using simplified Gram-Schmidt orthogonalisation in a different (and probably less efficient) way.
I'm open to suggestions.
My mention of GS orthogonalisation was merely an indication that whatever route you take, you're performing the same operation, only you're likely taking the long way 'round.

Quote:
Quote:...chances are that you spend more effort calculating it than you would crossing against a quasi-random vector.
It's all right here, so you tell me.
Well I'm sure it's all right, but is it perfect? [wink].
I doubt any reasonably brief method will asymptotically outperform any other, but I think two lines of fast code are better than two of not-quite-so-fast code. You're more than welcome to use whatever method you like, considering that they're all roughly equivalent. But you appear to be under the false impression that the cross-product method is inferior to the displace-project method.

Quote:
Quote:If you're worried that cross-products are complicated to implement without an API, then, again, think twice.
I don't understand. How does this effect the situation?
It doesn't. I was just guessing as to why you didn't want to use cross-products.

Anyway, this disagreement is completely moot. You've found a solution you're happy with, so let's all go to the pub [grin].

Regards
Admiral
Ring3 Circus - Diary of a programmer, journal of a hacker.
depending on how many such particles you want, it might be faster for you to generate a basis for the orthogonal plane first. then you only need to call rand twice and do very little arithmetic.
Quote:
Quote:Its an ugly hack to reach a result that was even simpler than the hack itself.
It's not an ugly hack. Many would argue that the sole purpose of the cross-product's existence is to produce perpendicular vectors. If you're prepared to start off with a vector (rand(), rand(), rand()) and you don't think that's ugly, then calling rand() once and calculating a cross-product is the picture of elegance.

A cross product between two vectors to obtain a perp vector is straight to the point. But I only have one. So I need to generate my whacko vector and cross twice to create two vectors to be randomly scaled. That seems to me like a mess. If there's another way to get the result, I'm in need of it to make a proper choice between the two routines.

I'm not even sure if my original operation will work. Does it? Even then, is the result circular? If I use -1 to +1 scaling of up and right, would the random result be round or square? Should I be scaling by 0.707? Or possibly combine the two after scaling and renormalize?

Quote:
Quote:
Quote:Any other method is simply using simplified Gram-Schmidt orthogonalisation in a different (and probably less efficient) way.
I'm open to suggestions.
My mention of GS orthogonalisation was merely an indication that whatever route you take, you're performing the same operation, only you're likely taking the long way 'round.

My mention of being open for suggestions was asking for the short way [smile]

Quote:I doubt any reasonably brief method will asymptotically outperform any other, but I think two lines of fast code are better than two of not-quite-so-fast code. You're more than welcome to use whatever method you like, considering that they're all roughly equivalent. But you appear to be under the false impression that the cross-product method is inferior to the displace-project method.

Just that my own version was inferior (like I said, I'm not even sure it will work). And that I'm unable to write anything better at the moment.

Quote:Anyway, this disagreement is completely moot. You've found a solution you're happy with, so let's all go to the pub [grin].

If I can be further educated, it's not so moot.

This topic is closed to new replies.

Advertisement