float *renderBlock(const Vector3i &blockIdx) const {
        float *result = new float[m_blockRes*m_blockRes*m_blockRes];
        Point offset = m_aabb.min + Vector(
                           blockIdx.x * m_blockSize * m_voxelWidth,
                           blockIdx.y * m_blockSize * m_voxelWidth,
                           blockIdx.z * m_blockSize * m_voxelWidth);

        int idx = 0;
        bool nonempty = false;
        for (int z = 0; z<m_blockRes; ++z) {
            for (int y = 0; y<m_blockRes; ++y) {
                for (int x = 0; x<m_blockRes; ++x) {
                    Point p = offset + Vector((Float) x, (Float) y, (Float) z) * m_voxelWidth;
                    float value = (float) m_nested->lookupFloat(p);
                    result[idx++] = value;
                    nonempty |= (value != 0);
                }
            }
        }

        ++statsCreate;
        statsEmpty.incrementBase();

        if (nonempty) {
            return result;
        } else {
            ++statsEmpty;
            delete[] result;
            return NULL;
        }
    }
Example #2
0
void VPLShaderManager::drawAllGeometryForVPL(const VPL &vpl, const Sensor *sensor) {
	const Emitter *currentEmitter = NULL;
	const BSDF *currentBSDF = NULL;
	bool currentHasNormals = false;

	m_renderer->setDepthTest(true);

	Matrix4x4 currentObjTrafo;
	currentObjTrafo.setIdentity();
	m_shadowMap->bind(0);

	m_renderer->beginDrawingMeshes();

	size_t nTriangles = 0;
	for (std::vector<Renderer::TransformedGPUGeometry>::const_iterator it = m_geometry.begin();
			it != m_geometry.end(); ++it) {
		const GPUGeometry *geo = (*it).first;
		const Matrix4x4 &trafo = (*it).second;
		const BSDF *bsdf = geo->getTriMesh()->getBSDF();
		const Emitter *emitter = geo->getTriMesh()->getEmitter();
		bool hasNormals = !geo->getTriMesh()->hasVertexNormals();

		nTriangles += geo->getTriMesh()->getTriangleCount();

		if (emitter != currentEmitter || bsdf != currentBSDF || hasNormals != currentHasNormals) {
			currentBSDF = bsdf; currentEmitter = emitter; currentHasNormals = hasNormals;

			if (m_currentProgram.program) {
				m_currentProgram.program->unbind();
				m_currentProgram.program = NULL;
				m_targetConfiguration.unbind();
			}

			bind(vpl, bsdf, sensor, emitter, trafo, hasNormals);
			currentObjTrafo = trafo;
		} else if (trafo != currentObjTrafo) {
			if (m_currentProgram.program)
				m_currentProgram.program->setParameter(
					m_currentProgram.param_instanceTransform, trafo);
			currentObjTrafo = trafo;
		}

		if (m_alpha != 1.0f && sampleTEAFloat((uint32_t)
				(it - m_geometry.begin()), m_vplIndex, 8) > m_alpha)
			continue;

		m_renderer->drawMesh(geo);
	}

	statsMaxTriangles.recordMaximum(nTriangles);

	m_renderer->endDrawingMeshes();
	unbind();
	m_renderer->checkError();
}
Example #3
0
// GridAccel Method Definitions
GridAccel::GridAccel(const vector<Reference<Primitive> > &p,
		bool forRefined, bool refineImmediately)
	: gridForRefined(forRefined) {
	// Initialize _prims_ with primitives for grid
	vector<Reference<Primitive> > prims;
	if (refineImmediately)
		for (u_int i = 0; i < p.size(); ++i)
			p[i]->FullyRefine(prims);
	else
		prims = p;
	// Initialize mailboxes for grid
	nMailboxes = prims.size();
	mailboxes = (MailboxPrim *)AllocAligned(nMailboxes *
		sizeof(MailboxPrim));
	for (u_int i = 0; i < nMailboxes; ++i)
		new (&mailboxes[i]) MailboxPrim(prims[i]);
	// Compute bounds and choose grid resolution
	for (u_int i = 0; i < prims.size(); ++i)
		bounds = Union(bounds, prims[i]->WorldBound());
	Vector delta = bounds.pMax - bounds.pMin;
	// Find _voxelsPerUnitDist_ for grid
	int maxAxis = bounds.MaximumExtent();
	float invMaxWidth = 1.f / delta[maxAxis];
	Assert(invMaxWidth > 0.f); // NOBOOK
	float cubeRoot = 3.f * powf(float(prims.size()), 1.f/3.f);
	float voxelsPerUnitDist = cubeRoot * invMaxWidth;
	for (int axis = 0; axis < 3; ++axis) {
		NVoxels[axis] =
		     Round2Int(delta[axis] * voxelsPerUnitDist);
		NVoxels[axis] = Clamp(NVoxels[axis], 1, 64);
	}
	// Compute voxel widths and allocate voxels
	for (int axis = 0; axis < 3; ++axis) {
		Width[axis] = delta[axis] / NVoxels[axis];
		InvWidth[axis] =
		    (Width[axis] == 0.f) ? 0.f : 1.f / Width[axis];
	}
	int nVoxels = NVoxels[0] * NVoxels[1] * NVoxels[2];
	voxels = (Voxel **)AllocAligned(nVoxels * sizeof(Voxel *));
	memset(voxels, 0, nVoxels * sizeof(Voxel *));
	// Add primitives to grid voxels
	for (u_int i = 0; i < prims.size(); ++i) {
		// Find voxel extent of primitive
		BBox pb = prims[i]->WorldBound();
		int vmin[3], vmax[3];
		for (int axis = 0; axis < 3; ++axis) {
			vmin[axis] = PosToVoxel(pb.pMin, axis);
			vmax[axis] = PosToVoxel(pb.pMax, axis);
		}
		// Add primitive to overlapping voxels
		for (int z = vmin[2]; z <= vmax[2]; ++z)
			for (int y = vmin[1]; y <= vmax[1]; ++y)
				for (int x = vmin[0]; x <= vmax[0]; ++x) {
					int offset = Offset(x, y, z);
					if (!voxels[offset]) {
						// Allocate new voxel and store primitive in it
						voxels[offset] = new (voxelArena) Voxel(&mailboxes[i]);
					}
					else {
						// Add primitive to already-allocated voxel
						voxels[offset]->AddPrimitive(&mailboxes[i]);
					}
				}
		static StatsRatio nPrimitiveVoxels("Grid Accelerator", // NOBOOK
			"Voxels covered vs # / primitives"); // NOBOOK
		nPrimitiveVoxels.Add((1 + vmax[0]-vmin[0]) * (1 + vmax[1]-vmin[1]) * // NOBOOK
			(1 + vmax[2]-vmin[2]), 1); // NOBOOK
	}
	// Update grid statistics
	static StatsPercentage nEmptyVoxels("Grid Accelerator",
	                                    "Empty voxels");
	static StatsRatio avgPrimsInVoxel("Grid Accelerator",
		"Average # of primitives in voxel");
	static StatsCounter maxPrimsInVoxel("Grid Accelerator",
		"Max # of primitives in a grid voxel");
	nEmptyVoxels.Add(0, NVoxels[0] * NVoxels[1] * NVoxels[2]);
	avgPrimsInVoxel.Add(0,NVoxels[0] * NVoxels[1] * NVoxels[2]);
	for (int z = 0; z < NVoxels[2]; ++z)
		for (int y = 0; y < NVoxels[1]; ++y)
			for (int x = 0; x < NVoxels[0]; ++x) {
				int offset = Offset(x, y, z);
				if (!voxels[offset]) nEmptyVoxels.Add(1, 0);
				else {
				    int nPrims = voxels[offset]->nPrimitives;
					maxPrimsInVoxel.Max(nPrims);
					avgPrimsInVoxel.Add(nPrims, 0);
				}
			}
}
Example #4
0
void PBRT_KDTREE_CREATED_LEAF(int nprims, int depth) {
    ++kdTreeLeafNodes;
    kdTreeMaxPrims.Max(nprims);
    kdTreeMaxDepth.Max(depth);
}
Example #5
0
bool CausticPerturbation::sampleMutation(
		Path &source, Path &proposal, MutationRecord &muRec) {
	int k = source.length(), m = k - 1, l = m - 1;

	if (k < 4 || !source.vertex(l)->isConnectable())
		return false;
	--l;

	while (l >= 0 && !source.vertex(l)->isConnectable())
		--l;

	if (l < 1)
		return false;

	muRec = MutationRecord(ECausticPerturbation, l, m, m-l,
		source.getPrefixSuffixWeight(l, m));
	statsAccepted.incrementBase();
	statsGenerated.incrementBase();

	/* 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 woSource = normalize(source.vertex(l+1)->getPosition()
			- source.vertex(l)->getPosition());
	Float phi = m_sampler->next1D() * 2 * M_PI;
	Float theta = theta2 * math::fastexp(m_logRatio * m_sampler->next1D());
	Vector wo = Frame(woSource).toWorld(sphericalDirection(theta, phi));

	/* Allocate memory for the proposed path */
	proposal.clear();
	proposal.append(source, 0, l+1);
	proposal.append(m_pool.allocEdge());
	for (int i=l+1; i<m; ++i) {
		proposal.append(m_pool.allocVertex());
		proposal.append(m_pool.allocEdge());
	}
	proposal.append(source, m, k+1);
	proposal.vertex(l) = proposal.vertex(l)->clone(m_pool);
	proposal.vertex(m) = proposal.vertex(m)->clone(m_pool);
	BDAssert(proposal.vertexCount() == source.vertexCount());
	BDAssert(proposal.edgeCount() == source.edgeCount());

	Float dist = source.edge(l)->length +
		perturbMediumDistance(m_sampler, source.vertex(l+1));

	/* Sample a perturbation and propagate it through specular interactions */
	if (!proposal.vertex(l)->perturbDirection(m_scene,
			proposal.vertex(l-1), proposal.edge(l-1),
			proposal.edge(l), proposal.vertex(l+1), wo, dist,
			source.vertex(l+1)->getType(), EImportance)) {
		proposal.release(l, m+1, m_pool);
		return false;
	}

	Vector woProposal = normalize(proposal.vertex(l+1)->getPosition()
			- source.vertex(l)->getPosition());
	theta = unitAngle(woSource, woProposal);
	if (theta >= theta2 || theta <= theta1) {
		proposal.release(l, m+1, m_pool);
		return false;
	}

	/* If necessary, propagate the perturbation through a sequence of
	   ideally specular interactions */
	for (int i=l+1; i<m-1; ++i) {
		Float dist = source.edge(i)->length +
			perturbMediumDistance(m_sampler, source.vertex(i+1));

		if (!proposal.vertex(i)->propagatePerturbation(m_scene,
				proposal.vertex(i-1), proposal.edge(i-1),
				proposal.edge(i), proposal.vertex(i+1),
				source.vertex(i)->getComponentType(), dist,
				source.vertex(i+1)->getType(), EImportance)) {
			proposal.release(l, m+1, m_pool);
			return false;
		}
	}

	if (!PathVertex::connect(m_scene,
			proposal.vertex(m-2),
			proposal.edge(m-2),
			proposal.vertex(m-1),
			proposal.edge(m-1),
			proposal.vertex(m),
			proposal.edge(m),
			proposal.vertex(m+1))) {
		proposal.release(l, m+1, m_pool);
		return false;
	}

	proposal.vertex(k-1)->updateSamplePosition(
		proposal.vertex(k-2));

	++statsGenerated;
	return true;
}
Example #6
0
bool BidirectionalMutator::sampleMutation(
		Path &source, Path &proposal, MutationRecord &muRec) {
	TwoTailedGeoDistr desiredLength(2), deletionLength(2);
	int k = source.length();

	/* Sample the desired path length of the proposal. This
	   is done using a two-tailed geometric distribution that is
	   centered around the current path length, and which respects
	   the specified minimum and maximum length constraints. */

	desiredLength.configure(k, m_kmin, m_kmax);
	int kPrime = desiredLength.sample(m_sampler->next1D());

	/* Sample the length of the deletion (in # of edges, 1 means
	   no vertices are removed). When kPrime is smaller than k,
	   we must delete at least k-kPrime+1 edges to be able to
	   achieve the desired path length.

	   When k==kPrime, we must delete *something*, or the mutation
	   is trivial, hence the conditional below expression. */

	int minDeletion = std::max((k == kPrime) ? 2 : 1, k-kPrime+1);
	deletionLength.configure(2, minDeletion, k);
	int kd = deletionLength.sample(m_sampler->next1D());

	/* Based on the desired length, this tells us how many
	   edges need to be added (k' = k - kd + ka) */
	int ka = kPrime-k+kd;

	/* Sample the left endpoint of the deleted range */
	int lMin = 0, lMax = k - kd;
	if (kd == 1 || ka == 1) {
		/* This will help to avoid certain path changes that would otherwise
		   always be rejected. Specifically, we don't want to remove the sensor
		   or emitter sample vertex, and we don't want to insert
		   vertices between a sensor/emitter sample and its supernode */
		lMin++; lMax--;
	}
	m_temp.clear();
	for (int l=lMin; l<=lMax; ++l) {
		int m = l+kd;
		if (!source.vertex(l)->isDegenerate() &&
			!source.vertex(m)->isDegenerate())
			m_temp.push_back(l);
	}
	if (m_temp.size() == 0)
		return false;

	int l = m_temp[std::min((int) (m_temp.size() *
			m_sampler->next1D()), (int) m_temp.size()-1)];
	int m = l+kd;

	/* Don't try to hit the emitter or sensor if they are degenerate */
	int sMin = 0, sMax = ka-1;
	if (l == 0 && m_scene->hasDegenerateEmitters())
		++sMin;
	else if (m == k && m_scene->hasDegenerateSensor())
		--sMax;

	/* Sample the number of SIS-type steps to take from the emitter direction */
	int s = std::min(sMin + (int) ((sMax-sMin+1) * m_sampler->next1D()), sMax);
	int t = ka - s - 1;

	/* Check a few assumptions */
	BDAssert(ka >= 1 && kd >= 1 && kd <= k
			&& l >= lMin && l <= lMax
			&& kPrime == k - kd + ka
			&& kPrime >= m_kmin
			&& kPrime <= m_kmax);

	/* Construct a mutation record */
	muRec = MutationRecord(EBidirectionalMutation, l, m, ka,
		source.getPrefixSuffixWeight(l, m));

	/* Keep some statistics */
	statsGenerated.incrementBase();
	statsAccepted.incrementBase();

	proposal.clear();
	proposal.append(source, 0, l+1);
	proposal.vertex(l) = proposal.vertex(l)->clone(m_pool);

	/* Perform a random walk from the emitter direction */
	if (proposal.randomWalk(m_scene, m_sampler, s, -1, EImportance, m_pool) != s) {
		proposal.release(l, proposal.vertexCount(), m_pool);
		return false;
	}

	/* Perform a random walk from the sensor direction */
	m_tempPath.clear();
	m_tempPath.append(source, m, k+1, true);
	m_tempPath.vertex(k-m) = m_tempPath.vertex(k-m)->clone(m_pool);

	if (m_tempPath.randomWalk(m_scene, m_sampler, t, -1, ERadiance, m_pool) != t) {
		proposal.release(l, proposal.vertexCount(), m_pool);
		m_tempPath.release(k-m, m_tempPath.vertexCount(), m_pool);
		return false;
	}

	PathEdge *connectionEdge = m_pool.allocEdge();
	proposal.append(connectionEdge);
	proposal.append(m_tempPath, 0, m_tempPath.vertexCount(), true);

	BDAssert(proposal.length() == kPrime &&
			 proposal.vertexCount() == proposal.edgeCount() + 1);

	const PathVertex
		*vsPred = l+s > 0 ? proposal.vertex(l+s-1) : NULL,
		*vtPred = l+s+2 <= kPrime ? proposal.vertex(l+s+2) : NULL;
	const PathEdge
		*vsEdge = l+s > 0 ? proposal.edge(l+s-1) : NULL,
		*vtEdge = l+s+1 < kPrime ? proposal.edge(l+s+1) : NULL;

	/* Now try to connect the two subpaths and reject
	   the proposal if there is no throughput */
	PathVertex *vs = proposal.vertex(l+s),
			   *vt = proposal.vertex(l+s+1);

	if (!PathVertex::connect(m_scene, vsPred,
			vsEdge, vs, connectionEdge, vt, vtEdge, vtPred)) {
		proposal.release(l, l+ka+1, m_pool);
		return false;
	}

	if (m >= k-1)
		proposal.vertex(kPrime-1)->updateSamplePosition(
			proposal.vertex(kPrime-2));

	++statsGenerated;
	return true;
}