void SFXSource::_updateVolume( const MatrixF& listener ) { const F32 volume = mVolume * mModulativeVolume; if ( !mIs3D ) { mDistToListener = 0.0f; mAttenuatedVolume = volume; return; } Point3F pos, lpos; mTransform.getColumn( 3, &pos ); listener.getColumn( 3, &lpos ); mDistToListener = ( pos - lpos ).len(); mAttenuatedVolume = SFXDistanceAttenuation( SFX->getDistanceModel(), mMinDistance, mMaxDistance, mDistToListener, volume, SFX->getRolloffFactor() ); }
void SFXEmitter::_renderCone( F32 radialIncrements, F32 sweepIncrements, F32 pointDistance, F32 startAngle, F32 stopAngle, F32 startVolume, F32 stopVolume, const ColorI& color ) { if( startAngle == stopAngle ) return; const F32 startAngleRadians = mDegToRad( startAngle ); const F32 stopAngleRadians = mDegToRad( stopAngle ); const F32 radialIncrementsRadians = mDegToRad( radialIncrements ); // Unit quaternions representing the start and end angle so we // can interpolate between the two without flipping. QuatF rotateZStart( EulerF( 0.f, 0.f, startAngleRadians / 2.f ) ); QuatF rotateZEnd( EulerF( 0.f, 0.f, stopAngleRadians / 2.f ) ); // Do an angular sweep on one side of our XY disc. Since we do a full 360 radial sweep // around Y for each angle, we only need to sweep over one side. const F32 increment = 1.f / ( ( ( startAngle / 2.f ) - ( stopAngle / 2.f ) ) / sweepIncrements ); for( F32 t = 0.f; t < 1.0f; t += increment ) { // Quaternion to rotate point into place on XY disc. QuatF rotateZ; rotateZ.interpolate( rotateZStart, rotateZEnd, t ); // Quaternion to rotate one position around Y axis. Used for radial sweep. QuatF rotateYOne( EulerF( 0.f, radialIncrementsRadians, 0.f ) ); // Do a radial sweep each step along the distance axis. For each step, volume is // the same for any point on the sweep circle. for( F32 y = pointDistance; y <= mDescription.mMaxDistance; y += pointDistance ) { ColorI c = color; // Compute volume at current point. First off, find the interpolated volume // in the cone. Only for the outer cone will this actually result in // interpolation. For the remaining angles, the cone volume is constant. F32 volume = mLerp( startVolume, stopVolume, t ); if( volume == 0.f ) c.alpha = 0; else { // Apply distance attenuation. F32 attenuatedVolume = SFXDistanceAttenuation( SFX->getDistanceModel(), mDescription.mMinDistance, mDescription.mMaxDistance, y, volume, SFX->getRolloffFactor() ); //RDTODO // Fade alpha according to how much volume we // have left at the current point. c.alpha = F32( c.alpha ) * ( attenuatedVolume / 1.f ); } PrimBuild::color( c ); // Create points by doing a full 360 degree radial sweep around Y. Point3F p( 0.f, y, 0.f ); rotateZ.mulP( p, &p ); for( F32 radialAngle = 0.f; radialAngle < 360.f; radialAngle += radialIncrements ) { PrimBuild::vertex3f( p.x, p.y, p.z ); rotateYOne.mulP( p, &p ); } } } }