/// <summary> /// Generate a spherical harmonic from the faces of a cubemap, treating each pixel as a light source and averaging the result. /// </summary> public static SphericalHarmonicL1RGB GenerateSphericalHarmonicFromCubeMap( Vector3[] colourDataPositiveX, Vector3[] colourDataNegativeX, Vector3[] colourDataPositiveY, Vector3[] colourDataNegativeY, Vector3[] colourDataPositiveZ, Vector3[] colourDataNegativeZ) { if (colourDataPositiveX == null || colourDataNegativeX == null || colourDataPositiveY == null || colourDataNegativeY == null || colourDataPositiveZ == null || colourDataNegativeZ == null) throw new ArgumentNullException(); SphericalHarmonicL1RGB sh = new SphericalHarmonicL1RGB(); Vector3[][] source = { colourDataPositiveX, colourDataNegativeX, colourDataPositiveY, colourDataNegativeY, colourDataPositiveZ, colourDataNegativeZ, }; //extract the 6 faces of the cubemap. for (int face = 0; face < 6; face++) { int size = (int)(Math.Sqrt(source[face].Length) + 0.5); if (size * size != source[face].Length) throw new ArgumentException("Cubemap face is an unexpected (non square) size"); Microsoft.Xna.Framework.Graphics.CubeMapFace faceId = (Microsoft.Xna.Framework.Graphics.CubeMapFace)face; //get the transformation for this face, Matrix cubeFaceMatrix; Xen.Graphics.DrawTargetTextureCube.GetCubeMapFaceMatrix(faceId, out cubeFaceMatrix); //extract the spherical harmonic for this face and accumulate it. sh += ExtractSphericalHarmonicForCubeFace(cubeFaceMatrix, source[face], size); } //average out over the sphere. account for cosine weighting which doubles the output - but it's also over a full sphere not a hemisphere return sh / 3; }
/// <summary> /// Multiply a spherical harmonic by a constant scale factor /// </summary> public static SphericalHarmonicL1RGB operator *(SphericalHarmonicL1RGB x, float scale) { SphericalHarmonicL1RGB o = new SphericalHarmonicL1RGB(); o.Red.X = x.Red.X * scale; o.Red.Y = x.Red.Y * scale; o.Red.Z = x.Red.Z * scale; o.Blue.X = x.Blue.X * scale; o.Blue.Y = x.Blue.Y * scale; o.Blue.Z = x.Blue.Z * scale; o.Green.X = x.Green.X * scale; o.Green.Y = x.Green.Y * scale; o.Green.Z = x.Green.Z * scale; return o; }
/// <summary> /// Divide a spherical harmonic by a constant factor /// </summary> public static SphericalHarmonicL1RGB operator /(SphericalHarmonicL1RGB x, float divider) { SphericalHarmonicL1RGB o = new SphericalHarmonicL1RGB(); float scale = 1.0f / divider; o.Red.X = x.Red.X * scale; o.Red.Y = x.Red.Y * scale; o.Red.Z = x.Red.Z * scale; o.Blue.X = x.Blue.X * scale; o.Blue.Y = x.Blue.Y * scale; o.Blue.Z = x.Blue.Z * scale; o.Green.X = x.Green.X * scale; o.Green.Y = x.Green.Y * scale; o.Green.Z = x.Green.Z * scale; return o; }
/// <summary> /// Add two spherical harmonics together /// </summary> public static SphericalHarmonicL1RGB operator +(SphericalHarmonicL1RGB x, SphericalHarmonicL1RGB y) { SphericalHarmonicL1RGB o = new SphericalHarmonicL1RGB(); o.Red.X = x.Red.X + y.Red.X; o.Red.Y = x.Red.Y + y.Red.Y; o.Red.Z = x.Red.Z + y.Red.Z; o.Blue.X = x.Blue.X + y.Blue.X; o.Blue.Y = x.Blue.Y + y.Blue.Y; o.Blue.Z = x.Blue.Z + y.Blue.Z; o.Green.X = x.Green.X + y.Green.X; o.Green.Y = x.Green.Y + y.Green.Y; o.Green.Z = x.Green.Z + y.Green.Z; return o; }
/// <summary> /// Linear interpolate (Lerp) between two spherical harmonics based on a interpolation factor /// </summary> /// <param name="factor">Determines the interpolation point. When factor is 1.0, the output will be <paramref name="x"/>, when factor is 0.0, the output will be <paramref name="y"/></param> /// <param name="result"></param> /// <param name="x"></param> /// <param name="y"></param> public static void Lerp(ref SphericalHarmonicL1RGB x, ref SphericalHarmonicL1RGB y, float factor, out SphericalHarmonicL1RGB result) { result = new SphericalHarmonicL1RGB(); float xs = factor; float ys = 1.0f - factor; result.Red.X = xs * x.Red.X + ys * y.Red.X; result.Red.Y = xs * x.Red.Y + ys * y.Red.Y; result.Red.Z = xs * x.Red.Z + ys * y.Red.Z; result.Blue.X = xs * x.Blue.X + ys * y.Blue.X; result.Blue.Y = xs * x.Blue.Y + ys * y.Blue.Y; result.Blue.Z = xs * x.Blue.Z + ys * y.Blue.Z; result.Green.X = xs * x.Green.X + ys * y.Green.X; result.Green.Y = xs * x.Green.Y + ys * y.Green.Y; result.Green.Z = xs * x.Green.Z + ys * y.Green.Z; }
/// <summary> /// Divide a spherical harmonic by a constant factor /// </summary> public static void Divide(ref SphericalHarmonicL1RGB x, float divider, out SphericalHarmonicL1RGB result) { result = new SphericalHarmonicL1RGB(); float scale = 1.0f / divider; result.Red.X = x.Red.X * scale; result.Red.Y = x.Red.Y * scale; result.Red.Z = x.Red.Z * scale; result.Blue.X = x.Blue.X * scale; result.Blue.Y = x.Blue.Y * scale; result.Blue.Z = x.Blue.Z * scale; result.Green.X = x.Green.X * scale; result.Green.Y = x.Green.Y * scale; result.Green.Z = x.Green.Z * scale; }
/// <summary> /// Multiply a spherical harmonic by a constant scale factor /// </summary> public static void Multiply(ref SphericalHarmonicL1RGB x, float scale, out SphericalHarmonicL1RGB result) { result = new SphericalHarmonicL1RGB(); result.Red.X = x.Red.X * scale; result.Red.Y = x.Red.Y * scale; result.Red.Z = x.Red.Z * scale; result.Blue.X = x.Blue.X * scale; result.Blue.Y = x.Blue.Y * scale; result.Blue.Z = x.Blue.Z * scale; result.Green.X = x.Green.X * scale; result.Green.Y = x.Green.Y * scale; result.Green.Z = x.Green.Z * scale; }
/// <summary> /// Add two spherical harmonics together /// </summary> public static void Add(ref SphericalHarmonicL1RGB x, ref SphericalHarmonicL1RGB y, out SphericalHarmonicL1RGB result) { result = new SphericalHarmonicL1RGB(); result.Red.X = x.Red.X + y.Red.X; result.Red.Y = x.Red.Y + y.Red.Y; result.Red.Z = x.Red.Z + y.Red.Z; result.Blue.X = x.Blue.X + y.Blue.X; result.Blue.Y = x.Blue.Y + y.Blue.Y; result.Blue.Z = x.Blue.Z + y.Blue.Z; result.Green.X = x.Green.X + y.Green.X; result.Green.Y = x.Green.Y + y.Green.Y; result.Green.Z = x.Green.Z + y.Green.Z; }