/** * This method generates the vectors for CylinderVectorGenerator. * * @param vector Vector to be over-written with the new vector. */ void CylinderVectorGenerator::generate( Vector3 &vector ) const { BW_GUARD; // Get a point along the axis of the cylinder. vector = origin_ + unitRand() * direction_; // Make sure that the radii are sorted: float minR = minRadius_; float maxR = maxRadius_; if (minR > maxR) std::swap(minR, maxR); // Choosing points in a disc uniformly is not as easy as you may first // think. Choosing the angle and radius randomly gives a distribution // concentrated at the center. A correct formula is given by: // http://mathworld.wolfram.com/DiskPointPicking.html // Here we adjust for the fact that we are not on the unit disc, but on // an annulus. To do this we convert the radius range from // [minRadius_, maxRadius] to [alpha, 1.0] where // alpha = minRadius_/maxRadius_, do the sqrt random distribution and // then convert back to the range [minRadius_, maxRadius]. float angle = unitRand() * 2.0f * MATH_PI; float r; if (minR == maxR) // handle case where radii are equal (or both zero) { r = minR; } else { float alpha = minR/maxR; float k1 = std::sqrtf( unitRand() * ( 1.0f - alpha ) + minR ); r = Math::lerp( k1, alpha, 1.0f, minR, maxR ); } vector += r * ( std::cosf( angle ) * basisU_ + std::sinf( angle ) * basisV_ ); }
void DenseMatrix<Complex> :: randomize( void ) // replaces entries with uniformly distributed real random numbers in the interval [-1,1] { for( int i = 0; i < m*n; i++ ) { data[i].re = 2.*unitRand() - 1.; data[i].im = 2.*unitRand() - 1.; } }
void DenseMatrix<Quaternion> :: randomize( void ) // replaces entries with uniformly distributed real random numbers in the interval [-1,1] { for( int i = 0; i < m*n; i++ ) { for( int k = 0; k < 4; k++ ) { data[i][k] = 2.*unitRand() - 1.; } } }
/** * This method generates the vectors for SphereVectorGenerator. * * @param vector Vector to be over-written with the new vector. */ void SphereVectorGenerator::generate( Vector3 &vector ) const { // Generate a random point on the unit sphere // (based upon http://mathworld.wolfram.com/SpherePointPicking.html): float theta = 2.0f * MATH_PI * unitRand(); float phi = std::acosf( 2.0f * unitRand() - 1.0f ); float sinphi = std::sinf( phi ); float x = std::cosf( theta ) * sinphi; float y = std::sinf( theta ) * sinphi; float z = std::cosf( phi ); vector = Vector3(x, y, z); // Make sure that the radii are sorted: float minR = minRadius_; float maxR = maxRadius_; if (minR > maxR) std::swap(minR, maxR); // Choose a random radius, taking into account that spherical shells // go as r^2 dr (integrate to give the volume of the shell and then // bias the choice of radius based upon that). float r; if (minR == maxR) // handle case where radii are equal (or both zero) { r = minR; } else { float alpha = minR / maxR; float k1 = std::powf( unitRand() * ( 1.0f - alpha ) + minR , 1.0f/3.0f); r = Math::lerp( k1, alpha, 1.0f, minR, maxR ); } // Scale the point to the sphere we want and move it into position. vector = r*vector + centre_; }
/** * This method executes the action for the given frame of time. The dTime * parameter is the time elapsed since the last call. * * @param particleSystem The particle system on which to operate. * @param dTime Elapsed time in seconds. */ void CollidePSA::execute( ParticleSystem &particleSystem, float dTime ) { BW_GUARD; SourcePSA* pSource = static_cast<SourcePSA*>( &*particleSystem.pAction( PSA_SOURCE_TYPE_ID ) ); if ( !pSource ) return; RompColliderPtr pGS = pSource->groundSpecifier(); if ( !pGS ) return; uint64 tend = timestamp() + stampsPerSecond() / 2000; bool soundHit = false; float maxVelocity = 0; Vector3 soundPos; uint materialKind; Particles::iterator it = particleSystem.begin(); Particles::iterator end = particleSystem.end(); WorldTriangle tri; //bust out of the loop if we take more than 0.5 msec //Sprite particles don't calculate spin while ( it != end && timestamp()<tend ) { Particle &particle = *it++; if (!particle.isAlive()) { continue; } //note - particles get moved after actions. Vector3 velocity; particle.getVelocity(velocity); Vector3 pos; Vector3 newPos; if(particleSystem.isLocal()) { Matrix world = particleSystem.worldTransform(); pos = world.applyPoint(particle.position()); Vector3 nPos; particleSystem.predictPosition( particle, dTime, nPos ); newPos = world.applyPoint(nPos); } else { pos = particle.position(); particleSystem.predictPosition( particle, dTime, newPos ); } float tValue = pGS->collide( pos, newPos, tri ); if ( tValue >= 0.f && tValue <= 1.f ) { // calc v as a dotprod of the two normalised vectors (before and after collision) Vector3 oldVel = velocity / velocity.length(); tri.bounce( velocity, elasticity_ ); particle.setVelocity( velocity ); float newSpeed = velocity.length(); Vector3 newVel(velocity / newSpeed); float severity = oldVel.dotProduct(newVel); //DEBUG_MSG("severity: %1.3f, speed=%1.3f\n", severity, newSpeed); float v = (1 - severity) * newSpeed; //now spin the particle ( mesh only ) if ( !spriteBased_ ) { //first, calculate the current rotation, and update the pitch/yaw value. Matrix currentRot; currentRot.setRotate( particle.yaw(), particle.pitch(), 0.f ); Matrix spin; float spinSpeed = particle.meshSpinSpeed(); Vector3 meshSpinAxis = particle.meshSpinAxis(); // If there is no spin direction then creating a rotation // matrix can create weird matrices - e.g. matrices with // negative scale components and a translation. We choose the // velocity as the spin direction (aribitrarily choosing, for // example up looks weird). if (meshSpinAxis == Vector3::zero()) { meshSpinAxis = velocity; meshSpinAxis.normalise(); } D3DXMatrixRotationAxis ( &spin, &meshSpinAxis, spinSpeed * (particle.age()-particle.meshSpinAge()) ); currentRot.preMultiply( spin ); particle.pitch( currentRot.pitch() ); particle.yaw( currentRot.yaw() ); //now, reset the age of the spin particle.meshSpinAge( particle.age() ); //finally, update the spin ( stored in the particle's colour ) float addedSpin = unitRand() * (maxAddedRotation_-minAddedRotation_) + minAddedRotation_; addedSpin *= min( newSpeed, 1.f ); spinSpeed = Math::clamp( 0.f, spinSpeed + addedSpin, 1.f ); particle.meshSpinSpeed(spinSpeed); particle.meshSpinAxis(meshSpinAxis); } if ( soundEnabled_ && v > 0.5f ) { soundHit = true; if (v > maxVelocity) { maxVelocity = v; soundPos = particle.position(); materialKind = tri.materialKind(); } } } } if ( soundHit ) { SmartPointer < RompSound > rs = RompSound::getProvider(); if (rs) { if (!soundTag_.empty()) { rs->playParticleSound( soundTag_.c_str(), soundPos, maxVelocity, soundSrcIdx_, materialKind ); } } } }
/** * This method generates the vectors for BoxVectorGenerator. * * @param vector Vector to be over-written with the new vector. */ void BoxVectorGenerator::generate( Vector3 &vector ) const { vector.set( corner_.x + unitRand() * ( opposite_.x - corner_.x ), corner_.y + unitRand() * ( opposite_.y - corner_.y ), corner_.z + unitRand() * ( opposite_.z - corner_.z ) ); }
/** * This function returns a uniform random number in the input range. */ inline float randInRange( float min, float max ) { return min + unitRand() * (max - min); }