edit: Sorry, I didn’t read carefully enough; I thought that you asked for an exact angle, not a range.

Please log in or register to post a reply.

Try starting with the equations for a random point on a sphere; you can easily modify the equations to generate a random vector within a cone by scaling the polar angle (denoted phi on that page) to the range you want. The cone will be centered the north pole of the sphere (usually (0, 0, 1)), but as roel said you can then rotate it to position the cone along whatever vector you want.

However, this gives you a uniform distribution over the cone and you might rather want the distribution to be biased more towards the center and fade out around the edges. You can easily acheive a cosine-weighted distribution by removing the arc-cosine in the sphere-point-picking equations. You could also apply a Gaussian function or something to the polar angle for more control over the spread.

I guess it all comes down to converting the vector (plane) to quaternion/matrix, then use that to rotate an up-vector by a random value (which lies within a range).

What is the easiest way to convert a vector into a quaternion? I can compute a 3x3 rotation matrix from the vector with a few cross products (lookat), then convert the matrix to quaternion. Is there a shortcut?

Hi Remdul.

I just wrote some code that somewhat works the way you thought up.

I built an orthogonal-basis (coordinate system) from the normal, calculated a random point on a circle in that coordinate system and just applied some basic trigonometry to build the new vector.

If you precompute the orthogonal basis and the sin/cos of the spread angle it boils down to some muls, adds and a square-root.

Works with spread-angles up to, but not reaching 180°. Afterwards it will break down.

```
typedef struct
//////////////
{
float x,y,z;
} Vector3;
void random_point_unitcircle (float *a_x, float *a_y)
/////////////////////////////////////////////////////
{
const float InvRandMax = 2.0f / (float)RAND_MAX;
float r,x,y;
do {
// get two randoms between -1 and 1:
x = ((float)rand() * InvRandMax) - 1.0f;
y = ((float)rand() * InvRandMax) - 1.0f;
// get radius (squared)
r = x*x+y*y;
// and repeat while point is not inside the unitcircle:
} while (r > 1.0f);
*a_x = x;
*a_y = y;
}
void normalize (Vector3 * vec)
///////////////////////////////
// normalized a vector
{
float len = (float)sqrt (vec->x * vec->x + vec->y * vec->y + vec->z * vec->z);
vec->x /= len;
vec->y /= len;
vec->z /= len;
}
void unitcross (Vector3 * out, Vector3 * a, Vector3 * b)
///////////////////////////////////////////////////////
// Builds cross product of A and B, returns normalized result.
{
out->x = a->y * b->z - a->z * b->y;
out->y = a->z * b->x - a->x * b->z;
out->z = a->x * b->y - a->y * b->x;
normalize (out);
}
void build_orthogonal_basis (Vector3 * Normal, Vector3 * Tangent, Vector3 * Binormal)
/////////////////////////////////////////////////////////////////////////////////////
// Builds a crude orthogonal-basis.
// Assumes, that Normal is a unit-vector (e.g. length(Normal) == 1)
{
// Pick any Unit-Vector that's not orthogonal to Normal:
if (fabs(Normal->x) > fabs(Normal->y))
{
Tangent->x = 0;
Tangent->y = 1;
Tangent->z = 0;
} else {
Tangent->x = 1;
Tangent->y = 0;
Tangent->z = 0;
}
// build a binormal from tangent and normal:
unitcross (Binormal, Tangent, Normal);
// And correct the tangent from the binormal and the normal.
unitcross (Tangent, Normal, Binormal);
}
void random_vector (Vector3 * result, Vector3 * normal, float theta)
{
Vector3 t,b;
float x,z;
float sin_theta, cos_theta;
// we need half the spread-angle only:
sin_theta = sin(theta * 0.5f);
cos_theta = cos(theta * 0.5f);
// build/guess a orthogonal-basis from the normal:
build_orthogonal_basis (normal, &t, &b);
// get random point in 2D:
random_point_unitcircle (&x, &z);
// scale the random point to apply the spread:
x *= sin_theta;
z *= sin_theta;
// transform point into orthogonal basis:
result->x = t.x * x + t.z * z;
result->y = normal->x * x + normal->z * z;
result->z = b.x * x + b.z * z;
// move the now rotated point along the normal.
// apply scaling to apply the spread:
result->x += normal->x * cos_theta;
result->y += normal->y * cos_theta;
result->z += normal->z * cos_theta;
// normalize it:
normalize (result);
}
```

That looks very complicated.

What about something like this:

http://dzindzinovic.blogspot.com/2010/05/xna-random-point-on-plane.html

EDIT:

According to this solution

http://www.devmaster.net/forums/showthread.php?t=9776

the radius for a random point in a circle should be a square root of a
random number.

Since the cross product in that function is normalized (has unit
length), the distribution should be uniform.

You are thinking too complicated if you just want to spread a particle’s emitted in some power.

I would do something like this (note, code is written directly in here and not checked for errors.. the idea matters only).

```
void emitparticle( flost pos[3], float posrandom, float dir[3], float dirrandom ) {
float rx = (float)(rand()&255)-127);
float ry = (float)(rand()&255)-127);
float rz = (float)(rand()&255)-127);
// normalize
float len = sqrtf( rx*rx+ry*ry+rz*rz);
rx /= len; ry/=len; rz/=len;
emitted_particle.posx = pos[0]+rx*posrandom;
emitted_particle.posy = pos[1]+ry*posrandom;
emitted_particle.posz = pos[2]+rz*posrandom;
emitted_particle.dirx = dir[0] + rx *dirrandom;
emitted_particle.diry = dir[1] + ry *dirrandom;
emitted_particle.dirz = dir[2] + rz *dirrandom;
}
```

So, the point is that you provide a direction vector for the particle (dir[3]) and then change it with a random factor. There are no specific angle of spread easily calculated, but you dont need such in most cases like these.

45degree distribution would be

dirrandom = length_of_dir3

Tuomo

There are no specific angle of spread easily calculated, but you dont need such in most cases like these.

A dot product along the principal axis will do - simply reject/ignore all the vectors that are outside the preferred angle. For orientation of the whole emitter one can use normal matrices for coordinate transformations (transforming from emitter to world space).

- Upcoming Multiplatform Game Program...
- Our first game - looking for feedbacks
- Network Emulation Tool
- Trouble with accessing GLSL array
- Fiction
- Game Programming Patterns: Bytecode
- Interactive WebGL Water Demo
- Skeletal Animation Tutorial with GP...
- Unreal Engine 4
- Microsoft xbox one selling poorly

Hi,

How can one generate a random vector that diverges from an arbitrary vector to a given range (angle)?

In case I’m not clear, I want something like a particle emitter that has a certain ‘spread’ angle.

So, given are:

-vector x,y,z (or plane normal)

-spread angle

I’ve read something about turning the vector into a quaternion (how?), then rotating a vector by a (random?) number of degrees, and something similar with a (rotation?) matrix, but I don’t have a clue how/if this works.

Thanks!