src/slg/engines/caches/photongi/tracephotonsthread.cpp
// The metropolis sampler used here is based on:
//  "Robust Adaptive Photon Tracing using Photon Path Visibility"
//  by TOSHIYA HACHISUKA and HENRIK WANN JENSEN
The metropolis sampler used here is based on:
"Robust Adaptive Photon Tracing using Photon Path Visibility"
by TOSHIYA HACHISUKA and HENRIK WANN JENSEN
The metropolis sampler used here is based on : " Robust Adaptive Photon Tracing using Photon Path Visibility " by TOSHIYA HACHISUKA and HENRIK WANN JENSEN
void TracePhotonsThread::RenderFunc() {
	const u_int workSize = 4096;
	RandomGenerator rndGen(1 + threadIndex);
	sampleBootSize = 7;
	sampleStepSize = 5;
	sampleSize = 
			sampleBootSize + 
			pgic.params.photon.maxPathDepth * sampleStepSize; 
	vector<float> currentPathSamples(sampleSize);
	vector<float> candidatePathSamples(sampleSize);
	vector<float> uniformPathSamples(sampleSize);
	vector<RadiancePhotonEntry> currentIndirectPhotons;
	vector<Photon> currentCausticPhotons;
	vector<RadiancePhotonEntry> candidateIndirectPhotons;
	vector<Photon> candidateCausticPhotons;
	vector<RadiancePhotonEntry> uniformIndirectPhotons;
	vector<Photon> uniformCausticPhotons;
	const double startTime = WallClockTime();
	double lastPrintTime = startTime;
	while(!boost::this_thread::interruption_requested()) {
		u_int workCounter;
		do {
			workCounter = globalPhotonsCounter;
		} while (!globalPhotonsCounter.compare_exchange_weak(workCounter, workCounter + workSize));
		if (workCounter >= photonTracedCount)
			break;
		indirectDone = (!pgic.params.indirect.enabled) ||
				((pgic.params.indirect.maxSize > 0) && (globalIndirectSize >= pgic.params.indirect.maxSize));
		causticDone = (!pgic.params.caustic.enabled) ||
				(globalCausticSize >= pgic.params.caustic.maxSize);
		u_int workToDo = (workCounter + workSize > photonTracedCount) ?
			(photonTracedCount - workCounter) : workSize;
		if (!indirectDone)
			globalIndirectPhotonsTraced += workToDo;
		if (!causticDone)
			globalCausticPhotonsTraced += workToDo;
		if (threadIndex == 0) {
			const double now = WallClockTime();
			if (now - lastPrintTime > 2.0) {
				const float indirectProgress = pgic.params.indirect.enabled ?
					(((globalIndirectSize > 0) && (pgic.params.indirect.maxSize > 0)) ?
						((100.0 * globalIndirectSize) / pgic.params.indirect.maxSize) : 0.f) :
					100.f;
				const float causticProgress = pgic.params.caustic.enabled ?
					((globalCausticSize > 0) ? ((100.0 * globalCausticSize) / pgic.params.caustic.maxSize) : 0.f) :
					100.f;
				SLG_LOG(boost::format("PhotonGI Cache photon traced: %d/%d [%.1f%%, %.1fM photons/sec, Map sizes (%.1f%%, %.1f%%)]") %
						workCounter % photonTracedCount %
						((100.0 * workCounter) / photonTracedCount) %
						(workCounter / (1000.0 * (now - startTime))) %
						indirectProgress %
						causticProgress);
				lastPrintTime = now;
			}
		}
		const u_int indirectPhotonsStart = indirectPhotons.size();
		const u_int causticPhotonsStart = causticPhotons.size();
		if (pgic.params.samplerType == PGIC_SAMPLER_METROPOLIS) {
			bool foundUseful = false;
			for (u_int i = 0; i < 16384; ++i) {
				UniformMutate(rndGen, currentPathSamples);
				foundUseful = TracePhotonPath(rndGen, currentPathSamples, currentIndirectPhotons,
						currentCausticPhotons);
				if (foundUseful)
					break;
#ifdef WIN32
				renderThread->yield();
#endif
			}
			if (!foundUseful) {
				SLG_LOG("PhotonGI metropolis sampler is unable to find a useful light path");
			} else {
				u_int currentPhotonsScale = 1;
				float mutationSize = 1.f;
				u_int acceptedCount = 1;
				u_int mutatedCount = 1;
				u_int uniformCount = 1;
				u_int workToDoIndex = workToDo;
				while (workToDoIndex-- && !boost::this_thread::interruption_requested()) {
					UniformMutate(rndGen, uniformPathSamples);
					if (TracePhotonPath(rndGen, uniformPathSamples, uniformIndirectPhotons,
							uniformCausticPhotons)) {
						AddPhotons(currentPhotonsScale, currentIndirectPhotons, currentCausticPhotons);
						copy(uniformPathSamples.begin(), uniformPathSamples.end(), currentPathSamples.begin());
						currentPhotonsScale = 1;
						currentIndirectPhotons = uniformIndirectPhotons;
						currentCausticPhotons = uniformCausticPhotons;
						++uniformCount;
					} else {
						Mutate(rndGen, currentPathSamples, candidatePathSamples, mutationSize);
						++mutatedCount;
						if (TracePhotonPath(rndGen, candidatePathSamples, candidateIndirectPhotons,
								candidateCausticPhotons)) {
							AddPhotons(currentPhotonsScale, currentIndirectPhotons, currentCausticPhotons);
							copy(candidatePathSamples.begin(), candidatePathSamples.end(), currentPathSamples.begin());
							currentPhotonsScale = 1;
							currentIndirectPhotons = candidateIndirectPhotons;
							currentCausticPhotons = candidateCausticPhotons;
							++acceptedCount;
						} else
							++currentPhotonsScale;
						const float R = acceptedCount / (float)mutatedCount;
						mutationSize += (R - .234f) / mutatedCount;
					}
#ifdef WIN32
					renderThread->yield();
#endif
				}
				if (currentPhotonsScale > 1) {
					AddPhotons(currentPhotonsScale, currentIndirectPhotons, currentCausticPhotons);
				}
				const float scaleFactor = uniformCount /  (float)workToDo;
				for (u_int i = indirectPhotonsStart; i < indirectPhotons.size(); ++i)
					indirectPhotons[i].alpha *= scaleFactor;
				for (u_int i = causticPhotonsStart; i < causticPhotons.size(); ++i)
					causticPhotons[i].alpha *= scaleFactor;
			}
		} else
		if (pgic.params.samplerType == PGIC_SAMPLER_RANDOM) {
			u_int workToDoIndex = workToDo;
			while (workToDoIndex-- && !boost::this_thread::interruption_requested()) {
				UniformMutate(rndGen, currentPathSamples);
				TracePhotonPath(rndGen, currentPathSamples, currentIndirectPhotons, currentCausticPhotons);
				AddPhotons(currentIndirectPhotons, currentCausticPhotons);
#ifdef WIN32
				renderThread->yield();
#endif
			}
		} else
			throw runtime_error("Unknown sampler type in TracePhotonsThread::RenderFunc(): " + ToString(pgic.params.samplerType));
		globalIndirectSize += indirectPhotons.size() - indirectPhotonsStart;
		globalCausticSize += causticPhotons.size() - causticPhotonsStart;
		. I can do the check only here because
		if (indirectDone && causticDone)
			break;
	}
}
void TracePhotonsThread :: RenderFunc ( ) { const u_int workSize = 4096 ; RandomGenerator rndGen ( 1 + threadIndex ) ; sampleBootSize = 7 ; sampleStepSize = 5 ; sampleSize = sampleBootSize + pgic . params . photon . maxPathDepth * sampleStepSize ; vector < float > currentPathSamples ( sampleSize ) ; vector < float > candidatePathSamples ( sampleSize ) ; vector < float > uniformPathSamples ( sampleSize ) ; vector < RadiancePhotonEntry > currentIndirectPhotons ; vector < Photon > currentCausticPhotons ; vector < RadiancePhotonEntry > candidateIndirectPhotons ; vector < Photon > candidateCausticPhotons ; vector < RadiancePhotonEntry > uniformIndirectPhotons ; vector < Photon > uniformCausticPhotons ; const double startTime = WallClockTime ( ) ; double lastPrintTime = startTime ; while ( ! boost :: this_thread :: interruption_requested ( ) ) { u_int workCounter ; do { workCounter = globalPhotonsCounter ; } while ( ! globalPhotonsCounter . compare_exchange_weak ( workCounter , workCounter + workSize ) ) ; if ( workCounter >= photonTracedCount ) break ; indirectDone = ( ! pgic . params . indirect . enabled ) || ( ( pgic . params . indirect . maxSize > 0 ) && ( globalIndirectSize >= pgic . params . indirect . maxSize ) ) ; causticDone = ( ! pgic . params . caustic . enabled ) || ( globalCausticSize >= pgic . params . caustic . maxSize ) ; u_int workToDo = ( workCounter + workSize > photonTracedCount ) ? ( photonTracedCount - workCounter ) : workSize ; if ( ! indirectDone ) globalIndirectPhotonsTraced += workToDo ; if ( ! causticDone ) globalCausticPhotonsTraced += workToDo ; if ( threadIndex == 0 ) { const double now = WallClockTime ( ) ; if ( now - lastPrintTime > 2.0 ) { const float indirectProgress = pgic . params . indirect . enabled ? ( ( ( globalIndirectSize > 0 ) && ( pgic . params . indirect . maxSize > 0 ) ) ? ( ( 100.0 * globalIndirectSize ) / pgic . params . indirect . maxSize ) : 0.f ) : 100.f ; const float causticProgress = pgic . params . caustic . enabled ? ( ( globalCausticSize > 0 ) ? ( ( 100.0 * globalCausticSize ) / pgic . params . caustic . maxSize ) : 0.f ) : 100.f ; SLG_LOG ( boost :: format ( " " ) % workCounter % photonTracedCount % ( ( 100.0 * workCounter ) / photonTracedCount ) % ( workCounter / ( 1000.0 * ( now - startTime ) ) ) % indirectProgress % causticProgress ) ; lastPrintTime = now ; } } const u_int indirectPhotonsStart = indirectPhotons . size ( ) ; const u_int causticPhotonsStart = causticPhotons . size ( ) ; if ( pgic . params . samplerType == PGIC_SAMPLER_METROPOLIS ) { bool foundUseful = false ; for ( u_int i = 0 ; i < 16384 ; ++ i ) { UniformMutate ( rndGen , currentPathSamples ) ; foundUseful = TracePhotonPath ( rndGen , currentPathSamples , currentIndirectPhotons , currentCausticPhotons ) ; if ( foundUseful ) break ; #ifdef WIN32 renderThread -> yield ( ) ; #endif } if ( ! foundUseful ) { SLG_LOG ( " " ) ; } else { u_int currentPhotonsScale = 1 ; float mutationSize = 1.f ; u_int acceptedCount = 1 ; u_int mutatedCount = 1 ; u_int uniformCount = 1 ; u_int workToDoIndex = workToDo ; while ( workToDoIndex -- && ! boost :: this_thread :: interruption_requested ( ) ) { UniformMutate ( rndGen , uniformPathSamples ) ; if ( TracePhotonPath ( rndGen , uniformPathSamples , uniformIndirectPhotons , uniformCausticPhotons ) ) { AddPhotons ( currentPhotonsScale , currentIndirectPhotons , currentCausticPhotons ) ; copy ( uniformPathSamples . begin ( ) , uniformPathSamples . end ( ) , currentPathSamples . begin ( ) ) ; currentPhotonsScale = 1 ; currentIndirectPhotons = uniformIndirectPhotons ; currentCausticPhotons = uniformCausticPhotons ; ++ uniformCount ; } else { Mutate ( rndGen , currentPathSamples , candidatePathSamples , mutationSize ) ; ++ mutatedCount ; if ( TracePhotonPath ( rndGen , candidatePathSamples , candidateIndirectPhotons , candidateCausticPhotons ) ) { AddPhotons ( currentPhotonsScale , currentIndirectPhotons , currentCausticPhotons ) ; copy ( candidatePathSamples . begin ( ) , candidatePathSamples . end ( ) , currentPathSamples . begin ( ) ) ; currentPhotonsScale = 1 ; currentIndirectPhotons = candidateIndirectPhotons ; currentCausticPhotons = candidateCausticPhotons ; ++ acceptedCount ; } else ++ currentPhotonsScale ; const float R = acceptedCount / ( float ) mutatedCount ; mutationSize += ( R - .234f ) / mutatedCount ; } #ifdef WIN32 renderThread -> yield ( ) ; #endif } if ( currentPhotonsScale > 1 ) { AddPhotons ( currentPhotonsScale , currentIndirectPhotons , currentCausticPhotons ) ; } const float scaleFactor = uniformCount / ( float ) workToDo ; for ( u_int i = indirectPhotonsStart ; i < indirectPhotons . size ( ) ; ++ i ) indirectPhotons [ i ] . alpha *= scaleFactor ; for ( u_int i = causticPhotonsStart ; i < causticPhotons . size ( ) ; ++ i ) causticPhotons [ i ] . alpha *= scaleFactor ; } } else if ( pgic . params . samplerType == PGIC_SAMPLER_RANDOM ) { u_int workToDoIndex = workToDo ; while ( workToDoIndex -- && ! boost :: this_thread :: interruption_requested ( ) ) { UniformMutate ( rndGen , currentPathSamples ) ; TracePhotonPath ( rndGen , currentPathSamples , currentIndirectPhotons , currentCausticPhotons ) ; AddPhotons ( currentIndirectPhotons , currentCausticPhotons ) ; #ifdef WIN32 renderThread -> yield ( ) ; #endif } } else throw runtime_error ( " " + ToString ( pgic . params . samplerType ) ) ; globalIndirectSize += indirectPhotons . size ( ) - indirectPhotonsStart ; globalCausticSize += causticPhotons . size ( ) - causticPhotonsStart ; if ( indirectDone && causticDone ) break ; } }
The metropolis sampler used here is based on:
"Robust Adaptive Photon Tracing using Photon Path Visibility"
by TOSHIYA HACHISUKA and HENRIK WANN JENSEN
The metropolis sampler used here is based on : " Robust Adaptive Photon Tracing using Photon Path Visibility " by TOSHIYA HACHISUKA and HENRIK WANN JENSEN
//-------------------------------------------------------------------------- // Initialization //-------------------------------------------------------------------------- // To generate the initial setup // For each light vertex //-------------------------------------------------------------------------- // Get a bucket of work to do //-------------------------------------------------------------------------- // Get some work to do // Check if it is time to stop // Print some progress information //---------------------------------------------------------------------- // Metropolis Sampler //---------------------------------------------------------------------- // Look for a useful path to start with // Work around Windows bad scheduling // I was unable to find a useful path. Something wrong. this // may be an empty scene, a dark room, etc. // Trace light paths // Add the old current photons (scaled by currentPhotonsScale) // The candidate path becomes the current one // Try a mutation of the current path // Add the old current photons (scaled by currentPhotonsScale) // The candidate path becomes the current one // 0.234 => the optimal asymptotic acceptance ratio has been // derived 23.4% [Roberts et al. 1997] // Work around Windows bad scheduling // Add the last current photons (scaled by currentPhotonsScale) // Scale all photon values //---------------------------------------------------------------------- // Random Sampler //---------------------------------------------------------------------- // Trace light paths // Add the new photons // Work around Windows bad scheduling //---------------------------------------------------------------------- // Update size counters // Check if it is time to stop. I can do the check only here because // globalPhotonsTraced was already incremented