# Random Vector within a cone [duplicate]

I'm looking to create a random vector within a cone given the radius (base).

It feels like I've been traversing through many pages on the internet and still I'm no further forward to getting an answer.

I was thinking I could get a point within the base of the cone and have it point towards the apex (then just use the inverse of that for my animation) but this seems like an incredibly long winded approach.

-

## marked as duplicate by bummzack, Anko, msell, Byte56♦, Laurent CouvidouMay 17 '13 at 22:44

What precisely do you mean by 'random vector within a cone'? Are you looking for a unit vector from the base whose direction lies somewhere in the cone of directions, a vector (of whatever the length might be) from the base of the cone to a random point on the surface, a vector between two points in the cone, a vector from the base to a random point within the volume of the cone, or something else entirely? – Steven Stadnicki Apr 4 '12 at 18:17
Also, assuming the first (a unit vector somewhere in the cone of directions), how wide is your cone going to be, and how close to a uniform distribution do you need to be? There are approximations if you're only looking at something like a 5-degree cone that will be pretty good, but they get much worse if you're considering e.g. a full hemisphere... – Steven Stadnicki Apr 4 '12 at 18:33
"a vector (of whatever length) from the apex to a random point on the base of the cone to" seems best fitting to what I need; sorry, I should have elaborated more in the original question. – Paul Apr 4 '12 at 18:49
Could you please give more context in the question, maybe explain how the vector is going to be used? The proposed answer is correct in its way, but it does not pick uniform directions within the cone. – sam hocevar Apr 5 '12 at 19:57
Basically, the use for the vector will be in a particle emitter, I need it to fire out from the 'emitters' position at random directions within a cone. – Paul Apr 5 '12 at 23:31

Given the discussion in the comments, this comes down to finding a random point on a circle. For instance, if we find a point (x,y) at random within a circle of radius 1, then the vector (.05*x, .05*y, 1) will be a roughly-random vector within the cone of angle arctan(.05) (or approximately 2.9 degrees) about the z axis.

There are several different methods of finding a random point on a sphere, but the most straightforward by far is what's known as the rejection method : find a point at random within the square of radius 1 and then reject it (that is, find another random point) if that point is outside the unit circle. Assuming that rand() returns a random number between 0 and 1.0, then the pseudocode for doing this would look something like:

``````do {
x = 2.0*rand()-1.0;
y = 2.0*rand()-1.0;
} while ( x*x+y*y > 1.0 );
// (x,y) is now randomly distributed within the unit circle
``````

Since the area of the square is 4 and the area of the circle is π, the probability that the point will be inside the circle is π/4 and the average number of times you'll execute the do loop is 4/π, or approximately 1.27 times for each random point within the circle; there's a less than 1% chance that you'll need more than 3 iterations of the loop to find a point within the circle. This uniform point in the circle can then be translated into a nearly-uniform vector in a spread about the z-axis by means of the method I listed above; in particular, if the maximum angle from the z axis is theta (so the cone's width is 2*theta), then pseudocode for using the random point would look something like:

``````r = tan(theta);
Vector v(r*x, r*y, 1);
v.Normalize();
``````

Note that this won't give a precisely uniform angular spread, because the surface of a sphere isn't flat - points near the center of the cone will be generated slightly less often than they 'should' be, compared to points at the fringes. But for small angles theta this gives a pretty good approximation, and it should certainly be good enough for most random-animation purposes.

-
See also mathworld.wolfram.com/DiskPointPicking.html for discussions of "point on disk" selection. – Tim Holt Apr 4 '12 at 18:51
@TimHolt : Agreed, though I'm surprised that page doesn't discuss other means of picking points - there's a small host of different techniques, of course. – Steven Stadnicki Apr 4 '12 at 18:57

Coincidentally I had to do the very same thing not that long ago :)

Here's the solution I came up with, assuming you have the cone angle, and the unit vector describing which direction it's facing.

• First, generate a random unit vector.
• Project this vector onto the 'plane' with the cone's direction vector as a normal. I put plane in quotes because to truly define a plane, you also need a point. However, this works for the purposes of this method. The formula, by the way, is:

`projectedVector = randomVector - (coneDirection*(dot(coneDirection,randomVector));`

• This vector is now perpedicular to the cone's direction, and can be taken as an axis around which to rotate the cone.

• Generate a random angle, `theta`, between 0 and the cone's maximum angle.
• Set up a rotation matrix for `theta` degrees around the axis `projectedVector`.
• Rotate the cone's direction using that matrix.

I would like to note that I don't know if this yields uniform distribution randomness, but it worked well for me.

-
Note that this amounts to essentially choosing a random angle phi in (0, 2pi) and a random angle theta in (0, theta_max) - this clusters vectors too closely around the center of the cone, for reasons outlined in the link on Tim Holt's comment to my answer. (The angle theta plays the role of the radius 'r' there, and phi plays the role of theta) – Steven Stadnicki Apr 4 '12 at 19:58
@StevenStadnicki Thanks. I figured it probably wasn't uniform. – ktodisco Apr 4 '12 at 21:21

I solved this by calculating the vector in spherical coordinates, converting back into cartesian and then hitting it with a rotation matrix to get it aligned with the direction of the emitter. Essentially this:

``````theta = random(0, emission_angle);
phi = random(0, 2*pi);

vec3 temp(cos(phi)*sin(theta), sin(phi)*sin(theta), cos(theta));