u_int SingleScattering::Li(const Scene &scene, const Ray &ray, const Sample &sample, SWCSpectrum *Lv, float *alpha) const { *Lv = 0.f; Region *vr = scene.volumeRegion; float t0, t1; if (!vr || !vr->IntersectP(ray, &t0, &t1)) return 0; // Do single scattering volume integration in _vr_ // Prepare for volume integration stepping const float length = ray.d.Length(); const u_int N = Ceil2UInt((t1 - t0) * length / stepSize); const float step = (t1 - t0) / N; const SpectrumWavelengths &sw(sample.swl); SWCSpectrum Tr(1.f); const Vector w(-ray.d / length); t0 += sample.sampler->GetOneD(sample, tauSampleOffset, 0) * step; Ray r(ray(t0), ray.d, 0.f, step, ray.time); const u_int nLights = scene.lights.size(); const u_int lightNum = min(nLights - 1, Floor2UInt(sample.sampler->GetOneD(sample, scatterSampleOffset, 0) * nLights)); Light *light = scene.lights[lightNum]; // Compute sample patterns for single scattering samples // FIXME - use real samples float *samp = static_cast<float *>(alloca(3 * N * sizeof(float))); LatinHypercube(*(sample.rng), samp, N, 3); u_int sampOffset = 0; DifferentialGeometry dg; dg.p = r.o; dg.nn = Normal(w); for (u_int i = 0; i < N; ++i) { // Ray is already offset above, no need to do it again const SWCSpectrum stepTau(vr->Tau(sw, r, .5f * stepSize, 0.f)); Tr *= Exp(-stepTau); // Possibly terminate raymarching if transmittance is small if (Tr.Filter(sw) < 1e-3f) { const float continueProb = .5f; if (sample.rng->floatValue() > continueProb) break; // TODO - REFACT - remove and add random value from sample Tr /= continueProb; } // Compute single-scattering source term at _p_ *Lv += Tr * vr->Lve(sw, dg); if (nLights > 0) { const SWCSpectrum ss(vr->SigmaS(sw, dg)); if (!ss.Black()) { // Add contribution of _light_ due to scattering at _p_ float pdf; float u1 = samp[sampOffset], u2 = samp[sampOffset + 1], u3 = samp[sampOffset + 2]; BSDF *ibsdf; SWCSpectrum L; if (light->SampleL(scene, sample, r.o, u1, u2, u3, &ibsdf, NULL, &pdf, &L)) { if (Connect(scene, sample, vr, true, false, r.o, ibsdf->dgShading.p, false, &L, NULL, NULL)) { const Vector wo(Normalize(r.o - ibsdf->dgShading.p)); *Lv += Tr * ss * L * ibsdf->F(sw, Vector(ibsdf->dgShading.nn), wo, false) * (vr->P(sw, dg, w, wo) * nLights); } } } } sampOffset += 3; // Advance to sample at _t0_ and update _T_ t0 += step; r.o = ray(t0); dg.p = r.o; } *Lv *= step * length; return light->group; }