Fix a nasty typo in ERPT.
Jeanphi
1 /***************************************************************************
2 * Copyright (C) 1998-2009 by authors (see AUTHORS.txt ) *
4 * This file is part of LuxRender. *
6 * Lux Renderer is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 3 of the License, or *
9 * (at your option) any later version. *
11 * Lux Renderer is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
19 * This project is based on PBRT ; see http://www.pbrt.org *
20 * Lux Renderer website : http://www.luxrender.net *
21 ***************************************************************************/
23 // initial metropolis light transport sample integrator
26 // TODO: add scaling of output image samples
36 #define SAMPLE_FLOATS 6
38 // mutate a value in the range [0-1]
39 static float mutate(const float x, const float randomValue)
41 static const float s1 = 1.f / 1024.f, s2 = 1.f / 16.f;
42 float dx = s2 * powf(s1 / s2, fabsf(2.f * randomValue - 1.f));
43 if (randomValue < 0.5f) {
45 return (x1 > 1.f) ? x1 - 1.f : x1;
48 return (x1 < 0.f) ? x1 + 1.f : x1;
52 // mutate a value in the range [min-max]
53 static float mutateScaled(const float x, const float randomValue, const float mini, const float maxi, const float range)
55 float dx = range * expf(-logf(2.f * range) * fabsf(2.f * randomValue - 1.f));
56 if (randomValue < 0.5f) {
58 return (x1 > maxi) ? x1 - maxi + mini : x1;
61 return (x1 < mini) ? x1 - mini + maxi : x1;
65 // Metropolis method definitions
66 ERPTSampler::ERPTSampler(u_int totMutations, float rng,
68 Sampler(sampler->xPixelStart, sampler->xPixelEnd,
69 sampler->yPixelStart, sampler->yPixelEnd, sampler->samplesPerPixel),
70 normalSamples(0), totalSamples(0), totalTimes(0), totalMutations(totMutations),
71 range(rng), baseSampler(sampler),
72 baseImage(NULL), sampleImage(NULL), currentImage(NULL),
73 baseTimeImage(NULL), timeImage(NULL), currentTimeImage(NULL), offset(NULL),
74 numChains(0), chain(0), mutation(~0U), stamp(0),
75 baseLY(0.f), quantum(0.f), weight(0.f), LY(0.f), alpha(0.f),
76 totalLY(0.), sampleCount(0.)
80 ERPTSampler::~ERPTSampler() {
81 FreeAligned(sampleImage);
82 FreeAligned(baseImage);
83 FreeAligned(timeImage);
84 FreeAligned(baseTimeImage);
89 ERPTSampler* ERPTSampler::clone() const
91 ERPTSampler *newSampler = new ERPTSampler(*this);
92 newSampler->baseSampler = baseSampler->clone();
93 newSampler->totalSamples = 0;
94 newSampler->sampleImage = NULL;
98 static void initERPT(ERPTSampler *sampler, const Sample *sample)
101 sampler->normalSamples = SAMPLE_FLOATS;
102 for (i = 0; i < sample->n1D.size(); ++i)
103 sampler->normalSamples += sample->n1D[i];
104 for (i = 0; i < sample->n2D.size(); ++i)
105 sampler->normalSamples += 2 * sample->n2D[i];
106 sampler->totalSamples = sampler->normalSamples;
107 sampler->offset = new u_int[sample->nxD.size()];
108 sampler->totalTimes = 0;
109 for (i = 0; i < sample->nxD.size(); ++i) {
110 sampler->offset[i] = sampler->totalSamples;
111 sampler->totalTimes += sample->nxD[i];
112 sampler->totalSamples += sample->dxD[i] * sample->nxD[i];
114 sampler->sampleImage = AllocAligned<float>(sampler->totalSamples);
115 sampler->baseImage = AllocAligned<float>(sampler->totalSamples);
116 sampler->timeImage = AllocAligned<int>(sampler->totalTimes);
117 sampler->baseTimeImage = AllocAligned<int>(sampler->totalTimes);
118 sampler->baseSampler->SetTsPack(sampler->tspack);
119 sampler->baseSampler->SetFilm(sampler->film);
120 sampler->mutation = ~0U;
122 // Fetch first contribution buffer from pool
123 sampler->contribBuffer = sampler->film->scene->contribPool->Next(NULL);
126 // interface for new ray/samples from scene
127 bool ERPTSampler::GetNextSample(Sample *sample, u_int *use_pos)
129 sample->sampler = this;
130 if (sampleImage == NULL) {
131 initERPT(this, sample);
134 if (mutation == ~0U) {
135 // Dade - we are at a valid checkpoint where we can stop the
136 // rendering. Check if we have enough samples per pixel in the film.
137 if (film->enoughSamplePerPixel)
140 const bool ret = baseSampler->GetNextSample(sample, use_pos);
141 sample->sampler = this;
142 for (u_int i = 0; i < totalTimes; ++i)
143 sample->timexD[0][i] = -1;
145 currentImage = baseImage;
146 currentTimeImage = baseTimeImage;
152 for (u_int i = 0; i < totalTimes; ++i)
153 sample->timexD[0][i] = baseTimeImage[i];
155 currentImage = baseImage;
156 currentTimeImage = baseTimeImage;
159 // *** small mutation ***
160 // mutate current sample
161 sample->imageX = mutateScaled(currentImage[0], tspack->rng->floatValue(), xPixelStart, xPixelEnd, range);
162 sample->imageY = mutateScaled(currentImage[1], tspack->rng->floatValue(), yPixelStart, yPixelEnd, range);
163 sample->lensU = mutate(currentImage[2], tspack->rng->floatValue());
164 sample->lensV = mutate(currentImage[3], tspack->rng->floatValue());
165 sample->time = mutate(currentImage[4], tspack->rng->floatValue());
166 sample->wavelengths = mutate(currentImage[5], tspack->rng->floatValue());
167 for (u_int i = SAMPLE_FLOATS; i < normalSamples; ++i)
168 sample->oneD[0][i - SAMPLE_FLOATS] = mutate(currentImage[i], tspack->rng->floatValue());
175 float *ERPTSampler::GetLazyValues(Sample *sample, u_int num, u_int pos)
177 const u_int size = sample->dxD[num];
178 float *data = sample->xD[num] + pos * size;
179 const int stampLimit = sample->stamp;
180 if (sample->timexD[num][pos] != stampLimit) {
181 if (sample->timexD[num][pos] == -1) {
182 baseSampler->GetLazyValues(sample, num, pos);
183 sample->timexD[num][pos] = 0;
185 const u_int start = offset[num] + pos * size;
186 float *image = currentImage + start;
187 for (u_int i = 0; i < size; ++i)
190 for (int &time = sample->timexD[num][pos]; time < stampLimit; ++time) {
191 for (u_int i = 0; i < size; ++i)
192 data[i] = mutate(data[i], tspack->rng->floatValue());
198 // interface for adding/accepting a new image sample.
199 void ERPTSampler::AddSample(const Sample &sample)
201 vector<Contribution> &newContributions(sample.contributions);
203 for(u_int i = 0; i < newContributions.size(); ++i)
204 newLY += newContributions[i].color.Y();
205 if (mutation == 0U || mutation == ~0U) {
207 // Add accumulated contribution of previous reference sample
208 weight *= quantum / LY;
209 if (!isinf(weight) && LY > 0.f) {
210 for(u_int i = 0; i < oldContributions.size(); ++i) {
211 // Radiance - added new use of contributionpool/buffers
212 if(&oldContributions && !contribBuffer->Add(&oldContributions[i], weight)) {
213 contribBuffer = film->scene->contribPool->Next(contribBuffer);
214 contribBuffer->Add(&oldContributions[i], weight);
220 if (mutation == ~0U) {
221 if (!(newLY > 0.f)) {
222 newContributions.clear();
225 contribBuffer->AddSampleCount(1.f);
228 const float meanIntensity = totalLY > 0. ? static_cast<float>(totalLY / sampleCount) : 1.f;
229 // calculate the number of chains on a new seed
230 quantum = newLY / meanIntensity;
231 numChains = max(1U, Floor2UInt(quantum + .5f));
232 // The following line avoids to block on a pixel
233 // if the initial sample is extremely bright
234 numChains = min(numChains, totalMutations);
235 quantum /= (numChains * totalMutations);
237 baseContributions = newContributions;
238 baseImage[0] = sample.imageX;
239 baseImage[1] = sample.imageY;
240 baseImage[2] = sample.lensU;
241 baseImage[3] = sample.lensV;
242 baseImage[4] = sample.time;
243 baseImage[5] = sample.wavelengths;
244 for (u_int i = SAMPLE_FLOATS; i < totalSamples; ++i)
245 baseImage[i] = sample.oneD[0][i - SAMPLE_FLOATS];
246 for (u_int i = 0 ; i < totalTimes; ++i)
247 baseTimeImage[i] = sample.timexD[0][i];
249 newContributions.clear();
253 oldContributions = baseContributions;
255 // calculate accept probability from old and new image sample
258 accProb = min(1.f, newLY / LY);
261 float newWeight = accProb;
262 weight += 1.f - accProb;
264 // try accepting of the new sample
265 if (accProb == 1.f || tspack->rng->floatValue() < accProb) {
266 // Add accumulated contribution of previous reference sample
267 weight *= quantum / LY;
268 if (!isinf(weight) && LY > 0.f) {
269 for(u_int i = 0; i < oldContributions.size(); ++i) {
270 // Radiance - added new use of contributionpool/buffers
271 if(&oldContributions && !contribBuffer->Add(&oldContributions[i], weight)) {
272 contribBuffer = film->scene->contribPool->Next(contribBuffer);
273 contribBuffer->Add(&oldContributions[i], weight);
279 oldContributions = newContributions;
281 // Save new contributions for reference
282 sampleImage[0] = sample.imageX;
283 sampleImage[1] = sample.imageY;
284 sampleImage[2] = sample.lensU;
285 sampleImage[3] = sample.lensV;
286 sampleImage[4] = sample.time;
287 sampleImage[5] = sample.wavelengths;
288 for (u_int i = SAMPLE_FLOATS; i < totalSamples; ++i)
289 sampleImage[i] = sample.oneD[0][i - SAMPLE_FLOATS];
290 for (u_int i = 0 ; i < totalTimes; ++i)
291 timeImage[i] = sample.timexD[0][i];
292 stamp = sample.stamp;
293 currentImage = sampleImage;
294 currentTimeImage = timeImage;
296 // Add contribution of new sample before rejecting it
297 newWeight *= quantum / newLY;
298 if (!isinf(newWeight) && newLY > 0.f) {
299 for(u_int i = 0; i < newContributions.size(); ++i) {
300 // Radiance - added new use of contributionpool/buffers
301 if(!contribBuffer->Add(&newContributions[i], newWeight)) {
302 contribBuffer = film->scene->contribPool->Next(contribBuffer);
303 contribBuffer->Add(&newContributions[i], newWeight);
308 // Restart from previous reference
309 for (u_int i = 0; i < totalTimes; ++i)
310 sample.timexD[0][i] = currentTimeImage[i];
311 sample.stamp = stamp;
313 if (++mutation >= totalMutations) {
315 if (++chain >= numChains) {
320 newContributions.clear();
323 Sampler* ERPTSampler::CreateSampler(const ParamSet ¶ms, const Film *film)
325 int xStart, xEnd, yStart, yEnd;
326 film->GetSampleExtent(&xStart, &xEnd, &yStart, &yEnd);
327 int totMutations = params.FindOneInt("chainlength", 100); // number of mutations from a given seed
328 float range = params.FindOneFloat("mutationrange", (xEnd - xStart + yEnd - yStart) / 50.f); // maximum distance in pixel for a small mutation
329 string base = params.FindOneString("basesampler", "random"); // sampler for new chain seed
330 Sampler *sampler = MakeSampler(base, params, film);
331 if (sampler == NULL) {
332 luxError(LUX_SYSTEM, LUX_SEVERE, "ERPTSampler: Could not obtain a valid sampler");
335 return new ERPTSampler(max(totMutations, 0), range, sampler);
338 static DynamicLoader::RegisterSampler<ERPTSampler> r("erpt");