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.