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 "igi.h"
00025 #include "scene.h"
00026 #include "light.h"
00027 #include "camera.h"
00028 #include "mc.h"
00029 #include "reflection/bxdf.h"
00030 #include "dynload.h"
00031 #include "paramset.h"
00032
00033 using namespace lux;
00034
00035 SWCSpectrum VirtualLight::GetSWCSpectrum(const TsPack* tspack) const
00036 {
00037 const float delta = (tspack->swl->w[0] - w[0]) * WAVELENGTH_SAMPLES /
00038 (WAVELENGTH_END - WAVELENGTH_START);
00039 SWCSpectrum result;
00040 if (delta < 0.f) {
00041 result.c[0] = Lerp(-delta, Le.c[0], 0.f);
00042 for (u_int i = 1; i < WAVELENGTH_SAMPLES; ++i)
00043 result.c[i] = Lerp(-delta, Le.c[i], Le.c[i - 1]);
00044 } else {
00045 for (u_int i = 0; i < WAVELENGTH_SAMPLES - 1; ++i)
00046 result.c[i] = Lerp(delta, Le.c[i], Le.c[i + 1]);
00047 result.c[WAVELENGTH_SAMPLES - 1] = Lerp(delta,
00048 Le.c[WAVELENGTH_SAMPLES - 1], 0.f);
00049 }
00050 return result;
00051 }
00052
00053
00054 IGIIntegrator::IGIIntegrator(int nl, int ns, int d, float md)
00055 {
00056 nLightPaths = RoundUpPow2(nl);
00057 nLightSets = RoundUpPow2(ns);
00058 minDist2 = md * md;
00059 maxSpecularDepth = d;
00060 virtualLights.resize(nLightSets);
00061 }
00062 void IGIIntegrator::RequestSamples(Sample *sample, const Scene *scene)
00063 {
00064
00065 u_int nLights = scene->lights.size();
00066 lightSampleOffset = new int[nLights];
00067 bsdfSampleOffset = new int[nLights];
00068 bsdfComponentOffset = new int[nLights];
00069 for (u_int i = 0; i < nLights; ++i) {
00070 int lightSamples = 1;
00071 lightSampleOffset[i] = sample->Add2D(lightSamples);
00072 bsdfSampleOffset[i] = sample->Add2D(lightSamples);
00073 bsdfComponentOffset[i] = sample->Add1D(lightSamples);
00074 }
00075 lightNumOffset = -1;
00076 vlSetOffset = sample->Add1D(1);
00077 }
00078 void IGIIntegrator::Preprocess(const TsPack *tspack, const Scene *scene)
00079 {
00080
00081 BufferOutputConfig config = BUF_FRAMEBUFFER;
00082 BufferType type = BUF_TYPE_PER_PIXEL;
00083 scene->sampler->GetBufferType(&type);
00084 bufferId = scene->camera->film->RequestBuffer(type, config, "eye");
00085
00086 if (scene->lights.size() == 0)
00087 return;
00088
00089 float *lightNum = new float[nLightPaths * nLightSets];
00090 float *lightSamp0 = new float[2 * nLightPaths * nLightSets];
00091 float *lightSamp1 = new float[2 * nLightPaths * nLightSets];
00092 LDShuffleScrambled1D(tspack, nLightPaths, nLightSets, lightNum);
00093 LDShuffleScrambled2D(tspack, nLightPaths, nLightSets, lightSamp0);
00094 LDShuffleScrambled2D(tspack, nLightPaths, nLightSets, lightSamp1);
00095
00096 tspack->swl->Sample(.5f, .5f);
00097 u_int nLights = scene->lights.size();
00098 float *lightPower = new float[nLights];
00099 float *lightCDF = new float[nLights + 1];
00100 for (u_int i = 0; i < nLights; ++i)
00101 lightPower[i] = scene->lights[i]->Power(tspack, scene).Y(tspack);
00102 float totalPower;
00103 ComputeStep1dCDF(lightPower, nLights, &totalPower, lightCDF);
00104 for (u_int s = 0; s < nLightSets; ++s) {
00105 for (u_int i = 0; i < nLightPaths; ++i) {
00106 tspack->swl->Sample(tspack->rng->floatValue(), tspack->rng->floatValue());
00107
00108 int sampOffset = s * nLightPaths + i;
00109
00110 float lightPdf;
00111 int lNum = Floor2Int(SampleStep1d(lightPower, lightCDF,
00112 totalPower, nLights, lightNum[sampOffset],
00113 &lightPdf) * nLights);
00114 lNum = Clamp<int>(lNum, 0, nLights - 1);
00115 Light *light = scene->lights[lNum];
00116
00117 RayDifferential ray;
00118 float pdf;
00119 SWCSpectrum alpha(light->Sample_L(tspack, scene,
00120 lightSamp0[2 * sampOffset],
00121 lightSamp0[2 * sampOffset + 1],
00122 lightSamp1[2 * sampOffset],
00123 lightSamp1[2 * sampOffset + 1],
00124 &ray, &pdf));
00125 if (pdf == 0.f || alpha.Black())
00126 continue;
00127 alpha /= pdf * lightPdf;
00128 Intersection isect;
00129 int nIntersections = 0;
00130 while (scene->Intersect(ray, &isect) &&
00131 !alpha.Black()) {
00132 ++nIntersections;
00133
00134 Vector wo = -ray.d;
00135 BSDF *bsdf = isect.GetBSDF(tspack, ray);
00136
00137 SWCSpectrum Le = alpha * bsdf->rho(tspack, wo) / M_PI;
00138 virtualLights[s].push_back(
00139 VirtualLight(tspack, isect.dg.p,
00140 isect.dg.nn, Le));
00141
00142 Vector wi;
00143 float pdf;
00144 BxDFType flags;
00145 SWCSpectrum fr;
00146 if (!bsdf->Sample_f(tspack, wo, &wi,
00147 tspack->rng->floatValue(),
00148 tspack->rng->floatValue(),
00149 tspack->rng->floatValue(),
00150 &fr, &pdf, BSDF_ALL, &flags))
00151 break;
00152 SWCSpectrum anew = fr * AbsDot(wi, bsdf->dgShading.nn) / pdf;
00153 float r = min(1.f, anew.Filter(tspack));
00154 if (tspack->rng->floatValue() > r)
00155 break;
00156 alpha *= anew / r;
00157 ray = RayDifferential(isect.dg.p, wi);
00158 }
00159 }
00160 }
00161 delete[] lightCDF;
00162 delete[] lightPower;
00163 delete[] lightNum;
00164 delete[] lightSamp0;
00165 delete[] lightSamp1;
00166 }
00167 int IGIIntegrator::Li(const TsPack *tspack, const Scene *scene,
00168 const Sample *sample) const
00169 {
00170 RayDifferential r;
00171 float rayWeight = tspack->camera->GenerateRay(*sample, &r);
00172 if (rayWeight > 0.f) {
00173
00174 ++(sample->imageX);
00175 float wt1 = tspack->camera->GenerateRay(*sample, &r.rx);
00176 --(sample->imageX);
00177 ++(sample->imageY);
00178 float wt2 = tspack->camera->GenerateRay(*sample, &r.ry);
00179 r.hasDifferentials = (wt1 > 0.f) && (wt2 > 0.f);
00180 --(sample->imageY);
00181 }
00182
00183 RayDifferential ray(r);
00184 SWCSpectrum L(0.f), pathThroughput(1.f);
00185 float alpha = 1.f;
00186 for (int depth = 0; ; ++depth) {
00187 Intersection isect;
00188 if (!scene->Intersect(r, &isect)) {
00189
00190 if (depth == 0)
00191 alpha = 0.f;
00192 for (u_int i = 0; i < scene->lights.size(); ++i)
00193 L += pathThroughput * scene->lights[i]->Le(tspack, r);
00194 break;
00195 }
00196 Vector wo = -r.d;
00197
00198 L += pathThroughput * isect.Le(tspack, wo);
00199
00200 BSDF *bsdf = isect.GetBSDF(tspack, r);
00201 const Point &p = bsdf->dgShading.p;
00202 const Normal &n = bsdf->dgShading.nn;
00203 for (u_int i = 0; i < scene->lights.size(); ++i) {
00204 SWCSpectrum Ld(0.f);
00205 float ln = Clamp((i + tspack->rng->floatValue()) / scene->lights.size(), 0.f, 1.f);
00206 UniformSampleOneLight(tspack, scene, p, n, wo, bsdf,
00207 sample, sample->twoD[lightSampleOffset[i]],
00208 &ln,
00209 sample->twoD[bsdfSampleOffset[i]],
00210 sample->oneD[bsdfComponentOffset[i]], &Ld);
00211 L += pathThroughput * Ld / scene->lights.size();
00212 }
00213
00214 u_int lSet = min<u_int>(Floor2Int(sample->oneD[vlSetOffset][0] * nLightSets),
00215 max<u_int>(1, virtualLights.size()) - 1);
00216 for (u_int i = 0; i < virtualLights[lSet].size(); ++i) {
00217 const VirtualLight &vl = virtualLights[lSet][i];
00218
00219
00220 float d2 = DistanceSquared(p, vl.p);
00221 if (d2 < .8f * minDist2)
00222 continue;
00223 float distScale = SmoothStep(.8f * minDist2,
00224 1.2f * minDist2, d2);
00225
00226 Vector wi = Normalize(vl.p - p);
00227 SWCSpectrum f = distScale * bsdf->f(tspack, wi, wo, BxDFType(~BSDF_SPECULAR));
00228 if (f.Black())
00229 continue;
00230 float G = AbsDot(wi, n) * AbsDot(wi, vl.n) / d2;
00231 SWCSpectrum Llight = f * vl.GetSWCSpectrum(tspack) *
00232 (G / virtualLights[lSet].size());
00233 scene->Transmittance(tspack, Ray(p, vl.p - p),
00234 sample, &Llight);
00235 const float rayEpsilon = MachineEpsilon::E(p);
00236 if (!scene->IntersectP(Ray(p, vl.p - p, rayEpsilon,
00237 1.f - rayEpsilon)))
00238 L += pathThroughput * Llight;
00239 }
00240
00241 if (depth >= maxSpecularDepth)
00242 break;
00243 Vector wi;
00244
00245 SWCSpectrum f;
00246 float pdf;
00247 if (!bsdf->Sample_f(tspack, wo, &wi, .5f, .5f, tspack->rng->floatValue(), &f, &pdf, BxDFType(BSDF_SPECULAR | BSDF_REFLECTION | BSDF_TRANSMISSION)))
00248 break;
00249
00250 r = RayDifferential(p, wi);
00251 r.time = ray.time;
00252 pathThroughput *= f * (AbsDot(wi, n) / pdf);
00253 }
00254 const XYZColor color(L.ToXYZ(tspack) * rayWeight);
00255 sample->AddContribution(sample->imageX, sample->imageY, color,
00256 alpha, bufferId, 0);
00257 return 1;
00258 }
00259 SurfaceIntegrator* IGIIntegrator::CreateSurfaceIntegrator(const ParamSet ¶ms)
00260 {
00261 int nLightSets = params.FindOneInt("nsets", 4);
00262 int nLightPaths = params.FindOneInt("nlights", 64);
00263 int maxDepth = params.FindOneInt("maxdepth", 5);
00264 float minDist = params.FindOneFloat("mindist", .1f);
00265 return new IGIIntegrator(nLightPaths, nLightSets, maxDepth, minDist);
00266 }
00267
00268 static DynamicLoader::RegisterSurfaceIntegrator<IGIIntegrator> r("igi");