int Path::randomWalkFromPixel(const Scene *scene, Sampler *sampler,
		int nSteps, const Point2i &pixelPosition, int rrStart, MemoryPool &pool) {

	PathVertex *v1 = pool.allocVertex(), *v2 = pool.allocVertex();
	PathEdge *e0 = pool.allocEdge(), *e1 = pool.allocEdge();

	/* Use a special sampling routine for the first two sensor vertices so that
	   the resulting subpath passes through the specified pixel position */
	int t = vertex(0)->sampleSensor(scene,
		sampler, pixelPosition, e0, v1, e1, v2);

	if (t < 1) {
		pool.release(e0);
		pool.release(v1);
		return 0;
	}

	append(e0, v1);

	if (t < 2) {
		pool.release(e1);
		pool.release(v2);
		return 1;
	}

	append(e1, v2);

	PathVertex *predVertex = v1, *curVertex = v2;
	PathEdge *predEdge = e1;
	Spectrum throughput(1.0f);

	for (; t<nSteps || nSteps == -1; ++t) {
		PathVertex *succVertex = pool.allocVertex();
		PathEdge *succEdge = pool.allocEdge();

		if (!curVertex->sampleNext(scene, sampler, predVertex, predEdge, succEdge,
				succVertex, ERadiance, rrStart != -1 && t >= rrStart, &throughput)) {
			pool.release(succVertex);
			pool.release(succEdge);
			return t;
		}

		append(succEdge, succVertex);

		predVertex = curVertex;
		curVertex = succVertex;
		predEdge = succEdge;
	}

	return nSteps;
}
int Path::randomWalk(const Scene *scene, Sampler *sampler,
		int nSteps, int rrStart, ETransportMode mode,
		MemoryPool &pool) {
	/* Determine the relevant edge and vertex to start the random walk */
	PathVertex *curVertex  = m_vertices[m_vertices.size()-1],
	           *predVertex = m_vertices.size() < 2 ? NULL :
	                         m_vertices[m_vertices.size()-2];
	PathEdge *predEdge     = m_edges.empty() ? NULL :
	                         m_edges[m_edges.size()-1];
	Spectrum throughput(1.0f);

	for (int i=0; i<nSteps || nSteps == -1; ++i) {
		PathVertex *succVertex = pool.allocVertex();
		PathEdge *succEdge = pool.allocEdge();

		if (!curVertex->sampleNext(scene, sampler, predVertex, predEdge, succEdge,
				succVertex, mode, rrStart != -1 && i >= rrStart, &throughput)) {
			pool.release(succVertex);
			pool.release(succEdge);
			return i;
		}

		append(succEdge, succVertex);

		predVertex = curVertex;
		curVertex = succVertex;
		predEdge = succEdge;
	}

	return nSteps;
}
std::pair<int, int> Path::alternatingRandomWalkFromPixel(const Scene *scene, Sampler *sampler,
		Path &emitterPath, int nEmitterSteps, Path &sensorPath, int nSensorSteps,
		const Point2i &pixelPosition, int rrStart, MemoryPool &pool) {
	/* Determine the relevant edges and vertices to start the random walk */
	PathVertex *curVertexS  = emitterPath.vertex(0),
	           *curVertexT  = sensorPath.vertex(0),
	           *predVertexS = NULL, *predVertexT = NULL;
	PathEdge   *predEdgeS  = NULL, *predEdgeT = NULL;

	PathVertex *v1 = pool.allocVertex(), *v2 = pool.allocVertex();
	PathEdge *e0 = pool.allocEdge(), *e1 = pool.allocEdge();

	/* Use a special sampling routine for the first two sensor vertices so that
	   the resulting subpath passes through the specified pixel position */
	int t = curVertexT->sampleSensor(scene,
		sampler, pixelPosition, e0, v1, e1, v2);

	if (t >= 1) {
		sensorPath.append(e0, v1);
	} else {
		pool.release(e0);
		pool.release(v1);
	}

	if (t == 2) {
		sensorPath.append(e1, v2);
		predVertexT = v1;
		curVertexT = v2;
		predEdgeT = e1;
	} else {
		pool.release(e1);
		pool.release(v2);
		curVertexT = NULL;
	}

	Spectrum throughputS(1.0f), throughputT(1.0f);

	int s = 0;
	do {
		if (curVertexT && (t < nSensorSteps || nSensorSteps == -1)) {
			PathVertex *succVertexT = pool.allocVertex();
			PathEdge *succEdgeT = pool.allocEdge();

			if (curVertexT->sampleNext(scene, sampler, predVertexT,
					predEdgeT, succEdgeT, succVertexT, ERadiance,
					rrStart != -1 && t >= rrStart, &throughputT)) {
				sensorPath.append(succEdgeT, succVertexT);
				predVertexT = curVertexT;
				curVertexT = succVertexT;
				predEdgeT = succEdgeT;
				t++;
			} else {
				pool.release(succVertexT);
				pool.release(succEdgeT);
				curVertexT = NULL;
			}
		} else {
			curVertexT = NULL;
		}

		if (curVertexS && (s < nEmitterSteps || nEmitterSteps == -1)) {
			PathVertex *succVertexS = pool.allocVertex();
			PathEdge *succEdgeS = pool.allocEdge();

			if (curVertexS->sampleNext(scene, sampler, predVertexS,
					predEdgeS, succEdgeS, succVertexS, EImportance,
					rrStart != -1 && s >= rrStart, &throughputS)) {
				emitterPath.append(succEdgeS, succVertexS);
				predVertexS = curVertexS;
				curVertexS = succVertexS;
				predEdgeS = succEdgeS;
				s++;
			} else {
				pool.release(succVertexS);
				pool.release(succEdgeS);
				curVertexS = NULL;
			}
		} else {
			curVertexS = NULL;
		}
	} while (curVertexS || curVertexT);

	return std::make_pair(s, t);
}
Example #4
0
bool PathEdge::pathConnect(const Scene *scene, const PathEdge *predEdge,
		const PathVertex *vs, Path &result, const PathVertex *vt,
		const PathEdge *succEdge, int maxInteractions, MemoryPool &pool) {
	BDAssert(result.edgeCount() == 0 && result.vertexCount() == 0);

	if (vs->isEmitterSupernode() || vt->isSensorSupernode()) {
		Float radianceTransport   = vt->isSensorSupernode() ? 1.0f : 0.0f,
		      importanceTransport = 1-radianceTransport;
		PathEdge *edge = pool.allocEdge();
		edge->medium = NULL;
		edge->length = 0.0f;
		edge->d = Vector(0.0f);
		edge->pdf[ERadiance]   = radianceTransport;
		edge->pdf[EImportance] = importanceTransport;
		edge->weight[ERadiance] = Spectrum(radianceTransport);
		edge->weight[EImportance] = Spectrum(importanceTransport);
		result.append(edge);
	} else {
		Point vsp = vs->getPosition(), vtp = vt->getPosition();
		Vector d(vsp-vtp);
		Float remaining = d.length();
		d /= remaining;
		if (remaining == 0) {
			#if defined(MTS_BD_DEBUG)
				SLog(EWarn, "Tried to connect %s and %s, which are located at exactly the same position!",
					vs->toString().c_str(), vt->toString().c_str());
			#endif
			return false;
		}

		Float lengthFactor = vs->isOnSurface() ? (1-ShadowEpsilon) : 1;
		Ray ray(vtp, d, vt->isOnSurface() ? Epsilon : 0,
				remaining * lengthFactor, vs->getTime());
		const Medium *medium = vt->getTargetMedium(succEdge,  d);

		int interactions = 0;

		Intersection its;
		while (true) {
			bool surface = scene->rayIntersectAll(ray, its);

			if (surface && (interactions == maxInteractions ||
				!(its.getBSDF()->getType() & BSDF::ENull))) {
				/* Encountered an occluder -- zero transmittance. */
				result.release(pool);
				return false;
			}

			/* Construct an edge */
			PathEdge *edge = pool.allocEdge();
			result.append(edge);
			edge->length = std::min(its.t, remaining);
			edge->medium = medium;
			edge->d = d;

			if (medium) {
				MediumSamplingRecord mRec;
				medium->eval(Ray(ray, 0, edge->length), mRec);
				edge->pdf[ERadiance] = (surface || !vs->isMediumInteraction())
					? mRec.pdfFailure : mRec.pdfSuccess;
				edge->pdf[EImportance] = (interactions > 0 || !vt->isMediumInteraction())
					? mRec.pdfFailure : mRec.pdfSuccessRev;

				if (edge->pdf[ERadiance] == 0 || edge->pdf[EImportance] == 0
						|| mRec.transmittance.isZero()) {
					/* Zero transmittance */
					result.release(pool);
					return false;
				}
				edge->weight[EImportance] = mRec.transmittance / edge->pdf[EImportance];
				edge->weight[ERadiance]   = mRec.transmittance / edge->pdf[ERadiance];
			} else {
				edge->weight[ERadiance] = edge->weight[EImportance] = Spectrum(1.0f);
				edge->pdf[ERadiance] = edge->pdf[EImportance] = 1.0f;
			}

			if (!surface || remaining - its.t < 0)
				break;

			/* Advance the ray */
			ray.o = ray(its.t);
			remaining -= its.t;
			ray.mint = Epsilon;
			ray.maxt = remaining * lengthFactor;

			const BSDF *bsdf = its.getBSDF();

			/* Account for the ENull interaction */
			Vector wo = its.toLocal(ray.d);
			BSDFSamplingRecord bRec(its, -wo, wo, ERadiance);
			bRec.component = BSDF::ENull;
			Float nullPdf = bsdf->pdf(bRec, EDiscrete);
			if (nullPdf == 0) {
				result.release(pool);
				return false;
			}

			PathVertex *vertex = pool.allocVertex();
			vertex->type = PathVertex::ESurfaceInteraction;
			vertex->degenerate = !(bsdf->hasComponent(BSDF::ESmooth)
				|| its.shape->isEmitter() || its.shape->isSensor());
			vertex->measure = EDiscrete;
			vertex->componentType = BSDF::ENull;
			vertex->pdf[EImportance] = vertex->pdf[ERadiance] = nullPdf;
			vertex->weight[EImportance] = vertex->weight[ERadiance]
				= bsdf->eval(bRec, EDiscrete) / nullPdf;
			vertex->rrWeight = 1.0f;
			vertex->getIntersection() = its;
			result.append(vertex);

			if (its.isMediumTransition()) {
				const Medium *expected = its.getTargetMedium(-ray.d);
				if (medium != expected) {
					#if defined(MTS_BD_TRACE)
						SLog(EWarn, "PathEdge::pathConnect(): attempted two connect "
							"two vertices that disagree about the medium in between! "
							"Please check your scene for leaks.");
					#endif
					++mediumInconsistencies;
					result.release(pool);
					return false;
				}
				medium = its.getTargetMedium(ray.d);
			}

			if (++interactions > 100) { /// Just a precaution..
				SLog(EWarn, "pathConnect(): round-off error issues?");
				result.release(pool);
				return false;
			}
		}

		if (medium != vs->getTargetMedium(predEdge, -d)) {
			#if defined(MTS_BD_TRACE)
				SLog(EWarn, "PathEdge::pathConnect(): attempted two connect "
					"two vertices that disagree about the medium in between! "
					"Please check your scene for leaks.");
			#endif
			++mediumInconsistencies;
			result.release(pool);
			return false;
		}
	}

	result.reverse();

	BDAssert(result.edgeCount() == result.vertexCount() + 1);
	BDAssert((int) result.vertexCount() <= maxInteractions || maxInteractions < 0);

	return true;
}