protected void GetSHCoefficients(WMath.Vector _Direction, ref double[] _Coefficients) { float x = -_Direction.z; float y = _Direction.y; float z = _Direction.x; // Build the SH coefficients from analytical formulae given in http://www-graphics.stanford.edu/papers/envmap/ _Coefficients[0] = 0.282095; // Y00 _Coefficients[1] = 0.488603 * z; // Y1-1 _Coefficients[2] = 0.488603 * y; // Y10 _Coefficients[3] = 0.488603 * x; // Y1+1 _Coefficients[4] = 1.092548 * x * z; // Y2-2 _Coefficients[5] = 1.092548 * y * z; // Y2-1 _Coefficients[6] = 0.315392 * (3 * y * y - 1); // Y20 _Coefficients[7] = 1.092548 * x * y; // Y2+1 _Coefficients[8] = 0.546274 * (x * x - z * z); // Y2+2 }
/// <summary> /// Initializes the collection of samples /// </summary> /// <param name="_Order">The order of the SH</param> /// <param name="_ThetaSamplesCount">The amount of samples on Theta (total samples count will be 2*N*N)</param> /// <param name="_Up">The vector to use as the Up direction (use [0,1,0] if not sure)</param> public void Initialize(int _Order, int _ThetaSamplesCount, WMath.Vector _Up) { m_Order = _Order; m_ThetaSamplesCount = _ThetaSamplesCount; m_SamplesCount = 2 * m_ThetaSamplesCount * m_ThetaSamplesCount; m_Random = new Random(m_RandomSeed); // Compute the rotation matrix Matrix3x3 Rotation = new Matrix3x3(); Vector Ortho = new Vector(0, 1, 0) ^ _Up; float fNorm = Ortho.SquareMagnitude(); if (fNorm < 1e-6f) { Rotation.MakeIdentity(); } else { Ortho /= (float)Math.Sqrt(fNorm); Rotation.SetRow0(Ortho); Rotation.SetRow1(_Up); Rotation.SetRow2(Ortho ^ _Up); } // Initialize the SH samples m_SHSamples = new SHSample[m_SamplesCount]; // Build the samples using stratified sampling int SampleIndex = 0; for (int ThetaIndex = 0; ThetaIndex < m_ThetaSamplesCount; ThetaIndex++) { for (int PhiIndex = 0; PhiIndex < 2 * m_ThetaSamplesCount; PhiIndex++) { double fTheta = 2.0 * System.Math.Acos(System.Math.Sqrt(1.0 - (ThetaIndex + m_Random.NextDouble()) / m_ThetaSamplesCount)); double fPhi = System.Math.PI * (PhiIndex + m_Random.NextDouble()) / m_ThetaSamplesCount; // Compute direction, rotate it then cast it back to sphercial coordinates Vector Direction = SphericalHarmonics.SHFunctions.SphericalToCartesian(fTheta, fPhi); Direction *= Rotation; SphericalHarmonics.SHFunctions.CartesianToSpherical(Direction, out fTheta, out fPhi); // Fill up the new sample m_SHSamples[SampleIndex] = new SHSample((float)fPhi, (float)fTheta); m_SHSamples[SampleIndex].m_SHFactors = new double[m_Order * m_Order]; // Build the SH Factors SHFunctions.InitializeSHCoefficients(m_Order, fTheta, fPhi, m_SHSamples[SampleIndex].m_SHFactors); SampleIndex++; } } }