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!
random vector on plane
Started by Remdul, May 18 2007 04:45 PM
8 replies to this topic
#2
Posted 18 May 2007 - 06:28 PM
edit: Sorry, I didn't read carefully enough; I thought that you asked for an exact angle, not a range.
#3
Posted 18 May 2007 - 07:25 PM
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.
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.
reedbeta.com - developer blog, OpenGL demos, and other projects
#4
Posted 21 May 2007 - 02:25 PM
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?
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?
#5
Posted 21 May 2007 - 07:12 PM
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.
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);
}
My music: http://myspace.com/planetarchh <-- my music
My stuff: torus.untergrund.net <-- some diy electronic stuff and more.
My stuff: torus.untergrund.net <-- some diy electronic stuff and more.
#6
Posted 20 May 2010 - 10:02 AM
That looks very complicated.
What about something like this:
http://dzindzinovic....t-on-plane.html
EDIT:
According to this solution
http://www.devmaster...read.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.
What about something like this:
http://dzindzinovic....t-on-plane.html
EDIT:
According to this solution
http://www.devmaster...read.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.
#7
Posted 20 May 2010 - 10:11 AM
That has no uniform distribution.
C++ addict
-
Currently working on: the 3D engine for Tomb Raider.
-
Currently working on: the 3D engine for Tomb Raider.
#8
Posted 05 August 2010 - 11:05 AM
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).
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
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
#9
Posted 14 August 2010 - 11:54 AM
Quote
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).
1 user(s) are reading this topic
0 members, 1 guests, 0 anonymous users












