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