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