User Tools

Site Tools




Irradiance is diffuse reflection and is in Lys calculated as Lambertian diffuse reflection.

This target can either be exported as an image or alternatively as 9 spherical harmonic coefficients. This provides a very efficient form of compression which works well with irradiance due to how blurred the appearance of irradiance is.

Irradiance As A Spherical Harmonics Expansion

Lys allows you to export the irradiance as a nine coefficient spherical harmonic expansion per channel.

These may be exported either as text or as a 9×1 floating point texture. The initial pixel represents the first band. The next three pixels represent the second band and the last five pixels represent the third band of the expansion. The orientation of the spherical harmonic expansion is identical to that of the destination cube map and the color space is always linear. An example of how to sample the function is shown below.

float coeffsSH(const int l, const int m, vec3 v);
vec3 SampleExpansionSH(sampler2D ShCoeffs_tex, vec3 v)
   // fetch all coefficients
   // pre-load these if you intend to sample more than once.
   vec3 coeffL0 = texelFetch(ShCoeffs_tex, ivec2(0,0), 0).xyz;
   vec3 coeffL1[3] = vec3[3]( texelFetch(ShCoeffs_tex, ivec2(1,0), 0).xyz,
                  texelFetch(ShCoeffs_tex, ivec2(2,0), 0).xyz,
                  texelFetch(ShCoeffs_tex, ivec2(3,0), 0).xyz );
   vec3 coeffL2[5] = vec3[5]( texelFetch(ShCoeffs_tex, ivec2(4,0), 0).xyz,
                  texelFetch(ShCoeffs_tex, ivec2(5,0), 0).xyz,
                  texelFetch(ShCoeffs_tex, ivec2(6,0), 0).xyz,
                  texelFetch(ShCoeffs_tex, ivec2(7,0), 0).xyz,
                  texelFetch(ShCoeffs_tex, ivec2(8,0), 0).xyz );
   // sample and sum up all contributions
   vec3 res = coeffsSH(0, 0, v) * coeffL0 + 
         coeffsSH(1, -1, v) * coeffL1[0] + coeffsSH(1, 0, v) * coeffL1[1] + coeffsSH(1, 1, v) * coeffL1[2] +
         coeffsSH(2, -2, v) * coeffL2[0] + coeffsSH(2, -1, v) * coeffL2[1] + coeffsSH(2, 0, v) * coeffL2[2] +
         coeffsSH(2, 1, v) * coeffL2[3] + coeffsSH(2, 2, v) * coeffL2[4];
   res = max(res, vec3(0.0));	// don't want negative values
   // to view as color divide by pi and convert to gamma space
   // vec3 vGammaColor = pow(res/M_PI, 1/2.2);
   return res;
// though this function looks complex most of it is optimized away
// by the shader compiler since l and m are known compile time.
float coeffsSH(const int l, const int m, vec3 v)
   float fRes = (1.0/2.0) * sqrt(1.0/M_PI);
   float x = v.x, y = v.y, z = v.z;
      case 1:
      { fRes = (1.0/2.0) * sqrt(3.0f/M_PI) * (m==-1 ? y : (m==0 ? z : x));} break;
      case 2:
         const float fS = (m==0 || m==2 ? 0.25 : 0.5) * sqrt((m==0 ? 5.0 : 15.0) / M_PI);
         if(m==-2) fRes = fS * x*y;
         else if(m==-1) fRes = fS * y*z;
         else if(m==0) fRes = fS * (2*z*z - x*x - y*y);
         else if(m==1) fRes = fS * z*x;
         else fRes = fS * (x*x-y*y);
   return fRes;

Irradiance vs Spherical Harmonics

Above we have set out renders1) featuring results of irradiance vs spherical harmonics. The results using irradiance are on the left whereas the right shows the results obtained from spherical harmonics.
1) All HDRI photo based source images shown in the above were kindly provided by Marmoset.
irradiance_lys.txt · Last modified: 2017/05/23 03:49 (external edit)