Sunday, December 25, 2011

Spherical Harmonics

  • Spherical Harmonics com e sem Occ







Spherical Harmonics eh uma tecnica usada muito em games para criar falsa iluminacao ambiente nos objetos , ele dispensa o uso de HDRI para simular a irradiancia sobre o difuse de um shader , apesar da matematica envolvida ser cheio de letras e numeros malucos a aplicacao eh bem simples usando um pouco a ajuda e o programa do paper :

esse paper explica que voce pode pegar todos os valores de "luma"!!! :P atraves de 9 coeficientes processados de um mapa de HDR .. esses coeficientes sao depois multiplicados sobre o diffuse
a formula eh isso aqui :

vector DiffuseColor = vector ( C1 * L22 * (tnorm[0] * tnorm[0] - tnorm[1] * tnorm[1]) +C3 * L20 * tnorm[2] * tnorm[2] +C4 * L00 -C5 * L20 +2.0 * C1 * L2m2 * tnorm[0] * tnorm[1] +2.0 * C1 * L21 * tnorm[0] * tnorm[2]+2.0 * C1 * L2m1 * tnorm[1] * tnorm[2] +2.0 * C2 * L11 * tnorm[0] +2.0 * C2 * L1m1 * tnorm[1] + 2.0 * C2 * L10 * tnorm[2] );

onde cada c1 c2 c3 etc .. sao numeros constantes indicados no paper .. e o L22 L11 etc .. sao coeficientes processados do HDRI ... existe uma tabela de mapas HDRI mais conhecidos para ser usados de exemplo .. o que eu usei eh o mapa Grace cathedral , c for preciso novos coficientes de mapas propios . o paper fornece um codigo em "C" que extrai os coeficientes para voce de um novo mapa , nao testei ainda . mas acho que eh possivel transformar esse codigo em um DSO para o renderman . assim extrair o coeficiente em renderTime c for o caso ... aqui vai a tabela :

um detalhe, como essa eh uma tecnica para produzir luz ambiente . ela nao gera sombra, alguns papers na net demonstram outras formas de usar esse calculo para retirar
o sample de cor pra producao de bleeding e sombras usando raytracing . mas basicamente
eh um looping de gather conferindo onde o raio obteve ou nao colisao , caso nao , ele utiliza o spherical harmonic para produzir o occlsuion , aqui . eu usei um simples occlusion do renderman para produzir isso. detalhe spherical harmonics pode ser usados tbm na composicao .. caso voce tenha um pass de normal ... no video "Nuke master Class de Roy Stelzer" encontrado no propio site da Foundry .. ele demonstra como aplicar isso ..

bem segue o codigo do shader :


  • surface spherical(float scalefactor = .2 , samples = 32 , occOnOff = 0.0)
  • {
  • // spherical harmonics coeficients
  • float C1 = 0.429043;
  • float C2 = 0.511664;
  • float C3 = 0.743125;
  • float C4 = 0.886227;
  • float C5 = 0.247708;
  • // Constants for Old Town Square lighting
  • vector L00 = vector( .79, .44, 0.54);
  • vector L1m1 = vector( 0.39, 0.35, 0.60);
  • vector L10 = vector( -0.34, -0.18, -0.27);
  • vector L11 = vector(-0.29, -0.06, .01);
  • vector L2m2 = vector(-0.11, -0.05, -0.12);
  • vector L2m1 = vector( -0.26, -0.22, -0.47);
  • vector L20 = vector(-0.16, -0.09, -0.15);
  • vector L21 = vector(0.56, 0.21, .14);
  • vector L22 = vector(.21, -0.05, -0.30);
  • vector tnorm = vector(faceforward(normalize(N),I));
  • vector DiffuseColor = vector ( C1 * L22 * (tnorm[0] * tnorm[0] - tnorm[1] * tnorm[1]) +
  • C3 * L20 * tnorm[2] * tnorm[2] +C4 * L00 -
  • C5 * L20 +
  • 2.0 * C1 * L2m2 * tnorm[0] * tnorm[1] +
  • 2.0 * C1 * L21 * tnorm[0] * tnorm[2]+
  • 2.0 * C1 * L2m1 * tnorm[1] * tnorm[2] +
  • 2.0 * C2 * L11 * tnorm[0] +
  • 2.0 * C2 * L1m1 * tnorm[1] +
  • 2.0 * C2 * L10 * tnorm[2] );
  • //occlusion
  • float average;
  • normal n = normalize(N),
  • nf = faceforward(n, I);
  • float hits = 0;
  • if(occOnOff != 0.0)
  • {
  • gather("illuminance", P, nf, PI/2, samples, "distribution","cosine")
  • {
  • hits += 1;
  • }
  • average = hits / samples;
  • }
  • else
  • {
  • average = 0;
  • }
  • Ci = (color(DiffuseColor * scalefactor)) - average;
  • Oi = 1;
  • }



  •