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 "path2.h"
00025 #include "bxdf.h"
00026 #include "light.h"
00027 #include "camera.h"
00028 #include "paramset.h"
00029
00030 using namespace lux;
00031
00032
00033 void Path2Integrator::RequestSamples(Sample *sample, const Scene *scene)
00034 {
00035 if (lightStrategy == SAMPLE_AUTOMATIC) {
00036 if (scene->lights.size() > 5)
00037 lightStrategy = SAMPLE_ONE_UNIFORM;
00038 else
00039 lightStrategy = SAMPLE_ALL_UNIFORM;
00040 }
00041
00042 vector<u_int> structure;
00043 structure.push_back(2);
00044 structure.push_back(1);
00045 structure.push_back(2);
00046 structure.push_back(1);
00047 structure.push_back(2);
00048 structure.push_back(1);
00049 if (rrStrategy != RR_NONE)
00050 structure.push_back(1);
00051 sampleOffset = sample->AddxD(structure, maxDepth + 1);
00052 }
00053
00054 SWCSpectrum Path2Integrator::Li(const Scene *scene,
00055 const RayDifferential &r, const Sample *sample,
00056 float *alpha) const
00057 {
00058 SampleGuard guard(sample->sampler, sample);
00059
00060 RayDifferential ray(r);
00061 Point lenP;
00062 float lenPdf;
00063 vector<SWCSpectrum> pathThroughput(maxDepth + 1), L(maxDepth + 1);
00064 vector<float> imageX(maxDepth + 1), imageY(maxDepth + 1);
00065 vector<float> weight(maxDepth + 1);
00066 pathThroughput[0] = scene->volumeIntegrator->Transmittance(scene, ray, sample, alpha);
00067 L[0] = scene->volumeIntegrator->Li(scene, ray, sample, alpha);
00068 imageX[0] = sample->imageX;
00069 imageY[0] = sample->imageY;
00070 scene->camera->SamplePosition(sample->lensU, sample->lensV, &lenP, &lenPdf);
00071 RayDifferential ray_gen;
00072 Sample &sample_gen = const_cast<Sample &>(*sample);
00073 bool specularBounce = true, specular0 = false;
00074 if (alpha) *alpha = 1.;
00075 int pathLength;
00076 float totalWeight = 1.f;
00077 for (pathLength = 0; ; ++pathLength) {
00078
00079 Intersection isect;
00080 if (!scene->Intersect(ray, &isect)) {
00081
00082
00083
00084 if (specularBounce) {
00085 SWCSpectrum Le(0.f);
00086 for (u_int i = 0; i < scene->lights.size(); ++i)
00087 Le += scene->lights[i]->Le(ray);
00088 Le *= pathThroughput[0];
00089 L[0] += Le;
00090 }
00091
00092 if (pathLength == 0 && alpha && L[0].Black())
00093 *alpha = 0.;
00094 break;
00095 }
00096 if (pathLength == 0) {
00097 r.maxt = ray.maxt;
00098 } else {
00099 SWCSpectrum T(scene->Transmittance(ray));
00100 for (int i = 0; i < pathLength; ++i) {
00101 pathThroughput[i] *= T;
00102 }
00103 }
00104
00105 Vector wo = -ray.d;
00106 if (specularBounce) {
00107 SWCSpectrum Le(isect.Le(wo));
00108 L[0] += pathThroughput[0] * Le;
00109 for (int i = 1; i < pathLength; ++i)
00110 L[i] += pathThroughput[i] * Le;
00111 }
00112 if (pathLength == maxDepth)
00113 break;
00114
00115 float *data = sample->sampler->GetLazyValues(const_cast<Sample *>(sample), sampleOffset, pathLength);
00116 BSDF *bsdf = isect.GetBSDF(ray, fabsf(2.f * data[5] - 1.f));
00117
00118 const Point &p = bsdf->dgShading.p;
00119 const Normal &n = bsdf->dgShading.nn;
00120
00121 SWCSpectrum Ll;
00122 switch (lightStrategy) {
00123 case SAMPLE_ALL_UNIFORM:
00124 Ll = UniformSampleAllLights(scene, p, n,
00125 wo, bsdf, sample,
00126 data, data + 2, data + 3, data + 5);
00127 break;
00128 case SAMPLE_ONE_UNIFORM:
00129 Ll = UniformSampleOneLight(scene, p, n,
00130 wo, bsdf, sample,
00131 data, data + 2, data + 3, data + 5);
00132 break;
00133 default:
00134 Ll = 0.f;
00135 }
00136
00137 L[0] += pathThroughput[0] * Ll;
00138 for (int i = 1; i < pathLength; ++i)
00139 L[i] += pathThroughput[i] * Ll;
00140
00141
00142 Vector wi;
00143 float pdf;
00144 BxDFType flags;
00145 SWCSpectrum f = bsdf->Sample_f(wo, &wi, data[6], data[7], data[8],
00146 &pdf, BSDF_ALL, &flags);
00147 if (pdf == .0f || f.Black())
00148 break;
00149 specularBounce = (flags & BSDF_SPECULAR) != 0;
00150 float cos = AbsDot(wi, n);
00151 float factor = cos / pdf;
00152
00153
00154 if (pathLength > 3) {
00155 if (rrStrategy == RR_EFFICIENCY) {
00156 const float q = min<float>(1.f, f.filter() * factor);
00157 if (q < data[9])
00158 break;
00159
00160 for (int i = 0; i < pathLength; ++i)
00161 pathThroughput[i] /= q;
00162 } else if (rrStrategy == RR_PROBABILITY) {
00163 if (continueProbability < data[9])
00164 break;
00165
00166 for (int i = 0; i < pathLength; ++i)
00167 pathThroughput[i] /= continueProbability;
00168 }
00169 }
00170
00171 pathThroughput[0] *= f;
00172 pathThroughput[0] *= factor;
00173 for (int i = 1; i < pathLength; ++i) {
00174 pathThroughput[i] *= f;
00175 pathThroughput[i] *= factor;
00176 }
00177 if (pathLength == 0) {
00178 weight[0] = scene->camera->GetConnectingFactor(lenP, p, wo, n);
00179 specular0 = specularBounce;
00180 if (specular0) {
00181 totalWeight = 0.f;
00182 weight[0] = 1.f;
00183 }
00184 }
00185 if (pathLength > 0) {
00186 if (scene->camera->IsVisibleFromEyes(scene, lenP, p, &sample_gen, &ray_gen)) {
00187 wo = -ray_gen.d;
00188 bsdf = isect.GetBSDF(ray_gen, fabsf(2.f * data[5] - 1.f));
00189 weight[pathLength] = scene->camera->GetConnectingFactor(lenP, bsdf->dgShading.p, wo, bsdf->dgShading.nn);
00190 pathThroughput[pathLength] = scene->Transmittance(ray_gen) * (weight[pathLength] / weight[0]);
00191 imageX[pathLength] = sample_gen.imageX;
00192 imageY[pathLength] = sample_gen.imageY;
00193
00194
00195 SWCSpectrum Lx;
00196 switch (lightStrategy) {
00197 case SAMPLE_ALL_UNIFORM:
00198 Lx = UniformSampleAllLights(scene, p, n,
00199 wo, bsdf, sample,
00200 data, data + 2, data + 3, data + 5);
00201 break;
00202 case SAMPLE_ONE_UNIFORM:
00203 Lx = UniformSampleOneLight(scene, bsdf->dgShading.p, bsdf->dgShading.nn,
00204 wo, bsdf, sample,
00205 data, data + 2, data + 3, data + 5);
00206 break;
00207 default:
00208 Lx = 0.f;
00209 }
00210 L[pathLength] += pathThroughput[pathLength] * Lx;
00211
00212 pdf = bsdf->Pdf(wo, wi);
00213 if (pdf > 0.f) {
00214 f = bsdf->f(wo, wi);
00215 if (!f.Black())
00216 pathThroughput[pathLength] *= f * (cos / pdf);
00217 else {
00218 pathThroughput[pathLength] = 0.f;
00219 weight[pathLength] = 0.f;
00220 }
00221 } else {
00222 pathThroughput[pathLength] = 0.f;
00223 weight[pathLength] = 0.f;
00224 }
00225 }
00226 totalWeight += weight[pathLength] / weight[0];
00227 }
00228
00229
00230
00231 ray = RayDifferential(p, wi);
00232 sample_gen.imageX = imageX[0];
00233 sample_gen.imageY = imageY[0];
00234 }
00235 for (int i = 0; i <= pathLength; ++i) {
00236 XYZColor color = L[i].ToXYZ();
00237 if (i || !specular0)
00238 color /= totalWeight;
00239 if (isinf(color.y()))
00240 continue;
00241 if ((i == 0 || weight[i] > 0.f) && color.y() >= -1e-5f)
00242 sample->AddContribution(imageX[i], imageY[i],
00243 color, alpha ? *alpha : 1.f);
00244 }
00245 return totalWeight;
00246 }
00247 SurfaceIntegrator* Path2Integrator::CreateSurfaceIntegrator(const ParamSet ¶ms)
00248 {
00249
00250 int maxDepth = params.FindOneInt("maxdepth", 16);
00251 float RRcontinueProb = params.FindOneFloat("rrcontinueprob", .65f);
00252 LightStrategy estrategy;
00253 string st = params.FindOneString("strategy", "auto");
00254 if (st == "one") estrategy = SAMPLE_ONE_UNIFORM;
00255 else if (st == "all") estrategy = SAMPLE_ALL_UNIFORM;
00256 else if (st == "auto") estrategy = SAMPLE_AUTOMATIC;
00257 else {
00258 std::stringstream ss;
00259 ss<<"Strategy '"<<st<<"' for direct lighting unknown. Using \"auto\".";
00260 luxError(LUX_BADTOKEN,LUX_WARNING,ss.str().c_str());
00261 estrategy = SAMPLE_AUTOMATIC;
00262 }
00263 RRStrategy rstrategy;
00264 string rst = params.FindOneString("rrstrategy", "efficiency");
00265 if (rst == "efficiency") rstrategy = RR_EFFICIENCY;
00266 else if (rst == "probability") rstrategy = RR_PROBABILITY;
00267 else if (rst == "none") rstrategy = RR_NONE;
00268 else {
00269 std::stringstream ss;
00270 ss<<"Strategy '"<<st<<"' for russian roulette path termination unknown. Using \"efficiency\".";
00271 luxError(LUX_BADTOKEN,LUX_WARNING,ss.str().c_str());
00272 rstrategy = RR_EFFICIENCY;
00273 }
00274
00275 return new Path2Integrator(estrategy, rstrategy, maxDepth, RRcontinueProb);
00276
00277 }
00278