Need help creating a random vector.

Started by
10 comments, last by JuNC 19 years, 5 months ago
I'm working on a particle engine and I would like to give the user some degree of randomness to the particles velocity, based on an angle to offset the vector by. PROBLEM: Say, if I have an initial vector <1,0,0> and I want to create a random vector based off that by some degree. So If I pass in an angle of 15 degree's, it would create a random vector between 15 degree's and -15 degree's. SOLUTION SO FAR: Using the vector they pass in I can determine the angle by using the dot product. Then I can add to the current angle by the degree, and subtract by the degree the user supplied. This gives me a range I can base a random number on. My problem is, I can only do this in 2d, moving to 3d I can't figure out how to get an angle. - Dave Neubelt
Advertisement
The simplest to explain method I can think of to do something like this would be:

1. generate three random numbers x, y, z each in the range [-1, 1]
2. create a vector out of those three numbers
3. if the magnitude of the vector is greater than 1, or smaller than some epsilon value, repeat from step 1.
4. if the angle between the given vector and the generated vector is greater than the given angle go back to step 1.
5. adjust the magntiude of the generated vector to be equal to the magnitude of the given vector.
Quote:Original post by SiCrane
4. if the angle between the given vector and the generated vector is greater than the given angle go back to step 1.
5. adjust the magntiude of the generated vector to be equal to the magnitude of the given vector.


I have a problem with step 4, I don't know how to determine the angle based on a 3d vector. I know how to do it with 2d, but 3d I don't know how angles work.

- Dave Neubelt
a dot b = ax*bx+ay*by+az+bz where a and b are vectors
||a|| = sqrt(ax*ax+ay*ay+az*az)
if (r dot i)/||r*i|| > cos(_r) then goto 1
r is the random vector
i is the input vector
_r is the angle
You can use the dot product, just like in 2D. X <dot> Y = |X| * |Y| cos(theta)
For a 15 degree angle that would generate a lot of random numbers and then throw them away . . . which might get expensive for a continually streaming particle generator, I don't know...

You could make it a little more efficient by finding the bounding box of possible particle velocities, and generating within that, though you would still need to discard some of the results.

The counding box is quite easy if you always point the center of the cone straight along one axis, and then rotate the resulting vector afterwards.
You could try this:

1) You have the vector you want to randomize, V. Normalize it.
2) Generate a new random vector, T, with length > epsilon, and normalize the vector.
3) If T and V are parallel (meaning the angle is too far away from 90 degrees, or abs(V dot T ) > 0.5 or something like that) go back to step 1.
4) Define a new vector, S, where S is the cross product of V and T (so is is perpendicular to both V and T); S = V x T
5) T = V x S (T should now be perpendicular to both V and S so that S, T and V are all perpendicular to one another)
6) Generate two random numbers; a between 0 and 2*pi and z between 0 and the maximum angle (in radians) between the input vector and the new randomized vector
7) The randomized V, V# = cos(z) * V + sin(z) * (cos(a)*S + sin(a)*T)

And you're done. Note that the new random vector is not evenly distributed (the new vector is more likely to be close to V). You could just transform(correct) z for that. I'm too lazy to figure out how. It'll wok none the less.

In case you wonder wnat a cross-product is, or what sin(a)*T means;
Write a vector X as (Xx, Xy, Xz)
Dot product: X dot Y = Xx*Yx + Xy*Yy + Zz*Yz (a scalar; a single value)
Cross Product: X x Y = (Xy*Yz - Xz*Yy, Xz*Yx-Xx*Yz, Xx*Yy - Xy*Yx) (a vector) - note that X x Y = - Y x X (so reversing the arguments negates the result)
Product between a scalar (a) and a vector (X): a*X = X*a = (Xx * a, Xy * a, Xz * a) (vector)
Normalizing X: X# = Normalize(X) = (Xx, Xy, Xz) * 1/sqrt(X dot X)

If you want to know what's going on; a and z parametrize a sphere. By picking a and z you specify a point on the sphere. I choose V, S and T so that they form a new base (i.e. are orthogonal) and use them as the axes of the sphere's parametrization.

Note that, since T is random you can skip picking a value for a and just make it zero so that V# = cos(z) * V + sin(z) * (cos(a)*S + sin(a)*T) = cos(z) * V + sin(z) * S. You'd still need T though as V and S should pe perpendicular.

One last note: the length of the returned vector always equals one. Multiply it by the length of V to randomize the vector V (as opposed to its direction).

I hope this helps and is clear...
What about...

1) Find the 2 angles that take the input vector back to the X axis (1, 0, 0) - assuming you can get hold of a 2D ATAN function which is quite simple, do a 2d atan with the x and z to get the angle about the Y axis, and then another with the x and y to get the angle about the z axis.

This will leave you with 2 angles that if you were to rotate (1, 0, 0) by ( in the correct order-let you work that out) you'de end up with the input vector again.

2) so then all you have to do is generate 2 random angles between -15 and 15, as in your question, and rotate (1, 0, 0) by ( Yang + randy ) and then (Zang + randz) (again I'd let you work out the order)

This works brilliantly for me, and is really simple. and if the atan uses a lookup table the speed is not a problem, in fact depending on how often this is called it wouldn't be too bad on a recent pentium etc...

sorry for putting together a shabby answer...working at the moment ;o) and in a rush...you should be able to find a Atan2D( ) funciton easily enough, or try the standard C one but you'll then have to make sure sort out the result from that as it won't give you a simple 0 to 2Pi angle, it'll give you a positive or negative angle to the nearest axis. ANYWAY I hope it's given you an idea...even if it just drives your thinking in a different direction.

GCoder
GCoder
Why not just use polar coordinates? You'll need three coordinates: length of the vector and two angles (one in the xy-plane and an other of your choice, not sure what would be easiest to implement).

I haven't read all of the replies thoroughly, so pardon me if it's been suggested.
2 + 2 = 5 for extremely large values of 2
Quote:Original post by Goldfish
Why not just use polar coordinates? You'll need three coordinates: length of the vector and two angles (one in the xy-plane and an other of your choice, not sure what would be easiest to implement).

I haven't read all of the replies thoroughly, so pardon me if it's been suggested.


I just suggested it ;)

This topic is closed to new replies.

Advertisement