Heya all...
I have a question regarding the following procedure, taken from a DX9 PointSprite ParticleEngine demo. The procedure's job is to return a random 3d vector, which is simply three ranged random floats, between -1.0f and +1.0f
I will supply here the original c++ souce, followed by my translation.
My question is simply this: why go to all this trouble? Why not just return three ranged random floats?


//-----------------------------------------------------------------------------
// Name: getRandomVector()
// Desc: Generates a random vector where X,Y, and Z components are between
// -1.0 and 1.0
//-----------------------------------------------------------------------------
D3DXVECTOR3 getRandomVector( void )
{
D3DXVECTOR3 vVector;

// Pick a random Z between -1.0f and 1.0f.
vVector.z = getRandomMinMax( -1.0f, 1.0f );

// Get radius of this circle
float radius = (float)sqrt(1 - vVector.z * vVector.z);

// Pick a random point on a circle.
float t = getRandomMinMax( -D3DX_PI, D3DX_PI );

// Compute matching X and Y for our Z.
vVector.x = (float)cosf(t) * radius;
vVector.y = (float)sinf(t) * radius;

return vVector;
}


==========================================
ok now here's my version of that... (I just leave them on the fp stack and return)

getRandomVector proc
local vVector:D3DXVECTOR3
local fradius:FLOAT
local ft:FLOAT

fld fp1 ;*see below

; // Pick a random Z between -1.0f and 1.0f.
invoke TFRandom,fpm1,fp1
fst vVector.z ;leave on fp stack so we can multiply with self

; // Get radius of this circle
; fradius = sqrt(1 - vVector.z * vVector.z) note the 1 in there, see above
fmul vVector.z
fsub
fsqrt
fstp fradius

; // Pick a random point on a circle.
.data
fpmpi REAL4 -3.1415926535897932384626433832795
fppi REAL4 3.1415926535897932384626433832795
.code
invoke TFRandom,fpmpi,fppi ; my Ranged Randoms func works fine

; // Compute matching X and Y for our Z.
fsincos
fmul fradius
fstp vVector.x
fmul fradius
fstp vVector.y
__LoadFloat3 vVector
ret
getRandomVector endp


=======================================

ok guys, so why not simply:
invoke TFRandom,fpm1,fp1
invoke TFRandom,fpm1,fp1
invoke TFRandom,fpm1,fp1
ret

Is there some fundamentally decent reason for normalizing a single random float (z) and then extracting x and y using sine /cosine math ?
Can we simply deduce that the rand() func used by c++ is extremely slow?
Posted on 2003-12-15 06:42:39 by Homer
Afternoon, EvilHomer2k.

If the returned vector isn't normalized, then any "movement" calculations will be stuffed up ( some particles would move faster than others in an uncontrolled way ). In any particle system, you'd want them to be random in a controlled way ;) .

Cheers,
Scronty
Posted on 2003-12-15 06:55:43 by Scronty
I understand this Scronty, and I agree with you, but let's put this in perspective by stating that this is ONLY for direction , and nothing to do with velocity (in this instance) and let's examine the usage of the code in c++

{
D3DXVECTOR3 vRandomVec = getRandomVector();
pParticle->m_vCurVel += vRandomVec * m_fVelocityVar;
}

We can see now that we are multiplying what is effectively a normal vector by a velocity factor, ie, that the RandomVector is limited to + or - 1 anyway (in x/y/z) and then multiplied by a Velocity constant, so with this in mind, can you see merit in normalizing the vector when we could simply limit it within the realm of normality in the first place?
Posted on 2003-12-15 07:01:38 by Homer
If you just return 3 random numbers for x, y and z you will get a vector with a random length. I would assume that you only want a vector with random direction, but constant length of 1. Having a random vector with random length will probably complicate the calculations further down the line.
Posted on 2003-12-15 16:04:43 by Beelzebub
The original code seems to be based on generating a point on a sphere through polar coordinates (is that what it was called? longitude/lattitude anyway).
I am not sure why exactly, but it could be that this gives a slightly different behaviour than just doing something like:

Vector3( rand(), rand(), rand() ).normalize();

So perhaps there's an idea behind this particular method (the above method is faster, after all, one sqrt(), 3 rand()s vs 1 sqrt(), 2 rand()s and a cos()/sin())...
Else well, the above should do fine, and if you only want direction, you could indeed leave out the normalization.
(The vector will be within the unit cube anyway, assuming the rand() returns a number from a uniform distribution of [-1..1]).
Posted on 2003-12-15 16:55:28 by Bruce-li
Yes, I was thinking in terms of a unit cube, not a unit sphere. I believe the original code is calculating random rays based on a unit sphere, as you pointed out, and obviously normalizing it means it always has unary length. Thanks guys, you are both absolutely correct in your observations, I'm sure, I'd already implemented this method yesterday, however it seems not to be the source of my problems :(
Having ascertained that base factor used for Velocity is correct, I had been hoping that the lack of motion of Particles was associated with bad calculation of the only other component in the calculation (apart from Time), being the direction vector.
I went on the ensure that my rand function was returning ranged floats correctly, and that the constant Velocity was correct. This only leaves Time, and that seems to be working too, because particles are certainly emitted over time, and emitted with the appropriate Delay. Sigh. What could be wrong now? :(
Posted on 2003-12-15 21:28:31 by Homer