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