samplers/erpt.cpp
author Aldo René Zang <aldo.zang@gmail.com>
Mon May 14 21:00:57 2012 -0300 (2 days ago)
branchARLuxrender
changeset 3699 29da2b1979f3
parent 3041 951060cdbc99
child 3442 f311f9c3f970
permissions -rw-r--r--
New features for Environment integrator. Added environment light features. New integrator depthfield.
     1 /***************************************************************************
     2  *   Copyright (C) 1998-2009 by authors (see AUTHORS.txt )                 *
     3  *                                                                         *
     4  *   This file is part of LuxRender.                                       *
     5  *                                                                         *
     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.                                   *
    10  *                                                                         *
    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.                          *
    15  *                                                                         *
    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/>. *
    18  *                                                                         *
    19  *   This project is based on PBRT ; see http://www.pbrt.org               *
    20  *   Lux Renderer website : http://www.luxrender.net                       *
    21  ***************************************************************************/
    22 
    23 // initial metropolis light transport sample integrator
    24 // by radiance
    25 
    26 // TODO: add scaling of output image samples
    27 
    28 // erpt.cpp*
    29 #include "erpt.h"
    30 #include "dynload.h"
    31 #include "scene.h"
    32 #include "error.h"
    33 
    34 using namespace lux;
    35 
    36 #define SAMPLE_FLOATS 6
    37 
    38 // mutate a value in the range [0-1]
    39 static float mutate(const float x, const float randomValue)
    40 {
    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) {
    44 		float x1 = x + dx;
    45 		return (x1 > 1.f) ? x1 - 1.f : x1;
    46 	} else {
    47 		float x1 = x - dx;
    48 		return (x1 < 0.f) ? x1 + 1.f : x1;
    49 	}
    50 }
    51 
    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)
    54 {
    55 	float dx = range * expf(-logf(2.f * range) * fabsf(2.f * randomValue - 1.f));
    56 	if (randomValue < 0.5f) {
    57 		float x1 = x + dx;
    58 		return (x1 > maxi) ? x1 - maxi + mini : x1;
    59 	} else {
    60 		float x1 = x - dx;
    61 		return (x1 < mini) ? x1 - mini + maxi : x1;
    62 	}
    63 }
    64 
    65 ERPTSampler::ERPTData::ERPTData(const Sample &sample) :
    66 	numChains(0), chain(0), mutation(~0U), stamp(0), currentStamp(0),
    67 	baseLY(0.f), quantum(0.f), weight(0.f), LY(0.f), alpha(0.f),
    68 	totalLY(0.), sampleCount(0.)
    69 {
    70 	u_int i;
    71 	normalSamples = SAMPLE_FLOATS;
    72 	for (i = 0; i < sample.n1D.size(); ++i)
    73 		normalSamples += sample.n1D[i];
    74 	for (i = 0; i < sample.n2D.size(); ++i)
    75 		normalSamples += 2 * sample.n2D[i];
    76 	totalSamples = normalSamples;
    77 	timeOffset = new u_int[sample.nxD.size()];
    78 	offset = new u_int[sample.nxD.size()];
    79 	totalTimes = 0;
    80 	for (i = 0; i < sample.nxD.size(); ++i) {
    81 		timeOffset[i] = totalTimes;
    82 		offset[i] = totalSamples;
    83 		totalTimes += sample.nxD[i];
    84 		totalSamples += sample.dxD[i] * sample.nxD[i];
    85 	}
    86 	sampleImage = AllocAligned<float>(totalSamples);
    87 	currentImage = AllocAligned<float>(totalSamples);
    88 	baseImage = AllocAligned<float>(totalSamples);
    89 	timeImage = AllocAligned<int>(totalTimes);
    90 	currentTimeImage = AllocAligned<int>(totalTimes);
    91 	baseTimeImage = AllocAligned<int>(totalTimes);
    92 }
    93 ERPTSampler::ERPTData::~ERPTData()
    94 {
    95 	FreeAligned(baseTimeImage);
    96 	FreeAligned(currentTimeImage);
    97 	FreeAligned(timeImage);
    98 	FreeAligned(baseImage);
    99 	FreeAligned(currentImage);
   100 	FreeAligned(sampleImage);
   101 	delete[] offset;
   102 	delete[] timeOffset;
   103 }
   104 
   105 // Metropolis method definitions
   106 ERPTSampler::ERPTSampler(u_int totMutations, float rng, Sampler *sampler) :
   107 	Sampler(sampler->xPixelStart, sampler->xPixelEnd,
   108 	sampler->yPixelStart, sampler->yPixelEnd, sampler->samplesPerPixel),
   109 	totalMutations(totMutations), range(rng), baseSampler(sampler)
   110 {
   111 }
   112 
   113 ERPTSampler::~ERPTSampler() {
   114 	delete baseSampler;
   115 }
   116 
   117 // interface for new ray/samples from scene
   118 bool ERPTSampler::GetNextSample(Sample *sample)
   119 {
   120 	const RandomGenerator *rng = sample->rng;
   121 	ERPTData *data = (ERPTData *)(sample->samplerData);
   122 
   123 	if (data->mutation == ~0U) {
   124 		// Dade - we are at a valid checkpoint where we can stop the
   125 		// rendering. Check if we have enough samples per pixel in the film.
   126 		if (film->enoughSamplesPerPixel)
   127 			return false;
   128 
   129 		sample->samplerData = data->baseSamplerData;
   130 		const bool ret = baseSampler->GetNextSample(sample);
   131 		float *image = data->baseImage;
   132 		*image++ = sample->imageX;
   133 		*image++ = sample->imageY;
   134 		*image++ = sample->lensU;
   135 		*image++ = sample->lensV;
   136 		*image++ = sample->time;
   137 		*image++ = sample->wavelengths;
   138 		for (u_int i = 0; i < sample->n1D.size(); ++i) {
   139 			for (u_int j = 0; j < sample->n1D[i]; ++j)
   140 				*image++ = baseSampler->GetOneD(*sample, i, j);
   141 		}
   142 		for (u_int i = 0; i < sample->n2D.size(); ++i) {
   143 			for (u_int j = 0; j < sample->n2D[i]; ++j) {
   144 				float u[2];
   145 				baseSampler->GetTwoD(*sample, i, j, u);
   146 				*image++ = u[0];
   147 				*image++ = u[1];
   148 			}
   149 		}
   150 		sample->samplerData = data;
   151 		for (u_int i = 0; i < data->totalTimes; ++i)
   152 			data->baseTimeImage[i] = -1;
   153 		data->currentStamp = 0;
   154 		data->stamp = 0;
   155 		return ret;
   156 	} else {
   157 		if (data->mutation == 0) {
   158 			// *** new chain ***
   159 			for (u_int i = 0; i < data->totalSamples; ++i)
   160 				data->currentImage[i] = data->baseImage[i];
   161 			for (u_int i = 0; i < data->totalTimes; ++i) {
   162 				data->timeImage[i] = -1;
   163 				data->currentTimeImage[i] = data->baseTimeImage[i];
   164 			}
   165 			data->currentStamp = 0;
   166 			data->stamp = 0;
   167 		}
   168 		// *** small mutation ***
   169 		// mutate current sample
   170 		data->sampleImage[0] = mutateScaled(data->currentImage[0], rng->floatValue(), xPixelStart, xPixelEnd, range);
   171 		data->sampleImage[1] = mutateScaled(data->currentImage[1], rng->floatValue(), yPixelStart, yPixelEnd, range);
   172 		for (u_int i = 2; i < data->normalSamples; ++i)
   173 			data->sampleImage[i] = mutate(data->currentImage[i], rng->floatValue());
   174 		data->stamp = data->currentStamp + 1;
   175 		sample->imageX = data->sampleImage[0];
   176 		sample->imageY = data->sampleImage[1];
   177 		sample->lensU = data->sampleImage[2];
   178 		sample->lensV = data->sampleImage[3];
   179 		sample->time = data->sampleImage[4];
   180 		sample->wavelengths = data->sampleImage[5];
   181 	}
   182 
   183 	return true;
   184 }
   185 
   186 float ERPTSampler::GetOneD(const Sample &sample, u_int num, u_int pos)
   187 {
   188 	ERPTData *data = (ERPTData *)(sample.samplerData);
   189 	u_int offset = SAMPLE_FLOATS;
   190 	for (u_int i = 0; i < num; ++i)
   191 		offset += sample.n1D[i];
   192 	if (data->mutation == ~0U)
   193 		return data->baseImage[offset + pos];
   194 	else
   195 		return data->sampleImage[offset + pos];
   196 }
   197 
   198 void ERPTSampler::GetTwoD(const Sample &sample, u_int num, u_int pos, float u[2])
   199 {
   200 	ERPTData *data = (ERPTData *)(sample.samplerData);
   201 	u_int offset = SAMPLE_FLOATS;
   202 	for (u_int i = 0; i < sample.n1D.size(); ++i)
   203 		offset += sample.n1D[i];
   204 	for (u_int i = 0; i < num; ++i)
   205 		offset += sample.n2D[i] * 2;
   206 	if (data->mutation == ~0U) {
   207 		u[0] = data->baseImage[offset + pos * 2];
   208 		u[1] = data->baseImage[offset + pos * 2 + 1];
   209 	} else {
   210 		u[0] = data->sampleImage[offset + pos * 2];
   211 		u[1] = data->sampleImage[offset + pos * 2 + 1];
   212 	}
   213 }
   214 
   215 float *ERPTSampler::GetLazyValues(const Sample &sample, u_int num, u_int pos)
   216 {
   217 	ERPTData *data = (ERPTData *)(sample.samplerData);
   218 	const u_int size = sample.dxD[num];
   219 	const u_int first = data->offset[num] + pos * size;
   220 	int &baseTime(data->baseTimeImage[data->timeOffset[num] + pos]);
   221 	if (baseTime == -1) {
   222 		const_cast<Sample&>(sample).samplerData = data->baseSamplerData;
   223 		float *base = baseSampler->GetLazyValues(sample, num, pos);
   224 		const_cast<Sample&>(sample).samplerData = data;
   225 		for (u_int i = 0; i < size; ++i)
   226 			data->baseImage[first + i] = base[i];
   227 		baseTime = 0;
   228 	}
   229 	if (data->mutation == ~0U)
   230 		return data->baseImage + first;
   231 	int &time(data->timeImage[data->timeOffset[num] + pos]);
   232 	const int stampLimit = data->stamp;
   233 	if (time != stampLimit) {
   234 		int &currentTime(data->currentTimeImage[data->timeOffset[num] + pos]);
   235 		if (currentTime == -1) {
   236 			for (u_int i = first; i < first + size; ++i)
   237 				data->currentImage[i] = data->baseImage[i];
   238 			currentTime = 0;
   239 		}
   240 		for (u_int i = first; i < first + size; ++i) {
   241 			data->sampleImage[i] = data->currentImage[i];
   242 			for (time = currentTime; time < stampLimit; ++time)
   243 				data->sampleImage[i] = mutate(data->sampleImage[i], sample.rng->floatValue());
   244 		}
   245 	}
   246 	return data->sampleImage + first;
   247 }
   248 
   249 // interface for adding/accepting a new image sample.
   250 void ERPTSampler::AddSample(const Sample &sample)
   251 {
   252 	ERPTData *data = (ERPTData *)(sample.samplerData);
   253 	vector<Contribution> &newContributions(sample.contributions);
   254 	float newLY = 0.0f;
   255 	for(u_int i = 0; i < newContributions.size(); ++i)
   256 		newLY += newContributions[i].color.Y();
   257 	if (data->mutation == 0U || data->mutation == ~0U) {
   258 		if (data->weight > 0.f) {
   259 			// Add accumulated contribution of previous reference sample
   260 			data->weight *= data->quantum / data->LY;
   261 			if (!isinf(data->weight) && data->LY > 0.f) {
   262 				for(u_int i = 0; i < data->oldContributions.size(); ++i)
   263 					sample.contribBuffer->Add(data->oldContributions[i], data->weight);
   264 			}
   265 			data->weight = 0.f;
   266 		}
   267 		if (data->mutation == ~0U) {
   268 			if (!(newLY > 0.f)) {
   269 				newContributions.clear();
   270 				return;
   271 			}
   272 			sample.contribBuffer->AddSampleCount(1.f);
   273 			++(data->sampleCount);
   274 			data->totalLY += newLY;
   275 			const float meanIntensity = data->totalLY > 0. ? static_cast<float>(data->totalLY / data->sampleCount) : 1.f;
   276 			// calculate the number of chains on a new seed
   277 			data->quantum = newLY / meanIntensity;
   278 			data->numChains = max(1U, Floor2UInt(data->quantum + .5f));
   279 			// The following line avoids to block on a pixel
   280 			// if the initial sample is extremely bright
   281 			data->numChains = min(data->numChains, totalMutations);
   282 			data->quantum /= data->numChains;
   283 			data->baseLY = newLY;
   284 			data->baseContributions = newContributions;
   285 			data->mutation = 0;
   286 			newContributions.clear();
   287 			return;
   288 		}
   289 		data->LY = data->baseLY;
   290 		data->oldContributions = data->baseContributions;
   291 	}
   292 	// calculate accept probability from old and new image sample
   293 	float accProb;
   294 	if (data->LY > 0.f)
   295 		accProb = min(1.f, newLY / data->LY);
   296 	else
   297 		accProb = 1.f;
   298 	float newWeight = accProb;
   299 	data->weight += 1.f - accProb;
   300 
   301 	// try accepting of the new sample
   302 	if (accProb == 1.f || sample.rng->floatValue() < accProb) {
   303 		// Add accumulated contribution of previous reference sample
   304 		data->weight *= data->quantum / data->LY;
   305 		if (!isinf(data->weight) && data->LY > 0.f) {
   306 			for(u_int i = 0; i < data->oldContributions.size(); ++i)
   307 				sample.contribBuffer->Add(data->oldContributions[i], data->weight);
   308 		}
   309 		data->weight = newWeight;
   310 		data->LY = newLY;
   311 		data->oldContributions = newContributions;
   312 
   313 		// Save new contributions for reference
   314 		swap(data->sampleImage, data->currentImage);
   315 		swap(data->timeImage, data->currentTimeImage);
   316 		data->currentStamp = data->stamp;
   317 	} else {
   318 		// Add contribution of new sample before rejecting it
   319 		newWeight *= data->quantum / newLY;
   320 		if (!isinf(newWeight) && newLY > 0.f) {
   321 			for(u_int i = 0; i < newContributions.size(); ++i)
   322 				sample.contribBuffer->Add(newContributions[i], newWeight);
   323 		}
   324 
   325 		data->stamp = data->currentStamp;
   326 	}
   327 	if (++(data->mutation) >= totalMutations) {
   328 		data->mutation = 0;
   329 		if (++(data->chain) >= data->numChains) {
   330 			data->chain = 0;
   331 			data->mutation = ~0U;
   332 		}
   333 	}
   334 	newContributions.clear();
   335 }
   336 
   337 Sampler* ERPTSampler::CreateSampler(const ParamSet &params, const Film *film)
   338 {
   339 	int xStart, xEnd, yStart, yEnd;
   340 	film->GetSampleExtent(&xStart, &xEnd, &yStart, &yEnd);
   341 	int totMutations = params.FindOneInt("chainlength", 100);	// number of mutations from a given seed
   342 	float range = params.FindOneFloat("mutationrange", (xEnd - xStart + yEnd - yStart) / 50.f);	// maximum distance in pixel for a small mutation
   343 	string base = params.FindOneString("basesampler", "random");	// sampler for new chain seed
   344 	Sampler *sampler = MakeSampler(base, params, film);
   345 	if (sampler == NULL) {
   346 		LOG( LUX_SEVERE,LUX_SYSTEM)<< "ERPTSampler: Could not obtain a valid sampler";
   347 		return NULL;
   348 	}
   349 	return new ERPTSampler(max(totMutations, 0), range, sampler);
   350 }
   351 
   352 static DynamicLoader::RegisterSampler<ERPTSampler> r("erpt");