} // Lerp

        #endregion

        #region Generate Spherical Harmonic from CubeMap

        /// <summary>
        /// Generate a spherical harmonic from the faces of a cubemap, treating each pixel as a light source and averaging the result.
        /// This method only accepts RGBM and color textures.
        /// </summary>
        public static SphericalHarmonicL2 GenerateSphericalHarmonicFromCubeTexture(TextureCube cubeTexture)
        {
            if (cubeTexture.Resource.Format != SurfaceFormat.Color)
            {
                throw new InvalidOperationException("Spherical Harmonic: the texture has to have a color surface format. DXT and floating point formats are not supported for the moment.");
            }

            SphericalHarmonicL2 sh = new SphericalHarmonicL2();

            // Extract the 6 faces of the cubemap.
            for (int face = 0; face < 6; face++)
            {
                CubeMapFace faceId = (CubeMapFace)face;

                // Get the transformation for this face.
                Matrix cubeFaceMatrix;
                switch (faceId)
                {
                case CubeMapFace.PositiveX:
                    cubeFaceMatrix = Matrix.CreateLookAt(Vector3.Zero, new Vector3(1, 0, 0), new Vector3(0, 1, 0));
                    break;

                case CubeMapFace.NegativeX:
                    cubeFaceMatrix = Matrix.CreateLookAt(Vector3.Zero, new Vector3(-1, 0, 0), new Vector3(0, 1, 0));
                    break;

                case CubeMapFace.PositiveY:
                    cubeFaceMatrix = Matrix.CreateLookAt(Vector3.Zero, new Vector3(0, 1, 0), new Vector3(0, 0, 1));
                    break;

                case CubeMapFace.NegativeY:
                    cubeFaceMatrix = Matrix.CreateLookAt(Vector3.Zero, new Vector3(0, -1, 0), new Vector3(0, 0, -1));
                    break;

                case CubeMapFace.PositiveZ:
                    cubeFaceMatrix = Matrix.CreateLookAt(Vector3.Zero, new Vector3(0, 0, -1), new Vector3(0, 1, 0));
                    break;

                case CubeMapFace.NegativeZ:
                    cubeFaceMatrix = Matrix.CreateLookAt(Vector3.Zero, new Vector3(0, 0, 1), new Vector3(0, 1, 0));
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }
                Color[] colorArray = new Color[cubeTexture.Size * cubeTexture.Size];
                cubeTexture.Resource.GetData(faceId, colorArray);

                // Extract the spherical harmonic for this face and accumulate it.
                sh += ExtractSphericalHarmonicForCubeFace(cubeFaceMatrix, colorArray, cubeTexture.Size, cubeTexture.IsRgbm, cubeTexture.RgbmMaxRange);
            }

            // Average out over the sphere.
            return(sh.GetWeightedAverageLightInputFromSphere());
        } // GenerateSphericalHarmonicFromCubeTexture
        } // ExtractSphericalHarmonicForCubeFace

        #endregion

        #region Generate Spherical Harmonic from Lat-Long Texture

        /// <summary>
        /// Generate a spherical harmonic from the faces of a cubemap, treating each pixel as a light source and averaging the result.
        /// This method only accepts floating point textures.
        /// </summary>
        public static SphericalHarmonicL2 GenerateSphericalHarmonicFromLatLongTexture(Texture texture)
        {
            if (texture.Resource.Format != SurfaceFormat.Vector4)
            {
                throw new InvalidOperationException("Spherical Harmonic: the texture has to have a floating point surface format. DXT formats are not supported for the moment.");
            }

            SphericalHarmonicL2 sh = new SphericalHarmonicL2();

            float[] colorArray = new float[texture.Width * texture.Height * 4];
            texture.Resource.GetData(colorArray);

            int pixelIndex = 0;

            for (int y = 0; y < texture.Height; y++)
            {
                SphericalHarmonicL2 lineSh = new SphericalHarmonicL2();

                for (int x = 0; x < texture.Width; x++)
                {
                    // http://www.scratchapixel.com/lessons/3d-advanced-lessons/reflection-mapping/converting-latitute-longitude-maps-and-mirror-balls/
                    float   theta     = (x / (float)texture.Width) * (float)Math.PI;
                    float   phi       = (1 - (y / (float)texture.Height)) * 2 * (float)Math.PI;
                    Vector3 direction = -new Vector3((float)(Math.Sin(theta) * Math.Cos(phi)), (float)(Math.Sin(theta) * Math.Sin(phi)), (float)(Math.Cos(theta)));
                    direction.Normalize();

                    Vector3 rgb = new Vector3(colorArray[pixelIndex * 4], colorArray[pixelIndex * 4 + 1], colorArray[pixelIndex * 4 + 2]);

                    //Add it to the SH
                    lineSh.AddLight(rgb, direction, 1);

                    pixelIndex++;
                }

                //average the SH
                if (lineSh.weighting > 0)
                {
                    lineSh *= 1 / lineSh.weighting;
                }

                // Add the line to the full SH
                // (SH is generated line by line to ease problems with floating point accuracy loss)
                sh += lineSh;
            }

            //average out over the sphere
            return(sh.GetWeightedAverageLightInputFromSphere());
        } // GenerateSphericalHarmonicFromLatLongHdrTexture