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 "bidirectional.h"
00025
00026 using namespace lux;
00027
00028
00029 BidirIntegrator* BidirIntegrator::clone() const
00030 {
00031 return new BidirIntegrator(*this);
00032 }
00033
00034 void BidirIntegrator::RequestSamples(Sample *sample, const Scene *scene) {
00035 for (int i = 0; i < MAX_VERTS; ++i) {
00036 eyeBSDFOffset[i] = sample->Add2D(1);
00037 eyeBSDFCompOffset[i] = sample->Add1D(1);
00038 lightBSDFOffset[i] = sample->Add2D(1);
00039 lightBSDFCompOffset[i] = sample->Add1D(1);
00040 directLightOffset[i] = sample->Add2D(1);
00041 directLightNumOffset[i] = sample->Add1D(1);
00042 directBSDFOffset[i] = sample->Add2D(1);
00043 directBSDFCompOffset[i] = sample->Add1D(1);
00044 }
00045 lightNumOffset = sample->Add1D(1);
00046 lightPosOffset = sample->Add2D(1);
00047 lightDirOffset = sample->Add2D(1);
00048 }
00049 Spectrum BidirIntegrator::Li(const Scene *scene,
00050 const RayDifferential &ray,
00051 const Sample *sample, float *alpha) const {
00052 Spectrum L(0.);
00053
00054 BidirVertex eyePath[MAX_VERTS], lightPath[MAX_VERTS];
00055 int nEye = generatePath(scene, ray, sample, eyeBSDFOffset,
00056 eyeBSDFCompOffset, eyePath, MAX_VERTS);
00057 if (nEye == 0) {
00058 *alpha = 0.;
00059 return L;
00060 }
00061 *alpha = 1;
00062
00063 int lightNum = Floor2Int(sample->oneD[lightNumOffset][0] *
00064 scene->lights.size());
00065 lightNum = min(lightNum, (int)scene->lights.size() - 1);
00066 Light *light = scene->lights[lightNum];
00067 float lightWeight = float(scene->lights.size());
00068
00069 Ray lightRay;
00070 float lightPdf;
00071 float u[4];
00072 u[0] = sample->twoD[lightPosOffset][0];
00073 u[1] = sample->twoD[lightPosOffset][1];
00074 u[2] = sample->twoD[lightDirOffset][0];
00075 u[3] = sample->twoD[lightDirOffset][1];
00076 Spectrum Le = light->Sample_L(scene, u[0], u[1], u[2], u[3],
00077 &lightRay, &lightPdf);
00078 if (lightPdf == 0.) return 0.f;
00079 Le = lightWeight / lightPdf;
00080 int nLight = generatePath(scene, lightRay, sample, lightBSDFOffset,
00081 lightBSDFCompOffset, lightPath, MAX_VERTS);
00082
00083 Spectrum directWt(1.0);
00084 for (int i = 1; i <= nEye; ++i) {
00085
00086 directWt /= eyePath[i-1].rrWeight;
00087 L += directWt *
00088 UniformSampleOneLight(scene, eyePath[i-1].p, eyePath[i-1].ng, eyePath[i-1].wi,
00089 eyePath[i-1].bsdf, sample, directLightOffset[i-1], directLightNumOffset[i-1],
00090 directBSDFOffset[i-1], directBSDFCompOffset[i-1]) /
00091 weightPath(eyePath, i, lightPath, 0);
00092 directWt *= eyePath[i-1].bsdf->f(eyePath[i-1].wi, eyePath[i-1].wo) *
00093 AbsDot(eyePath[i-1].wo, eyePath[i-1].ng) /
00094 eyePath[i-1].bsdfWeight;
00095 for (int j = 1; j <= nLight; ++j)
00096 L += Le * evalPath(scene, eyePath, i, lightPath, j) /
00097 weightPath(eyePath, i, lightPath, j);
00098 }
00099 return L;
00100 }
00101 int BidirIntegrator::generatePath(const Scene *scene, const Ray &r,
00102 const Sample *sample, const int *bsdfOffset,
00103 const int *bsdfCompOffset,
00104 BidirVertex *vertices, int maxVerts) const {
00105 int nVerts = 0;
00106 RayDifferential ray(r.o, r.d);
00107 while (nVerts < maxVerts) {
00108
00109 Intersection isect;
00110 if (!scene->Intersect(ray, &isect))
00111 break;
00112 BidirVertex &v = vertices[nVerts];
00113 MemoryArena arena;
00114 v.bsdf = isect.GetBSDF( ray);
00115 v.p = isect.dg.p;
00116 v.ng = isect.dg.nn;
00117 v.ns = v.bsdf->dgShading.nn;
00118 v.wi = -ray.d;
00119 ++nVerts;
00120
00121 if (nVerts > 2) {
00122 float rrProb = .2f;
00123 if (lux::random::floatValue() > rrProb)
00124 break;
00125 v.rrWeight = 1.f / rrProb;
00126 }
00127
00128 float u1 = sample->twoD[bsdfOffset[nVerts-1]][0];
00129 float u2 = sample->twoD[bsdfOffset[nVerts-1]][1];
00130 float u3 = sample->oneD[bsdfCompOffset[nVerts-1]][0];
00131 Spectrum fr = v.bsdf->Sample_f(v.wi, &v.wo, u1, u2, u3,
00132 &v.bsdfWeight, BSDF_ALL, &v.flags);
00133 if (fr.Black() && v.bsdfWeight == 0.f)
00134 break;
00135 ray = RayDifferential(v.p, v.wo);
00136 }
00137
00138 for (int i = 0; i < nVerts-1; ++i)
00139 vertices[i].dAWeight = vertices[i].bsdfWeight *
00140 AbsDot(-vertices[i].wo, vertices[i+1].ng) /
00141 DistanceSquared(vertices[i].p, vertices[i+1].p);
00142 return nVerts;
00143 }
00144
00145 float BidirIntegrator::weightPath(BidirVertex *eye, int nEye,
00146 BidirVertex *light, int nLight) const {
00147 return float(nEye + nLight);
00148 }
00149 Spectrum BidirIntegrator::evalPath(const Scene *scene, BidirVertex *eye, int nEye,
00150 BidirVertex *light, int nLight) const {
00151 Spectrum L(1.);
00152 for (int i = 0; i < nEye-1; ++i)
00153 L *= eye[i].bsdf->f(eye[i].wi, eye[i].wo) *
00154 AbsDot(eye[i].wo, eye[i].ng) /
00155 (eye[i].bsdfWeight * eye[i].rrWeight);
00156 Vector w = light[nLight-1].p - eye[nEye-1].p;
00157 L *= eye[nEye-1].bsdf->f(eye[nEye-1].wi, w) *
00158 G(eye[nEye-1], light[nLight-1]) *
00159 light[nLight-1].bsdf->f(-w, light[nLight-1].wi) /
00160 (eye[nEye-1].rrWeight * light[nLight-1].rrWeight);
00161 for (int i = nLight-2; i >= 0; --i)
00162 L *= light[i].bsdf->f(light[i].wi, light[i].wo) *
00163 AbsDot(light[i].wo, light[i].ng) /
00164 (light[i].bsdfWeight * light[i].rrWeight);
00165 if (L.Black())
00166 return L;
00167 if (!visible(scene, eye[nEye-1].p, light[nLight-1].p))
00168 return 0.;
00169 return L;
00170 }
00171 float BidirIntegrator::G(const BidirVertex &v0, const BidirVertex &v1) {
00172 Vector w = Normalize(v1.p - v0.p);
00173 return AbsDot(v0.ng, w) * AbsDot(v1.ng, -w) /
00174 DistanceSquared(v0.p, v1.p);
00175 }
00176 bool BidirIntegrator::visible(const Scene *scene, const Point &P0,
00177 const Point &P1) {
00178 Ray ray(P0, P1-P0, RAY_EPSILON, 1.f - RAY_EPSILON);
00179 return !scene->IntersectP(ray);
00180 }
00181 SurfaceIntegrator* BidirIntegrator::CreateSurfaceIntegrator(const ParamSet ¶ms) {
00182 return new BidirIntegrator;
00183 }