A equação de transferência é uma equação integral que
descreve o efeito de um meio participativo na
distribuição da radiância. Para seu calculo se usa
integração de Monte Carlo.
Considere primeiro a função de Henyey-Greenstein
Esta técnica de amostragem é implementada aqui em uma
rotina que toma um vetor , o parametro
assimétrico e dois números aleatórios, amostras desta
distribuição, e usa o resultado para construir o
correspondente raio de saída.
00148 COREDLL Vector SampleHG(const Vector &w, float g, 00149 float u1, float u2) { 00150 float costheta; 00151 if (fabsf(g) < 1e-3) 00152 costheta = 1.f - 2.f * u1; 00153 else 00154 costheta = -1.f / (2.f * g) * 00155 (1.f + g*g - ((1.f-g*g) * (1.f-g+2.f*g*u1))); 00156 float sintheta = sqrtf(max(0.f, 1.f-costheta*costheta)); 00157 float phi = 2.f * M_PI * u2; 00158 Vector v1, v2; 00159 CoordinateSystem(w, &v1, &v2); 00160 return SphericalDirection(sintheta, costheta, 00161 phi, v1, v2, w); 00162 }
Porque as funções de fase são já funções de
distribuição, a densidade de probabilidade para
amostrar qualquer direção partículasr é o valor da
função fase para um par dado de direções.
00163 COREDLL float HGPdf(const Vector &w, const Vector &wp, 00164 float g) { 00165 return PhaseHG(w, wp, g); 00166 }
Calculando a espessura óptica.
mede o total de densidade do meio participativo
que o raio passa.
DensityRegion::Tau() calcula uma estimação da
espessura óptica para um raio passando através de um
meio qualquer.
Lembremos
, onde
E seu valor é estimado por
A natural aproximação é aplicar amostragem
estratificada, dividindo a linha de 0 ate em
pedaço e pegando uma amostra aleatória em cada um.
Pauly, Kolling e Keller 2000 mostram que a técnica de
integração mais eficiente para este problema é gerar
um parametro estratificado onde a amostra adentro de
cada estrato tem o mesmo offset.
O método Tau() aplica esta técnica, a qual somente pega uma variável aleatória simples . E indiretamente escolhe o número de amostras tomadas por o estimador chamado de passo em stepSize, e acha o tamanho do estrato e o método que acha o comprimento de um raio dado. Logo calcula assim
00124 Spectrum DensityRegion::Tau(const Ray &r, 00125 float stepSize, float u) const { 00126 float t0, t1; 00127 float length = r.d.Length(); 00128 if (length == 0.f) return 0.f; 00129 Ray rn(r.o, r.d / length, 00130 r.mint * length, 00131 r.maxt * length); 00132 if (!IntersectP(rn, &t0, &t1)) return 0.; 00133 Spectrum tau(0.); 00134 t0 += u * stepSize; 00135 while (t0 < t1) { 00136 tau += sigma_t(rn(t0), -rn.d); 00137 t0 += stepSize; 00138 } 00139 return tau * stepSize; 00140 }
Integradores Volumétricos
A equação de transferência governa o comportamento da
luz em um meio que absorve, que emite e dispersa radiância.
Temos que
O primeiro termo é a radiância emitida pela superfície
e esta radiância pode ser atenuada pelo meio
participativo.
E a transmissão do raio calcula esta atenuação.
O segundo termo calcula a radiância adicionada ao
longo do raio devido a emissão de volta ao ponto.
A classe VolumeIntegrator:
Os metodos Preprocess() e RequestSamples() são da
mesma forma que integradores de superfície.
O método
dá a radiância ao longo do raio devido
ao meio participativo. Ray::maxt dá o valor da
interseção do raio com a superfície.
O integrador volumétrico somente calcula a dispersão
volumétrica em [mint,maxt].
Transmittance() calcula a transmissão de Ray::mint ate
Ray::maxt.
00096 class VolumeIntegrator : public Integrator { 00097 public: 00098 virtual Spectrum Transmittance(const Scene *scene, 00099 const Ray &ray, const Sample *sample, 00100 float *alpha) const = 0; 00101 };