Jan

06-13-2002, 07:37 AM

Hi guys, some days ago, i asked, if someone knows, how to produce a random vector around a "normal". I didnīt get so much replies, maybe because it is hard to explain.

However, thanks to my math-teacher, i solved the problem now, and i think, it would be interessting for all those people, who think of the same problem, because it can be very usefull in particle-systems.

So hereīs the solution (quite long):

VECTOR RandomVector (VECTOR Normal, int iMaxAlpha, float iDesiredLength)

{

/* THEORY

We want to produce a vector, which points in the direction of "Normal"

but has a deviation of maximal "iMaxAlpha" into any direction.

To produce a random vector, we take a vector parallel to the x-axis (1,0,0)

and rotate it first around the z-axis. If we did this by 45 degree, we would

for example get (0.7, 0.7, 0)

Then we rotate it around the x-axis by a random angle between 0 and 360 degree.

For example, if we did this by 90 degree, we would get (0.7, 0, 0.7).

Then we have a random vector around the x-axis. To get it to be a vector around

"Normal", we have to rotate it around two axis by the angle between "Normal" and

the used axis.

Thats all ;-)

To do this, you need a simple 3x3 matrix class and a vector class. And you

need a function, to multiply the matrix with the vector.

Because you need sin and cos very often, you may precalculate the values and

store them in an array, just as i did. (Therefore i shorten the float-angles

to int-angles.)

Hope, you may find it usefull.

*/

//calculate the length of "Normal" in the XY-plane

float lengthxy = Normal.x*Normal.x + Normal.y*Normal.y; // sqared length

lengthxy = sqrt (lengthxy); // real length

//calculate the angle between the x-axis and "Normal" in the XY-plane

float alphaxy = Normal.y / lengthxy; // sin alpha = y / hypotenuse

int ialphaxy = (int) (asin (alphaxy)*180.0f/3.141f);//convert it to degree

//calculate the length of "Normal" in the XZ-plane

float lengthxz = Normal.x*Normal.x + Normal.z*Normal.z; // sqared length

lengthxz = sqrt (lengthxz); // real length

//calculate the angle between the x-axis and "Normal" in the XZ-plane

float alphaxz = Normal.z / lengthxz; // sin alpha = z / hypotenuse

int ialphaxz = (int) (asin (alphaxz)*180.0f/3.141f);//convert it to degree

//now we take a vector, which is parallel to the x-axis and rotate it to create a

//random vector

VECTOR n (1,0,0);//x-axis

int alpha = rand () % iMaxAlpha;//we will rotate it by alpha around the z-axis

//here comes our matrix, which will rotate the vector around the z-axis

MATRIX3X3 mat (COS[alpha], -SIN[alpha], 0,

SIN[alpha], COS[alpha], 0,

0 , 0 , 1);

//we multiply mat and n (matrix multiplication), to rotate n and store it in d

VECTOR d = mat * n;

//our new vector lies in the XY-plane (because we rotated it around the z-axis),

//now we rotate it around the x-axis, so it will lie in all three planes

int beta = rand () % 360; // rotation around x-axis

//here comes our rotation matrix

mat.SetMatrix (1,0,0,

0,COS[beta],-SIN[beta],

0,SIN[beta],COS[beta]);

// multiply d and mat

d = mat * d;

//now we have a random vector around the x-axis

//but we want it to be a random vector around "Normal", so we will rotate it by

//ialphaxy and ialphaxz, to produce a vector around "Normal"

//rotate the vector around the z-axis (by ialphaxy)

mat.SetMatrix (COS[ialphaxy],-SIN[ialphaxy],0,

SIN[ialphaxy],COS[ialphaxy],0,

0,0,1);

d = mat * d;

//rotate the vector around the y-axis (by ialphaxz)

mat.SetMatrix (COS[ialphaxz],0,SIN[ialphaxz],

0,1,0,

-SIN[ialphaxz],0,COS[ialphaxz]);

d = mat * d;

//thats all, we have a random vector, now we can do some extra stuff

d.Normalize (); // unit-length

//and strecht it to the desired length

d *= iDesiredLength;

return (d);

}

Have fun with it.

Jan.

However, thanks to my math-teacher, i solved the problem now, and i think, it would be interessting for all those people, who think of the same problem, because it can be very usefull in particle-systems.

So hereīs the solution (quite long):

VECTOR RandomVector (VECTOR Normal, int iMaxAlpha, float iDesiredLength)

{

/* THEORY

We want to produce a vector, which points in the direction of "Normal"

but has a deviation of maximal "iMaxAlpha" into any direction.

To produce a random vector, we take a vector parallel to the x-axis (1,0,0)

and rotate it first around the z-axis. If we did this by 45 degree, we would

for example get (0.7, 0.7, 0)

Then we rotate it around the x-axis by a random angle between 0 and 360 degree.

For example, if we did this by 90 degree, we would get (0.7, 0, 0.7).

Then we have a random vector around the x-axis. To get it to be a vector around

"Normal", we have to rotate it around two axis by the angle between "Normal" and

the used axis.

Thats all ;-)

To do this, you need a simple 3x3 matrix class and a vector class. And you

need a function, to multiply the matrix with the vector.

Because you need sin and cos very often, you may precalculate the values and

store them in an array, just as i did. (Therefore i shorten the float-angles

to int-angles.)

Hope, you may find it usefull.

*/

//calculate the length of "Normal" in the XY-plane

float lengthxy = Normal.x*Normal.x + Normal.y*Normal.y; // sqared length

lengthxy = sqrt (lengthxy); // real length

//calculate the angle between the x-axis and "Normal" in the XY-plane

float alphaxy = Normal.y / lengthxy; // sin alpha = y / hypotenuse

int ialphaxy = (int) (asin (alphaxy)*180.0f/3.141f);//convert it to degree

//calculate the length of "Normal" in the XZ-plane

float lengthxz = Normal.x*Normal.x + Normal.z*Normal.z; // sqared length

lengthxz = sqrt (lengthxz); // real length

//calculate the angle between the x-axis and "Normal" in the XZ-plane

float alphaxz = Normal.z / lengthxz; // sin alpha = z / hypotenuse

int ialphaxz = (int) (asin (alphaxz)*180.0f/3.141f);//convert it to degree

//now we take a vector, which is parallel to the x-axis and rotate it to create a

//random vector

VECTOR n (1,0,0);//x-axis

int alpha = rand () % iMaxAlpha;//we will rotate it by alpha around the z-axis

//here comes our matrix, which will rotate the vector around the z-axis

MATRIX3X3 mat (COS[alpha], -SIN[alpha], 0,

SIN[alpha], COS[alpha], 0,

0 , 0 , 1);

//we multiply mat and n (matrix multiplication), to rotate n and store it in d

VECTOR d = mat * n;

//our new vector lies in the XY-plane (because we rotated it around the z-axis),

//now we rotate it around the x-axis, so it will lie in all three planes

int beta = rand () % 360; // rotation around x-axis

//here comes our rotation matrix

mat.SetMatrix (1,0,0,

0,COS[beta],-SIN[beta],

0,SIN[beta],COS[beta]);

// multiply d and mat

d = mat * d;

//now we have a random vector around the x-axis

//but we want it to be a random vector around "Normal", so we will rotate it by

//ialphaxy and ialphaxz, to produce a vector around "Normal"

//rotate the vector around the z-axis (by ialphaxy)

mat.SetMatrix (COS[ialphaxy],-SIN[ialphaxy],0,

SIN[ialphaxy],COS[ialphaxy],0,

0,0,1);

d = mat * d;

//rotate the vector around the y-axis (by ialphaxz)

mat.SetMatrix (COS[ialphaxz],0,SIN[ialphaxz],

0,1,0,

-SIN[ialphaxz],0,COS[ialphaxz]);

d = mat * d;

//thats all, we have a random vector, now we can do some extra stuff

d.Normalize (); // unit-length

//and strecht it to the desired length

d *= iDesiredLength;

return (d);

}

Have fun with it.

Jan.