00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "single.h"
00025 #include "light.h"
00026 #include "paramset.h"
00027
00028 using namespace lux;
00029
00030
00031 void SingleScattering::RequestSamples(Sample *sample,
00032 const Scene *scene) {
00033 tauSampleOffset = sample->Add1D(1);
00034 scatterSampleOffset = sample->Add1D(1);
00035 }
00036 SWCSpectrum SingleScattering::Transmittance(const Scene *scene,
00037 const Ray &ray, const Sample *sample, float *alpha) const {
00038 if (!scene->volumeRegion) return SWCSpectrum(1.f);
00039 float step = sample ? stepSize : 4.f * stepSize;
00040 float offset = sample ? sample->oneD[tauSampleOffset][0] :
00041 lux::random::floatValue();
00042 SWCSpectrum tau = scene->volumeRegion->Tau(ray, step, offset);
00043 return Exp(-tau);
00044 }
00045 SWCSpectrum SingleScattering::Li(const Scene *scene,
00046 const RayDifferential &ray, const Sample *sample,
00047 float *alpha) const {
00048 VolumeRegion *vr = scene->volumeRegion;
00049 float t0, t1;
00050 if (!vr || !vr->IntersectP(ray, &t0, &t1)) return 0.f;
00051
00052 SWCSpectrum Lv(0.);
00053
00054 int N = Ceil2Int((t1-t0) / stepSize);
00055 float step = (t1 - t0) / N;
00056 SWCSpectrum Tr(1.f);
00057 Point p = ray(t0), pPrev;
00058 Vector w = -ray.d;
00059 if (sample)
00060 t0 += sample->oneD[scatterSampleOffset][0] * step;
00061 else
00062 t0 += lux::random::floatValue() * step;
00063
00064 float *samp = (float *)alloca(4 * N * sizeof(float));
00065 LatinHypercube(samp, N, 4);
00066 int sampOffset = 0;
00067 for (int i = 0; i < N; ++i, t0 += step) {
00068
00069 pPrev = p;
00070 p = ray(t0);
00071 SWCSpectrum stepTau = vr->Tau(Ray(pPrev, p - pPrev, 0, 1),
00072 .5f * stepSize, lux::random::floatValue());
00073 Tr *= Exp(-stepTau);
00074
00075 if (Tr.filter() < 1e-3) {
00076 const float continueProb = .5f;
00077 if (lux::random::floatValue() > continueProb) break;
00078 Tr /= continueProb;
00079 }
00080
00081 Lv += Tr * vr->Lve(p, w);
00082 SWCSpectrum ss = vr->sigma_s(p, w);
00083 if (!ss.Black() && scene->lights.size() > 0) {
00084 int nLights = scene->lights.size();
00085 int lightNum =
00086 min(Floor2Int(samp[sampOffset] * nLights),
00087 nLights-1);
00088 Light *light = scene->lights[lightNum];
00089
00090 float pdf;
00091 VisibilityTester vis;
00092 Vector wo;
00093 float u1 = samp[sampOffset+1], u2 = samp[sampOffset+2], u3 = samp[sampOffset+3];
00094 SWCSpectrum L = light->Sample_L(p, u1, u2, u3, &wo, &pdf, &vis);
00095 if (!L.Black() && pdf > 0.f && vis.Unoccluded(scene)) {
00096 SWCSpectrum Ld = L * vis.Transmittance(scene);
00097 Lv += Tr * ss * vr->p(p, w, -wo) *
00098 Ld * float(nLights) / pdf;
00099 }
00100 }
00101 sampOffset += 3;
00102 }
00103 return Lv * step;
00104 }
00105 VolumeIntegrator* SingleScattering::CreateVolumeIntegrator(const ParamSet ¶ms) {
00106 float stepSize = params.FindOneFloat("stepsize", 1.f);
00107 return new SingleScattering(stepSize);
00108 }