You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
124 lines
3.1 KiB
124 lines
3.1 KiB
//========= Copyright Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose: spherical math routines
|
|
//
|
|
//=====================================================================================//
|
|
|
|
#include <math.h>
|
|
#include <float.h> // Needed for FLT_EPSILON
|
|
#include "basetypes.h"
|
|
#include <memory.h>
|
|
#include "tier0/dbg.h"
|
|
#include "mathlib/mathlib.h"
|
|
#include "mathlib/vector.h"
|
|
#include "mathlib/spherical_geometry.h"
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
float s_flFactorials[]={
|
|
1.,
|
|
1.,
|
|
2.,
|
|
6.,
|
|
24.,
|
|
120.,
|
|
720.,
|
|
5040.,
|
|
40320.,
|
|
362880.,
|
|
3628800.,
|
|
39916800.,
|
|
479001600.,
|
|
6227020800.,
|
|
87178291200.,
|
|
1307674368000.,
|
|
20922789888000.,
|
|
355687428096000.,
|
|
6402373705728000.,
|
|
121645100408832000.,
|
|
2432902008176640000.,
|
|
51090942171709440000.,
|
|
1124000727777607680000.,
|
|
25852016738884976640000.,
|
|
620448401733239439360000.,
|
|
15511210043330985984000000.,
|
|
403291461126605635584000000.,
|
|
10888869450418352160768000000.,
|
|
304888344611713860501504000000.,
|
|
8841761993739701954543616000000.,
|
|
265252859812191058636308480000000.,
|
|
8222838654177922817725562880000000.,
|
|
263130836933693530167218012160000000.,
|
|
8683317618811886495518194401280000000.
|
|
};
|
|
|
|
float AssociatedLegendrePolynomial( int nL, int nM, float flX )
|
|
{
|
|
// evaluate associated legendre polynomial at flX, using recurrence relation
|
|
float flPmm = 1.;
|
|
if ( nM > 0 )
|
|
{
|
|
float flSomX2 = sqrt( ( 1 - flX ) * ( 1 + flX ) );
|
|
float flFact = 1.;
|
|
for( int i = 0 ; i < nM; i++ )
|
|
{
|
|
flPmm *= -flFact * flSomX2;
|
|
flFact += 2.0;
|
|
}
|
|
}
|
|
if ( nL == nM )
|
|
return flPmm;
|
|
float flPmmp1 = flX * ( 2.0 * nM + 1.0 ) * flPmm;
|
|
if ( nL == nM + 1 )
|
|
return flPmmp1;
|
|
float flPll = 0.;
|
|
for( int nLL = nM + 2 ; nLL <= nL; nLL++ )
|
|
{
|
|
flPll = ( ( 2.0 * nLL - 1.0 ) * flX * flPmmp1 - ( nLL + nM - 1.0 ) * flPmm ) * ( 1.0 / ( nLL - nM ) );
|
|
flPmm = flPmmp1;
|
|
flPmmp1 = flPll;
|
|
}
|
|
return flPll;
|
|
}
|
|
|
|
static float SHNormalizationFactor( int nL, int nM )
|
|
{
|
|
double flTemp = ( ( 2. * nL + 1.0 ) * s_flFactorials[ nL - nM ] )/ ( 4. * M_PI * s_flFactorials[ nL + nM ] );
|
|
return sqrt( flTemp );
|
|
}
|
|
|
|
#define SQRT_2 1.414213562373095
|
|
|
|
FORCEINLINE float SphericalHarmonic( int nL, int nM, float flTheta, float flPhi, float flCosTheta )
|
|
{
|
|
if ( nM == 0 )
|
|
return SHNormalizationFactor( nL, 0 ) * AssociatedLegendrePolynomial( nL, nM, flCosTheta );
|
|
|
|
if ( nM > 0 )
|
|
return SQRT_2 * SHNormalizationFactor( nL, nM ) * cos ( nM * flPhi ) *
|
|
AssociatedLegendrePolynomial( nL, nM, flCosTheta );
|
|
|
|
return
|
|
SQRT_2 * SHNormalizationFactor( nL, -nM ) * sin( -nM * flPhi ) * AssociatedLegendrePolynomial( nL, -nM, flCosTheta );
|
|
|
|
}
|
|
|
|
float SphericalHarmonic( int nL, int nM, float flTheta, float flPhi )
|
|
{
|
|
return SphericalHarmonic( nL, nM, flTheta, flPhi, cos( flTheta ) );
|
|
}
|
|
|
|
float SphericalHarmonic( int nL, int nM, Vector const &vecDirection )
|
|
{
|
|
Assert( fabs( VectorLength( vecDirection ) - 1.0 ) < 0.0001 );
|
|
float flPhi = acos( vecDirection.z );
|
|
float flTheta = 0;
|
|
float S = Square( vecDirection.x ) + Square( vecDirection.y );
|
|
if ( S > 0 )
|
|
{
|
|
flTheta = atan2( vecDirection.y, vecDirection.x );
|
|
}
|
|
return SphericalHarmonic( nL, nM, flTheta, flPhi, cos( flTheta ) );
|
|
}
|
|
|