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
00026 #include "stdafx.h"
00027 #include "integrators/path.h"
00028 #include "scene.h"
00029 #include "intersection.h"
00030 #include "paramset.h"
00031
00032
00033 void PathIntegrator::RequestSamples(Sampler *sampler, Sample *sample,
00034 const Scene *scene) {
00035 for (int i = 0; i < SAMPLE_DEPTH; ++i) {
00036 lightSampleOffsets[i] = LightSampleOffsets(1, sample);
00037 lightNumOffset[i] = sample->Add1D(1);
00038 bsdfSampleOffsets[i] = BSDFSampleOffsets(1, sample);
00039 pathSampleOffsets[i] = BSDFSampleOffsets(1, sample);
00040 }
00041 }
00042
00043
00044 Spectrum PathIntegrator::Li(const Scene *scene, const Renderer *renderer,
00045 const RayDifferential &r, const Intersection &isect,
00046 const Sample *sample, RNG &rng, MemoryArena &arena) const {
00047
00048 Spectrum pathThroughput = 1., L = 0.;
00049 RayDifferential ray(r);
00050 bool specularBounce = false;
00051 Intersection localIsect;
00052 const Intersection *isectp = &isect;
00053 for (int bounces = 0; ; ++bounces) {
00054
00055 if (bounces == 0 || specularBounce)
00056 L += pathThroughput * isectp->Le(-ray.d);
00057
00058
00059 BSDF *bsdf = isectp->GetBSDF(ray, arena);
00060 const Point &p = bsdf->dgShading.p;
00061 const Normal &n = bsdf->dgShading.nn;
00062 Vector wo = -ray.d;
00063 if (bounces < SAMPLE_DEPTH)
00064 L += pathThroughput *
00065 UniformSampleOneLight(scene, renderer, arena, p, n, wo,
00066 isectp->rayEpsilon, ray.time, bsdf, sample, rng,
00067 lightNumOffset[bounces], &lightSampleOffsets[bounces],
00068 &bsdfSampleOffsets[bounces]);
00069 else
00070 L += pathThroughput *
00071 UniformSampleOneLight(scene, renderer, arena, p, n, wo,
00072 isectp->rayEpsilon, ray.time, bsdf, sample, rng);
00073
00074
00075
00076
00077 BSDFSample outgoingBSDFSample;
00078 if (bounces < SAMPLE_DEPTH)
00079 outgoingBSDFSample = BSDFSample(sample, pathSampleOffsets[bounces],
00080 0);
00081 else
00082 outgoingBSDFSample = BSDFSample(rng);
00083 Vector wi;
00084 float pdf;
00085 BxDFType flags;
00086 Spectrum f = bsdf->Sample_f(wo, &wi, outgoingBSDFSample, &pdf,
00087 BSDF_ALL, &flags);
00088 if (f.IsBlack() || pdf == 0.)
00089 break;
00090 specularBounce = (flags & BSDF_SPECULAR) != 0;
00091 pathThroughput *= f * AbsDot(wi, n) / pdf;
00092 ray = RayDifferential(p, wi, ray, isectp->rayEpsilon);
00093
00094
00095 if (bounces > 3) {
00096 float continueProbability = min(.5f, pathThroughput.y());
00097 if (rng.RandomFloat() > continueProbability)
00098 break;
00099 pathThroughput /= continueProbability;
00100 }
00101 if (bounces == maxDepth)
00102 break;
00103
00104
00105 if (!scene->Intersect(ray, &localIsect)) {
00106 if (specularBounce)
00107 for (uint32_t i = 0; i < scene->lights.size(); ++i)
00108 L += pathThroughput * scene->lights[i]->Le(ray);
00109 break;
00110 }
00111 if (bounces > 1)
00112 pathThroughput *= renderer->Transmittance(scene, ray, NULL, rng, arena);
00113 isectp = &localIsect;
00114 }
00115 return L;
00116 }
00117
00118
00119 PathIntegrator *CreatePathSurfaceIntegrator(const ParamSet ¶ms) {
00120 int maxDepth = params.FindOneInt("maxdepth", 5);
00121 return new PathIntegrator(maxDepth);
00122 }
00123
00124