/// <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 SphericalHarmonicL2RGB 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(); } SphericalHarmonicL2RGB sh = new SphericalHarmonicL2RGB(); 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 return(sh.GetWeightedAverageLightInputFromSphere()); }
/// <summary> /// Multiply a spherical harmonic by a constant scale factor /// </summary> public static void Multiply(ref SphericalHarmonicL2RGB x, float scale, out SphericalHarmonicL2RGB result) { result = new SphericalHarmonicL2RGB(); result.Weighting = x.Weighting * scale; result.SH0.X = x.SH0.X * scale; result.SH0.Y = x.SH0.Y * scale; result.SH0.Z = x.SH0.Z * scale; result.SH1.X = x.SH1.X * scale; result.SH1.Y = x.SH1.Y * scale; result.SH1.Z = x.SH1.Z * scale; result.SH2.X = x.SH2.X * scale; result.SH2.Y = x.SH2.Y * scale; result.SH2.Z = x.SH2.Z * scale; result.SH3.X = x.SH3.X * scale; result.SH3.Y = x.SH3.Y * scale; result.SH3.Z = x.SH3.Z * scale; result.SH4.X = x.SH4.X * scale; result.SH4.Y = x.SH4.Y * scale; result.SH4.Z = x.SH4.Z * scale; result.SH5.X = x.SH5.X * scale; result.SH5.Y = x.SH5.Y * scale; result.SH5.Z = x.SH5.Z * scale; result.SH6.X = x.SH6.X * scale; result.SH6.Y = x.SH6.Y * scale; result.SH6.Z = x.SH6.Z * scale; result.SH7.X = x.SH7.X * scale; result.SH7.Y = x.SH7.Y * scale; result.SH7.Z = x.SH7.Z * scale; result.SH8.X = x.SH8.X * scale; result.SH8.Y = x.SH8.Y * scale; result.SH8.Z = x.SH8.Z * scale; }
/// <summary> /// Add two spherical harmonics together /// </summary> public static void Add(ref SphericalHarmonicL2RGB x, ref SphericalHarmonicL2RGB y, out SphericalHarmonicL2RGB result) { result = new SphericalHarmonicL2RGB(); result.Weighting = x.Weighting + y.Weighting; result.SH0.X = x.SH0.X + y.SH0.X; result.SH0.Y = x.SH0.Y + y.SH0.Y; result.SH0.Z = x.SH0.Z + y.SH0.Z; result.SH1.X = x.SH1.X + y.SH1.X; result.SH1.Y = x.SH1.Y + y.SH1.Y; result.SH1.Z = x.SH1.Z + y.SH1.Z; result.SH2.X = x.SH2.X + y.SH2.X; result.SH2.Y = x.SH2.Y + y.SH2.Y; result.SH2.Z = x.SH2.Z + y.SH2.Z; result.SH3.X = x.SH3.X + y.SH3.X; result.SH3.Y = x.SH3.Y + y.SH3.Y; result.SH3.Z = x.SH3.Z + y.SH3.Z; result.SH4.X = x.SH4.X + y.SH4.X; result.SH4.Y = x.SH4.Y + y.SH4.Y; result.SH4.Z = x.SH4.Z + y.SH4.Z; result.SH5.X = x.SH5.X + y.SH5.X; result.SH5.Y = x.SH5.Y + y.SH5.Y; result.SH5.Z = x.SH5.Z + y.SH5.Z; result.SH6.X = x.SH6.X + y.SH6.X; result.SH6.Y = x.SH6.Y + y.SH6.Y; result.SH6.Z = x.SH6.Z + y.SH6.Z; result.SH7.X = x.SH7.X + y.SH7.X; result.SH7.Y = x.SH7.Y + y.SH7.Y; result.SH7.Z = x.SH7.Z + y.SH7.Z; result.SH8.X = x.SH8.X + y.SH8.X; result.SH8.Y = x.SH8.Y + y.SH8.Y; result.SH8.Z = x.SH8.Z + y.SH8.Z; }
/// <summary> /// Multiply a spherical harmonic by a constant scale factor /// </summary> public static SphericalHarmonicL2RGB operator *(SphericalHarmonicL2RGB x, float scale) { SphericalHarmonicL2RGB o = new SphericalHarmonicL2RGB(); o.Weighting = x.Weighting * scale; o.SH0.X = x.SH0.X * scale; o.SH0.Y = x.SH0.Y * scale; o.SH0.Z = x.SH0.Z * scale; o.SH1.X = x.SH1.X * scale; o.SH1.Y = x.SH1.Y * scale; o.SH1.Z = x.SH1.Z * scale; o.SH2.X = x.SH2.X * scale; o.SH2.Y = x.SH2.Y * scale; o.SH2.Z = x.SH2.Z * scale; o.SH3.X = x.SH3.X * scale; o.SH3.Y = x.SH3.Y * scale; o.SH3.Z = x.SH3.Z * scale; o.SH4.X = x.SH4.X * scale; o.SH4.Y = x.SH4.Y * scale; o.SH4.Z = x.SH4.Z * scale; o.SH5.X = x.SH5.X * scale; o.SH5.Y = x.SH5.Y * scale; o.SH5.Z = x.SH5.Z * scale; o.SH6.X = x.SH6.X * scale; o.SH6.Y = x.SH6.Y * scale; o.SH6.Z = x.SH6.Z * scale; o.SH7.X = x.SH7.X * scale; o.SH7.Y = x.SH7.Y * scale; o.SH7.Z = x.SH7.Z * scale; o.SH8.X = x.SH8.X * scale; o.SH8.Y = x.SH8.Y * scale; o.SH8.Z = x.SH8.Z * scale; return(o); }
/// <summary> /// Add two spherical harmonics together /// </summary> public static SphericalHarmonicL2RGB operator +(SphericalHarmonicL2RGB x, SphericalHarmonicL2RGB y) { SphericalHarmonicL2RGB o = new SphericalHarmonicL2RGB(); o.Weighting = x.Weighting + y.Weighting; o.SH0.X = x.SH0.X + y.SH0.X; o.SH0.Y = x.SH0.Y + y.SH0.Y; o.SH0.Z = x.SH0.Z + y.SH0.Z; o.SH1.X = x.SH1.X + y.SH1.X; o.SH1.Y = x.SH1.Y + y.SH1.Y; o.SH1.Z = x.SH1.Z + y.SH1.Z; o.SH2.X = x.SH2.X + y.SH2.X; o.SH2.Y = x.SH2.Y + y.SH2.Y; o.SH2.Z = x.SH2.Z + y.SH2.Z; o.SH3.X = x.SH3.X + y.SH3.X; o.SH3.Y = x.SH3.Y + y.SH3.Y; o.SH3.Z = x.SH3.Z + y.SH3.Z; o.SH4.X = x.SH4.X + y.SH4.X; o.SH4.Y = x.SH4.Y + y.SH4.Y; o.SH4.Z = x.SH4.Z + y.SH4.Z; o.SH5.X = x.SH5.X + y.SH5.X; o.SH5.Y = x.SH5.Y + y.SH5.Y; o.SH5.Z = x.SH5.Z + y.SH5.Z; o.SH6.X = x.SH6.X + y.SH6.X; o.SH6.Y = x.SH6.Y + y.SH6.Y; o.SH6.Z = x.SH6.Z + y.SH6.Z; o.SH7.X = x.SH7.X + y.SH7.X; o.SH7.Y = x.SH7.Y + y.SH7.Y; o.SH7.Z = x.SH7.Z + y.SH7.Z; o.SH8.X = x.SH8.X + y.SH8.X; o.SH8.Y = x.SH8.Y + y.SH8.Y; o.SH8.Z = x.SH8.Z + y.SH8.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 SphericalHarmonicL2RGB x, ref SphericalHarmonicL2RGB y, float factor, out SphericalHarmonicL2RGB result) { result = new SphericalHarmonicL2RGB(); float xs = factor; float ys = 1.0f - factor; result.Weighting = x.Weighting * xs + y.Weighting * ys; result.SH0.X = xs * x.SH0.X + ys * y.SH0.X; result.SH0.Y = xs * x.SH0.Y + ys * y.SH0.Y; result.SH0.Z = xs * x.SH0.Z + ys * y.SH0.Z; result.SH1.X = xs * x.SH1.X + ys * y.SH1.X; result.SH1.Y = xs * x.SH1.Y + ys * y.SH1.Y; result.SH1.Z = xs * x.SH1.Z + ys * y.SH1.Z; result.SH2.X = xs * x.SH2.X + ys * y.SH2.X; result.SH2.Y = xs * x.SH2.Y + ys * y.SH2.Y; result.SH2.Z = xs * x.SH2.Z + ys * y.SH2.Z; result.SH3.X = xs * x.SH3.X + ys * y.SH3.X; result.SH3.Y = xs * x.SH3.Y + ys * y.SH3.Y; result.SH3.Z = xs * x.SH3.Z + ys * y.SH3.Z; result.SH4.X = xs * x.SH4.X + ys * y.SH4.X; result.SH4.Y = xs * x.SH4.Y + ys * y.SH4.Y; result.SH4.Z = xs * x.SH4.Z + ys * y.SH4.Z; result.SH5.X = xs * x.SH5.X + ys * y.SH5.X; result.SH5.Y = xs * x.SH5.Y + ys * y.SH5.Y; result.SH5.Z = xs * x.SH5.Z + ys * y.SH5.Z; result.SH6.X = xs * x.SH6.X + ys * y.SH6.X; result.SH6.Y = xs * x.SH6.Y + ys * y.SH6.Y; result.SH6.Z = xs * x.SH6.Z + ys * y.SH6.Z; result.SH7.X = xs * x.SH7.X + ys * y.SH7.X; result.SH7.Y = xs * x.SH7.Y + ys * y.SH7.Y; result.SH7.Z = xs * x.SH7.Z + ys * y.SH7.Z; result.SH8.X = xs * x.SH8.X + ys * y.SH8.X; result.SH8.Y = xs * x.SH8.Y + ys * y.SH8.Y; result.SH8.Z = xs * x.SH8.Z + ys * y.SH8.Z; }
/// <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 SphericalHarmonicL2RGB 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(); SphericalHarmonicL2RGB sh = new SphericalHarmonicL2RGB(); 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 return sh.GetWeightedAverageLightInputFromSphere(); }
/// <summary> /// Divide a spherical harmonic by a constant factor /// </summary> public static SphericalHarmonicL2RGB operator /(SphericalHarmonicL2RGB x, float divider) { SphericalHarmonicL2RGB o = new SphericalHarmonicL2RGB(); float scale = 1.0f / divider; o.Weighting = x.Weighting * scale; o.SH0.X = x.SH0.X * scale; o.SH0.Y = x.SH0.Y * scale; o.SH0.Z = x.SH0.Z * scale; o.SH1.X = x.SH1.X * scale; o.SH1.Y = x.SH1.Y * scale; o.SH1.Z = x.SH1.Z * scale; o.SH2.X = x.SH2.X * scale; o.SH2.Y = x.SH2.Y * scale; o.SH2.Z = x.SH2.Z * scale; o.SH3.X = x.SH3.X * scale; o.SH3.Y = x.SH3.Y * scale; o.SH3.Z = x.SH3.Z * scale; o.SH4.X = x.SH4.X * scale; o.SH4.Y = x.SH4.Y * scale; o.SH4.Z = x.SH4.Z * scale; o.SH5.X = x.SH5.X * scale; o.SH5.Y = x.SH5.Y * scale; o.SH5.Z = x.SH5.Z * scale; o.SH6.X = x.SH6.X * scale; o.SH6.Y = x.SH6.Y * scale; o.SH6.Z = x.SH6.Z * scale; o.SH7.X = x.SH7.X * scale; o.SH7.Y = x.SH7.Y * scale; o.SH7.Z = x.SH7.Z * scale; o.SH8.X = x.SH8.X * scale; o.SH8.Y = x.SH8.Y * scale; o.SH8.Z = x.SH8.Z * scale; return o; }
/// <summary> /// Add two spherical harmonics together /// </summary> public static SphericalHarmonicL2RGB operator +(SphericalHarmonicL2RGB x, SphericalHarmonicL2RGB y) { SphericalHarmonicL2RGB o = new SphericalHarmonicL2RGB(); o.Weighting = x.Weighting + y.Weighting; o.SH0.X = x.SH0.X + y.SH0.X; o.SH0.Y = x.SH0.Y + y.SH0.Y; o.SH0.Z = x.SH0.Z + y.SH0.Z; o.SH1.X = x.SH1.X + y.SH1.X; o.SH1.Y = x.SH1.Y + y.SH1.Y; o.SH1.Z = x.SH1.Z + y.SH1.Z; o.SH2.X = x.SH2.X + y.SH2.X; o.SH2.Y = x.SH2.Y + y.SH2.Y; o.SH2.Z = x.SH2.Z + y.SH2.Z; o.SH3.X = x.SH3.X + y.SH3.X; o.SH3.Y = x.SH3.Y + y.SH3.Y; o.SH3.Z = x.SH3.Z + y.SH3.Z; o.SH4.X = x.SH4.X + y.SH4.X; o.SH4.Y = x.SH4.Y + y.SH4.Y; o.SH4.Z = x.SH4.Z + y.SH4.Z; o.SH5.X = x.SH5.X + y.SH5.X; o.SH5.Y = x.SH5.Y + y.SH5.Y; o.SH5.Z = x.SH5.Z + y.SH5.Z; o.SH6.X = x.SH6.X + y.SH6.X; o.SH6.Y = x.SH6.Y + y.SH6.Y; o.SH6.Z = x.SH6.Z + y.SH6.Z; o.SH7.X = x.SH7.X + y.SH7.X; o.SH7.Y = x.SH7.Y + y.SH7.Y; o.SH7.Z = x.SH7.Z + y.SH7.Z; o.SH8.X = x.SH8.X + y.SH8.X; o.SH8.Y = x.SH8.Y + y.SH8.Y; o.SH8.Z = x.SH8.Z + y.SH8.Z; return o; }
/// <summary> /// Divide a spherical harmonic by a constant factor /// </summary> public static void Divide(ref SphericalHarmonicL2RGB x, float divider, out SphericalHarmonicL2RGB result) { result = new SphericalHarmonicL2RGB(); float scale = 1.0f / divider; result.Weighting = x.Weighting * scale; result.SH0.X = x.SH0.X * scale; result.SH0.Y = x.SH0.Y * scale; result.SH0.Z = x.SH0.Z * scale; result.SH1.X = x.SH1.X * scale; result.SH1.Y = x.SH1.Y * scale; result.SH1.Z = x.SH1.Z * scale; result.SH2.X = x.SH2.X * scale; result.SH2.Y = x.SH2.Y * scale; result.SH2.Z = x.SH2.Z * scale; result.SH3.X = x.SH3.X * scale; result.SH3.Y = x.SH3.Y * scale; result.SH3.Z = x.SH3.Z * scale; result.SH4.X = x.SH4.X * scale; result.SH4.Y = x.SH4.Y * scale; result.SH4.Z = x.SH4.Z * scale; result.SH5.X = x.SH5.X * scale; result.SH5.Y = x.SH5.Y * scale; result.SH5.Z = x.SH5.Z * scale; result.SH6.X = x.SH6.X * scale; result.SH6.Y = x.SH6.Y * scale; result.SH6.Z = x.SH6.Z * scale; result.SH7.X = x.SH7.X * scale; result.SH7.Y = x.SH7.Y * scale; result.SH7.Z = x.SH7.Z * scale; result.SH8.X = x.SH8.X * scale; result.SH8.Y = x.SH8.Y * scale; result.SH8.Z = x.SH8.Z * scale; }