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
00029 enum LightStrategy { SAMPLE_ALL_UNIFORM, SAMPLE_ONE_UNIFORM,
00030 SAMPLE_ONE_WEIGHTED
00031 };
00032 class DirectLighting : public SurfaceIntegrator {
00033 public:
00034
00035 DirectLighting(LightStrategy ls, int md);
00036 ~DirectLighting();
00037 Spectrum Li(const Scene *scene, const RayDifferential &ray, const Sample *sample,
00038 float *alpha) const;
00039 void RequestSamples(Sample *sample, const Scene *scene) {
00040 if (strategy == SAMPLE_ALL_UNIFORM) {
00041
00042 u_int nLights = scene->lights.size();
00043 lightSampleOffset = new int[nLights];
00044 bsdfSampleOffset = new int[nLights];
00045 bsdfComponentOffset = new int[nLights];
00046 for (u_int i = 0; i < nLights; ++i) {
00047 const Light *light = scene->lights[i];
00048 int lightSamples =
00049 scene->sampler->RoundSize(light->nSamples);
00050 lightSampleOffset[i] = sample->Add2D(lightSamples);
00051 bsdfSampleOffset[i] = sample->Add2D(lightSamples);
00052 bsdfComponentOffset[i] = sample->Add1D(lightSamples);
00053 }
00054 lightNumOffset = -1;
00055 }
00056 else {
00057
00058 lightSampleOffset = new int[1];
00059 lightSampleOffset[0] = sample->Add2D(1);
00060 lightNumOffset = sample->Add1D(1);
00061 bsdfSampleOffset = new int[1];
00062 bsdfSampleOffset[0] = sample->Add2D(1);
00063 bsdfComponentOffset = new int[1];
00064 bsdfComponentOffset[0] = sample->Add1D(1);
00065 }
00066 }
00067 private:
00068
00069 LightStrategy strategy;
00070 mutable int rayDepth;
00071 int maxDepth;
00072
00073 int *lightSampleOffset, lightNumOffset;
00074 int *bsdfSampleOffset, *bsdfComponentOffset;
00075 mutable float *avgY, *avgYsample, *cdf;
00076 mutable float overallAvgY;
00077 };
00078
00079 DirectLighting::~DirectLighting() {
00080 delete[] avgY;
00081 delete[] avgYsample;
00082 delete[] cdf;
00083 }
00084 DirectLighting::DirectLighting(LightStrategy st, int md) {
00085 maxDepth = md;
00086 rayDepth = 0;
00087 strategy = st;
00088 avgY = avgYsample = cdf = NULL;
00089 overallAvgY = 0.;
00090 }
00091 Spectrum DirectLighting::Li(const Scene *scene,
00092 const RayDifferential &ray, const Sample *sample,
00093 float *alpha) const {
00094 Intersection isect;
00095 Spectrum L(0.);
00096 if (scene->Intersect(ray, &isect)) {
00097 if (alpha) *alpha = 1.;
00098
00099 BSDF *bsdf = isect.GetBSDF(ray);
00100 Vector wo = -ray.d;
00101 const Point &p = bsdf->dgShading.p;
00102 const Normal &n = bsdf->dgShading.nn;
00103
00104 L += isect.Le(wo);
00105
00106 if (scene->lights.size() > 0) {
00107
00108 switch (strategy) {
00109 case SAMPLE_ALL_UNIFORM:
00110 L += UniformSampleAllLights(scene, p, n, wo, bsdf,
00111 sample, lightSampleOffset, bsdfSampleOffset,
00112 bsdfComponentOffset);
00113 break;
00114 case SAMPLE_ONE_UNIFORM:
00115 L += UniformSampleOneLight(scene, p, n, wo, bsdf,
00116 sample, lightSampleOffset[0], lightNumOffset,
00117 bsdfSampleOffset[0], bsdfComponentOffset[0]);
00118 break;
00119 case SAMPLE_ONE_WEIGHTED:
00120 L += WeightedSampleOneLight(scene, p, n, wo, bsdf,
00121 sample, lightSampleOffset[0], lightNumOffset,
00122 bsdfSampleOffset[0], bsdfComponentOffset[0], avgY,
00123 avgYsample, cdf, overallAvgY);
00124 break;
00125 }
00126 }
00127 if (rayDepth++ < maxDepth) {
00128 Vector wi;
00129
00130 Spectrum f = bsdf->Sample_f(wo, &wi,
00131 BxDFType(BSDF_REFLECTION | BSDF_SPECULAR));
00132 if (!f.Black()) {
00133
00134 RayDifferential rd(p, wi);
00135 rd.hasDifferentials = true;
00136 rd.rx.o = p + isect.dg.dpdx;
00137 rd.ry.o = p + isect.dg.dpdy;
00138
00139 Normal dndx = bsdf->dgShading.dndu * bsdf->dgShading.dudx +
00140 bsdf->dgShading.dndv * bsdf->dgShading.dvdx;
00141 Normal dndy = bsdf->dgShading.dndu * bsdf->dgShading.dudy +
00142 bsdf->dgShading.dndv * bsdf->dgShading.dvdy;
00143 Vector dwodx = -ray.rx.d - wo, dwody = -ray.ry.d - wo;
00144 float dDNdx = Dot(dwodx, n) + Dot(wo, dndx);
00145 float dDNdy = Dot(dwody, n) + Dot(wo, dndy);
00146 rd.rx.d = wi -
00147 dwodx + 2 * Vector(Dot(wo, n) * dndx +
00148 dDNdx * n);
00149 rd.ry.d = wi -
00150 dwody + 2 * Vector(Dot(wo, n) * dndy +
00151 dDNdy * n);
00152 L += scene->Li(rd, sample) * f * AbsDot(wi, n);
00153 }
00154 f = bsdf->Sample_f(wo, &wi,
00155 BxDFType(BSDF_TRANSMISSION | BSDF_SPECULAR));
00156 if (!f.Black()) {
00157
00158 RayDifferential rd(p, wi);
00159 rd.hasDifferentials = true;
00160 rd.rx.o = p + isect.dg.dpdx;
00161 rd.ry.o = p + isect.dg.dpdy;
00162
00163 float eta = bsdf->eta;
00164 Vector w = -wo;
00165 if (Dot(wo, n) < 0) eta = 1.f / eta;
00166
00167 Normal dndx = bsdf->dgShading.dndu * bsdf->dgShading.dudx + bsdf->dgShading.dndv * bsdf->dgShading.dvdx;
00168 Normal dndy = bsdf->dgShading.dndu * bsdf->dgShading.dudy + bsdf->dgShading.dndv * bsdf->dgShading.dvdy;
00169
00170 Vector dwodx = -ray.rx.d - wo, dwody = -ray.ry.d - wo;
00171 float dDNdx = Dot(dwodx, n) + Dot(wo, dndx);
00172 float dDNdy = Dot(dwody, n) + Dot(wo, dndy);
00173
00174 float mu = eta * Dot(w, n) - Dot(wi, n);
00175 float dmudx = (eta - (eta*eta*Dot(w,n))/Dot(wi, n)) * dDNdx;
00176 float dmudy = (eta - (eta*eta*Dot(w,n))/Dot(wi, n)) * dDNdy;
00177
00178 rd.rx.d = wi + eta * dwodx - Vector(mu * dndx + dmudx * n);
00179 rd.ry.d = wi + eta * dwody - Vector(mu * dndy + dmudy * n);
00180 L += scene->Li(rd, sample) * f * AbsDot(wi, n);
00181 }
00182 }
00183 --rayDepth;
00184 }
00185 else {
00186
00187 if (alpha) *alpha = 0.;
00188 for (u_int i = 0; i < scene->lights.size(); ++i)
00189 L += scene->lights[i]->Le(ray);
00190 if (alpha && !L.Black()) *alpha = 1.;
00191 return L;
00192 }
00193 return L;
00194 }
00195 extern "C" DLLEXPORT SurfaceIntegrator *CreateSurfaceIntegrator(const ParamSet ¶ms) {
00196 int maxDepth = params.FindOneInt("maxdepth", 5);
00197 LightStrategy strategy;
00198 string st = params.FindOneString("strategy", "all");
00199 if (st == "one") strategy = SAMPLE_ONE_UNIFORM;
00200 else if (st == "all") strategy = SAMPLE_ALL_UNIFORM;
00201 else if (st == "weighted") strategy = SAMPLE_ONE_WEIGHTED;
00202 else {
00203 Warning("Strategy \"%s\" for direct lighting unknown. "
00204 "Using \"all\".", st.c_str());
00205 strategy = SAMPLE_ALL_UNIFORM;
00206 }
00207 return new DirectLighting(strategy, maxDepth);
00208 }