예제 #1
0
Float BidirectionalMutator::Q(const Path &source, const Path &proposal,
		const MutationRecord &muRec) const {
	const int k = source.length(), l = muRec.l,
		      m = muRec.m, ka = muRec.ka, mPrime = l+ka;

	Spectrum *importanceWeights = (Spectrum *) alloca(ka * sizeof(Spectrum)),
			 *radianceWeights  = (Spectrum *) alloca(ka * sizeof(Spectrum));

	/* Compute importance transport weights along the subpath */
	importanceWeights[0] = Spectrum(1.0f);
	for (int s=1; s<ka; ++s)
		importanceWeights[s] = importanceWeights[s-1] *
			proposal.vertex(l+s-1)->weight[EImportance] *
			proposal.edge(l+s-1)->weight[EImportance];

	/* Compute radiance transport weights along the subpath */
	radianceWeights[0] = Spectrum(1.0f);
	for (int t=1; t<ka; ++t)
		radianceWeights[t] = radianceWeights[t-1] *
			proposal.vertex(mPrime-t+1)->weight[ERadiance] *
			proposal.edge(mPrime-t)->weight[ERadiance];

	int sMin = 0, sMax = ka-1;
	if (l == 0 && m_scene->hasDegenerateEmitters())
		++sMin;
	else if (m == k && m_scene->hasDegenerateSensor())
		--sMax;

	Float result = 0.0f;
	for (int s = sMin; s <= sMax; ++s) {
		const PathEdge *edge = proposal.edge(l+s);
		const PathVertex *vs = proposal.vertex(l+s),
			  *vt = proposal.vertex(l+s+1);
		int t = ka - s - 1;

		/* Cannot connect endpoints with degenerate distributions */
		if (!vs->isConnectable() || !vt->isConnectable())
			continue;

		Spectrum weight = importanceWeights[s]
			* radianceWeights[t]
			* edge->evalCached(vs, vt, PathEdge::EEverything)
			* muRec.weight;

		Float luminance = weight.getLuminance();

		if (luminance <= 0 || !std::isfinite(luminance)) {
			Log(EWarn, "Internal error: luminance = %f!", luminance);
			continue;
		}

		result += 1 / luminance;
	}

	return result * pmfMutation(source, muRec);
}
예제 #2
0
Float CausticPerturbation::Q(const Path &source, const Path &proposal,
		const MutationRecord &muRec) const {
	int m = muRec.m, l = muRec.l;

	/* Heuristic perturbation size computation (Veach, p.354) */
	Float lengthE = source.edge(m-1)->length;
	Float lengthL = 0;
	for (int i=l; i<m-1; ++i)
		lengthL += source.edge(i)->length;
	Float factor = lengthE/lengthL,
		theta1 = m_theta1 * factor,
		theta2 = m_theta2 * factor;

	Vector d1 = normalize(source.vertex(l+1)->getPosition()   - source.vertex(l)->getPosition());
	Vector d2 = normalize(proposal.vertex(l+1)->getPosition() - source.vertex(l)->getPosition());
	Float theta = unitAngle(d1, d2);
	if (theta >= theta2 || theta <= theta1)
		return 0.0f;

	Float solidAngleDensity = 1.0f / (2*M_PI * -m_logRatio * std::sin(theta) * theta);

	Spectrum weight = muRec.weight * proposal.edge(m-1)->evalCached(
		proposal.vertex(m-1), proposal.vertex(m), PathEdge::EEverything);

	for (int i=l; i<m-1; ++i) {
		const PathVertex *v0 = proposal.vertex(i),
			  *v1 = proposal.vertex(i+1);
		const PathEdge *edge = proposal.edge(i);

		weight *= edge->evalCached(v0, v1,
			PathEdge::ETransmittance | PathEdge::EValueCosineImp);

		if (v1->isMediumInteraction())
			weight /= pdfMediumPerturbation(source.vertex(i+1),
					source.edge(i), edge);
	}

	return solidAngleDensity / weight.getLuminance();
}