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 "paramset.h"
00028
00029 using namespace lux;
00030
00031
00032 void PathIntegrator::RequestSamples(Sample *sample, const Scene *scene)
00033 {
00034 if (lightStrategy == SAMPLE_AUTOMATIC) {
00035 if (scene->lights.size() > 5)
00036 lightStrategy = SAMPLE_ONE_UNIFORM;
00037 else
00038 lightStrategy = SAMPLE_ALL_UNIFORM;
00039 }
00040
00041 vector<u_int> structure;
00042 structure.push_back(2);
00043 structure.push_back(1);
00044 structure.push_back(2);
00045 structure.push_back(1);
00046 structure.push_back(2);
00047 structure.push_back(1);
00048 if (rrStrategy != RR_NONE)
00049 structure.push_back(1);
00050 sampleOffset = sample->AddxD(structure, maxDepth + 1);
00051 }
00052
00053 SWCSpectrum PathIntegrator::Li(const Scene *scene,
00054 const RayDifferential &r, const Sample *sample,
00055 float *alpha) const
00056 {
00057 SampleGuard guard(sample->sampler, sample);
00058
00059 RayDifferential ray(r);
00060 SWCSpectrum pathThroughput(scene->volumeIntegrator->Transmittance(scene, ray, sample, alpha));
00061 SWCSpectrum L(scene->volumeIntegrator->Li(scene, ray, sample, alpha));
00062 float V = .1f;
00063 bool specularBounce = true, specular = true;
00064 if (alpha) *alpha = 1.;
00065 XYZColor color(L.ToXYZ());
00066 if (color.y() > 0.f)
00067 sample->AddContribution(sample->imageX, sample->imageY,
00068 color, alpha ? *alpha : 1.f, V);
00069 for (int pathLength = 0; ; ++pathLength) {
00070
00071 Intersection isect;
00072 if (!scene->Intersect(ray, &isect)) {
00073
00074
00075
00076 if (specularBounce) {
00077 SWCSpectrum Le(0.f);
00078 for (u_int i = 0; i < scene->lights.size(); ++i)
00079 Le += scene->lights[i]->Le(ray);
00080 Le *= pathThroughput;
00081 L += Le;
00082 color = Le.ToXYZ();
00083 }
00084
00085 if (pathLength == 0 && alpha && L.Black())
00086 *alpha = 0.;
00087 if (color.y() > 0.f)
00088 sample->AddContribution(sample->imageX, sample->imageY,
00089 color, alpha ? *alpha : 1.f, V);
00090 break;
00091 }
00092 if (pathLength == 0) {
00093 r.maxt = ray.maxt;
00094 }
00095 else
00096 pathThroughput *= scene->Transmittance(ray);
00097
00098 Vector wo = -ray.d;
00099 if (specularBounce) {
00100 SWCSpectrum Le(isect.Le(wo));
00101 Le *= pathThroughput;
00102 L += Le;
00103 color = Le.ToXYZ();
00104 if (color.y() > 0.f)
00105 sample->AddContribution(sample->imageX, sample->imageY,
00106 color, alpha ? *alpha : 1.f, V);
00107 }
00108 if (pathLength == maxDepth)
00109 break;
00110
00111 float *data = sample->sampler->GetLazyValues(const_cast<Sample *>(sample), sampleOffset, pathLength);
00112 BSDF *bsdf = isect.GetBSDF(ray, fabsf(2.f * data[5] - 1.f));
00113
00114 const Point &p = bsdf->dgShading.p;
00115 const Normal &n = bsdf->dgShading.nn;
00116
00117 SWCSpectrum Ll;
00118 switch (lightStrategy) {
00119 case SAMPLE_ALL_UNIFORM:
00120 Ll = UniformSampleAllLights(scene, p, n,
00121 wo, bsdf, sample,
00122 data, data + 2, data + 3, data + 5);
00123 break;
00124 case SAMPLE_ONE_UNIFORM:
00125 Ll = UniformSampleOneLight(scene, p, n,
00126 wo, bsdf, sample,
00127 data, data + 2, data + 3, data + 5);
00128 break;
00129 default:
00130 Ll = 0.f;
00131 }
00132 Ll *= pathThroughput;
00133 L += Ll;
00134 color = Ll.ToXYZ();
00135 if (color.y() > 0.f)
00136 sample->AddContribution(sample->imageX, sample->imageY,
00137 color, alpha ? *alpha : 1.f, V);
00138
00139
00140 Vector wi;
00141 float pdf;
00142 BxDFType flags;
00143 SWCSpectrum f = bsdf->Sample_f(wo, &wi, data[6], data[7], data[8],
00144 &pdf, BSDF_ALL, &flags);
00145 if (pdf == .0f || f.Black())
00146 break;
00147
00148 const float dp = AbsDot(wi, n) / pdf;
00149
00150
00151 if (pathLength > 3) {
00152 if (rrStrategy == RR_EFFICIENCY) {
00153 const float q = min<float>(1.f, f.filter() * dp);
00154 if (q < data[9])
00155 break;
00156
00157 pathThroughput /= q;
00158 } else if (rrStrategy == RR_PROBABILITY) {
00159 if (continueProbability < data[9])
00160 break;
00161
00162 pathThroughput /= continueProbability;
00163 }
00164 }
00165
00166 specularBounce = (flags & BSDF_SPECULAR) != 0;
00167 specular = specular && specularBounce;
00168 pathThroughput *= f;
00169 pathThroughput *= dp;
00170 if (!specular)
00171 V += dp;
00172
00173 ray = RayDifferential(p, wi);
00174 }
00175 return L;
00176 }
00177 SurfaceIntegrator* PathIntegrator::CreateSurfaceIntegrator(const ParamSet ¶ms)
00178 {
00179
00180 int maxDepth = params.FindOneInt("maxdepth", 16);
00181 float RRcontinueProb = params.FindOneFloat("rrcontinueprob", .65f);
00182 LightStrategy estrategy;
00183 string st = params.FindOneString("strategy", "auto");
00184 if (st == "one") estrategy = SAMPLE_ONE_UNIFORM;
00185 else if (st == "all") estrategy = SAMPLE_ALL_UNIFORM;
00186 else if (st == "auto") estrategy = SAMPLE_AUTOMATIC;
00187 else {
00188 std::stringstream ss;
00189 ss<<"Strategy '"<<st<<"' for direct lighting unknown. Using \"auto\".";
00190 luxError(LUX_BADTOKEN,LUX_WARNING,ss.str().c_str());
00191 estrategy = SAMPLE_AUTOMATIC;
00192 }
00193 RRStrategy rstrategy;
00194 string rst = params.FindOneString("rrstrategy", "efficiency");
00195 if (rst == "efficiency") rstrategy = RR_EFFICIENCY;
00196 else if (rst == "probability") rstrategy = RR_PROBABILITY;
00197 else if (rst == "none") rstrategy = RR_NONE;
00198 else {
00199 std::stringstream ss;
00200 ss<<"Strategy '"<<st<<"' for russian roulette path termination unknown. Using \"efficiency\".";
00201 luxError(LUX_BADTOKEN,LUX_WARNING,ss.str().c_str());
00202 rstrategy = RR_EFFICIENCY;
00203 }
00204
00205 return new PathIntegrator(estrategy, rstrategy, maxDepth, RRcontinueProb);
00206 }
00207