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?

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?

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

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

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?

{

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?

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.

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]).

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]).

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? :(

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? :(