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/igi.h"
00028 #include "scene.h"
00029 #include "montecarlo.h"
00030 #include "progressreporter.h"
00031 #include "sampler.h"
00032 #include "intersection.h"
00033 #include "paramset.h"
00034 #include "camera.h"
00035
00036
00037 IGIIntegrator::~IGIIntegrator() {
00038 delete[] lightSampleOffsets;
00039 delete[] bsdfSampleOffsets;
00040 }
00041
00042
00043 void IGIIntegrator::RequestSamples(Sampler *sampler, Sample *sample,
00044 const Scene *scene) {
00045
00046 uint32_t nLights = scene->lights.size();
00047 lightSampleOffsets = new LightSampleOffsets[nLights];
00048 bsdfSampleOffsets = new BSDFSampleOffsets[nLights];
00049 for (uint32_t i = 0; i < nLights; ++i) {
00050 const Light *light = scene->lights[i];
00051 int nSamples = light->nSamples;
00052 if (sampler) nSamples = sampler->RoundSize(nSamples);
00053 lightSampleOffsets[i] = LightSampleOffsets(nSamples, sample);
00054 bsdfSampleOffsets[i] = BSDFSampleOffsets(nSamples, sample);
00055 }
00056 vlSetOffset = sample->Add1D(1);
00057
00058 if (sampler) nGatherSamples = sampler->RoundSize(nGatherSamples);
00059 gatherSampleOffset = BSDFSampleOffsets(nGatherSamples, sample);
00060 }
00061
00062
00063 void IGIIntegrator::Preprocess(const Scene *scene, const Camera *camera,
00064 const Renderer *renderer) {
00065 if (scene->lights.size() == 0) return;
00066 MemoryArena arena;
00067 RNG rng;
00068
00069 vector<float> lightNum(nLightPaths * nLightSets);
00070 vector<float> lightSampPos(2 * nLightPaths * nLightSets, 0.f);
00071 vector<float> lightSampComp(nLightPaths * nLightSets, 0.f);
00072 vector<float> lightSampDir(2 * nLightPaths * nLightSets, 0.f);
00073 LDShuffleScrambled1D(nLightPaths, nLightSets, &lightNum[0], rng);
00074 LDShuffleScrambled2D(nLightPaths, nLightSets, &lightSampPos[0], rng);
00075 LDShuffleScrambled1D(nLightPaths, nLightSets, &lightSampComp[0], rng);
00076 LDShuffleScrambled2D(nLightPaths, nLightSets, &lightSampDir[0], rng);
00077
00078
00079 Distribution1D *lightDistribution = ComputeLightSamplingCDF(scene);
00080 for (uint32_t s = 0; s < nLightSets; ++s) {
00081 for (uint32_t i = 0; i < nLightPaths; ++i) {
00082
00083 int sampOffset = s*nLightPaths + i;
00084
00085
00086 float lightPdf;
00087 int ln = lightDistribution->SampleDiscrete(lightNum[sampOffset],
00088 &lightPdf);
00089 Light *light = scene->lights[ln];
00090
00091
00092 RayDifferential ray;
00093 float pdf;
00094 LightSample ls(lightSampPos[2*sampOffset], lightSampPos[2*sampOffset+1],
00095 lightSampComp[sampOffset]);
00096 Normal Nl;
00097 Spectrum alpha = light->Sample_L(scene, ls, lightSampDir[2*sampOffset],
00098 lightSampDir[2*sampOffset+1],
00099 camera->shutterOpen, &ray, &Nl, &pdf);
00100 if (pdf == 0.f || alpha.IsBlack()) continue;
00101 alpha /= pdf * lightPdf;
00102 Intersection isect;
00103 while (scene->Intersect(ray, &isect) && !alpha.IsBlack()) {
00104
00105 alpha *= renderer->Transmittance(scene, RayDifferential(ray), NULL,
00106 rng, arena);
00107 Vector wo = -ray.d;
00108 BSDF *bsdf = isect.GetBSDF(ray, arena);
00109
00110
00111 Spectrum contrib = alpha * bsdf->rho(wo, rng) / M_PI;
00112 virtualLights[s].push_back(VirtualLight(isect.dg.p, isect.dg.nn, contrib,
00113 isect.rayEpsilon));
00114
00115
00116 Vector wi;
00117 float pdf;
00118 BSDFSample bsdfSample(rng);
00119 Spectrum fr = bsdf->Sample_f(wo, &wi, bsdfSample, &pdf);
00120 if (fr.IsBlack() || pdf == 0.f)
00121 break;
00122 Spectrum contribScale = fr * AbsDot(wi, bsdf->dgShading.nn) / pdf;
00123
00124
00125 float rrProb = min(1.f, contribScale.y());
00126 if (rng.RandomFloat() > rrProb)
00127 break;
00128 alpha *= contribScale / rrProb;
00129 ray = RayDifferential(isect.dg.p, wi, ray, isect.rayEpsilon);
00130 }
00131 arena.FreeAll();
00132 }
00133 }
00134 delete lightDistribution;
00135 }
00136
00137
00138 Spectrum IGIIntegrator::Li(const Scene *scene, const Renderer *renderer,
00139 const RayDifferential &ray, const Intersection &isect,
00140 const Sample *sample, RNG &rng, MemoryArena &arena) const {
00141 Spectrum L(0.);
00142 Vector wo = -ray.d;
00143
00144 L += isect.Le(wo);
00145
00146
00147 BSDF *bsdf = isect.GetBSDF(ray, arena);
00148 const Point &p = bsdf->dgShading.p;
00149 const Normal &n = bsdf->dgShading.nn;
00150 L += UniformSampleAllLights(scene, renderer, arena, p, n,
00151 wo, isect.rayEpsilon, ray.time, bsdf, sample, rng,
00152 lightSampleOffsets, bsdfSampleOffsets);
00153
00154 uint32_t lSet = min(uint32_t(sample->oneD[vlSetOffset][0] * nLightSets),
00155 nLightSets-1);
00156 for (uint32_t i = 0; i < virtualLights[lSet].size(); ++i) {
00157 const VirtualLight &vl = virtualLights[lSet][i];
00158
00159 float d2 = DistanceSquared(p, vl.p);
00160 Vector wi = Normalize(vl.p - p);
00161 float G = AbsDot(wi, n) * AbsDot(wi, vl.n) / d2;
00162 G = min(G, gLimit);
00163 Spectrum f = bsdf->f(wo, wi);
00164 if (G == 0.f || f.IsBlack()) continue;
00165 Spectrum Llight = f * G * vl.pathContrib / virtualLights[lSet].size();
00166 RayDifferential connectRay(p, wi, ray, isect.rayEpsilon,
00167 sqrtf(d2) * (1.f - vl.rayEpsilon));
00168 Llight *= renderer->Transmittance(scene, connectRay, NULL, rng, arena);
00169
00170
00171 if (Llight.y() < rrThreshold) {
00172 float continueProbability = .1f;
00173 if (rng.RandomFloat() > continueProbability)
00174 continue;
00175 Llight /= continueProbability;
00176 }
00177
00178
00179 if (!scene->IntersectP(connectRay))
00180 L += Llight;
00181 }
00182 if (ray.depth < maxSpecularDepth) {
00183
00184 int nSamples = (ray.depth == 0) ? nGatherSamples : 1;
00185 for (int i = 0; i < nSamples; ++i) {
00186 Vector wi;
00187 float pdf;
00188 BSDFSample bsdfSample = (ray.depth == 0) ?
00189 BSDFSample(sample, gatherSampleOffset, i) : BSDFSample(rng);
00190 Spectrum f = bsdf->Sample_f(wo, &wi, bsdfSample,
00191 &pdf, BxDFType(BSDF_ALL & ~BSDF_SPECULAR));
00192 if (!f.IsBlack() && pdf > 0.f) {
00193
00194 float maxDist = sqrtf(AbsDot(wi, n) / gLimit);
00195 RayDifferential gatherRay(p, wi, ray, isect.rayEpsilon, maxDist);
00196 Intersection gatherIsect;
00197 Spectrum Li = renderer->Li(scene, gatherRay, sample, rng, arena,
00198 &gatherIsect);
00199 if (Li.IsBlack()) continue;
00200
00201
00202 float Ggather = AbsDot(wi, n) * AbsDot(-wi, gatherIsect.dg.nn) /
00203 DistanceSquared(p, gatherIsect.dg.p);
00204 if (Ggather - gLimit > 0.f && !isinf(Ggather)) {
00205 float gs = (Ggather - gLimit) / Ggather *
00206 AbsDot(-wi, gatherIsect.dg.nn);
00207 L += f * Li * (AbsDot(wi, n) * gs / (nSamples * pdf));
00208 }
00209 }
00210 }
00211 }
00212 if (ray.depth + 1 < maxSpecularDepth) {
00213 Vector wi;
00214
00215 L += SpecularReflect(ray, bsdf, rng, isect, renderer, scene, sample,
00216 arena);
00217 L += SpecularTransmit(ray, bsdf, rng, isect, renderer, scene, sample,
00218 arena);
00219 }
00220 return L;
00221 }
00222
00223
00224 IGIIntegrator *CreateIGISurfaceIntegrator(const ParamSet ¶ms) {
00225 int nLightPaths = params.FindOneInt("nlights", 64);
00226 if (PbrtOptions.quickRender) nLightPaths = max(1, nLightPaths / 4);
00227 int nLightSets = params.FindOneInt("nsets", 4);
00228 float rrThresh = params.FindOneFloat("rrthreshold", .0001f);
00229 int maxDepth = params.FindOneInt("maxdepth", 5);
00230 float glimit = params.FindOneFloat("glimit", 10.f);
00231 int gatherSamples = params.FindOneInt("gathersamples", 16);
00232 return new IGIIntegrator(nLightPaths, nLightSets, rrThresh,
00233 maxDepth, glimit, gatherSamples);
00234 }
00235
00236