/* This file is part of Mitsuba, a physically based rendering system. Copyright (c) 2007-2010 by Wenzel Jakob and others. Mitsuba is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License Version 3 as published by the Free Software Foundation. Mitsuba is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "irrtree.h" MTS_NAMESPACE_BEGIN IrradianceOctree::IrradianceOctree(int maxDepth, Float threshold, const AABB &bounds) : m_maxDepth(maxDepth), m_threshold(threshold) { m_root = new OctreeNode(bounds); m_numSamples = 0; } IrradianceOctree::IrradianceOctree(Stream *stream, InstanceManager *manager) : SerializableObject(stream, manager) { m_root = new OctreeNode(AABB(stream)); m_threshold = stream->readFloat(); m_maxDepth = stream->readInt(); m_numSamples = 0; unsigned int numSamples = stream->readUInt(); for (unsigned int i=0; iaabb.serialize(stream); stream->writeFloat(m_threshold); stream->writeInt(m_maxDepth); stream->writeUInt(m_numSamples); m_root->serialize(stream); } void IrradianceOctree::addSample(const IrradianceSample &sample) { static StatsCounter numSamples("SSS IrradianceOctree", "Number of samples"); ++numSamples; ++m_numSamples; if (!sample.E.isValid()) Log(EWarn, "Invalid sample: %s", sample.E.toString().c_str()); else addSample(m_root, sample, 0); } void IrradianceOctree::dumpOBJ(const std::string &filename) const { std::ofstream os(filename.c_str()); os << "o IrrSamples" << endl; m_root->dumpOBJ(os); /// Need to generate some fake geometry so that blender will import the points for (unsigned int i=3; i<=m_numSamples; i++) os << "f " << i << " " << i-1 << " " << i-2 << endl; os.close(); } void IrradianceOctree::addSample(OctreeNode *node, const IrradianceSample &sample, int depth) { static StatsCounter nodesCreated("SSS IrradianceOctree", "Number of created nodes"); node->samples.push_back(sample); if (node->leaf && (m_maxDepth == depth || node->samples.size() < 8)) return; node->leaf = false; for (sample_iterator it = node->samples.begin(); it != node->samples.end(); ++it) { const IrradianceSample &s = *it; Point midPoint = node->aabb.getMidPoint(); int nodeId = (s.p.x > midPoint.x ? 1 : 0) + (s.p.y > midPoint.y ? 2 : 0) + (s.p.z > midPoint.z ? 4 : 0); if (!node->children[nodeId]) { AABB childAABB(midPoint, midPoint); childAABB.expandBy(node->aabb.getCorner(nodeId)); node->children[nodeId] = new OctreeNode(childAABB); ++nodesCreated; } addSample(node->children[nodeId], s, depth + 1); } std::vector empty; node->samples.swap(empty); } void IrradianceOctree::preprocess(OctreeNode *node) { /* Initialize the cluster values */ node->cluster.E = Spectrum(0.0f); node->cluster.area = 0.0f; node->cluster.p = Point(0.0f, 0.0f, 0.0f); Float combinedWeight = 0.0f; if (!node->samples.empty()) { /* Leaf node */ for (sample_iterator it = node->samples.begin(); it != node->samples.end(); ++it) { const IrradianceSample &sample = *it; node->cluster.E += sample.E * sample.area; node->cluster.area += sample.area; Float pointWeight = sample.E.average() * sample.area; node->cluster.p += sample.p * pointWeight; combinedWeight += pointWeight; } node->cluster.E /= node->cluster.area; if (combinedWeight != 0) node->cluster.p /= combinedWeight; } else { int numChildren = 0; /* Inner node */ for (int i=0; i<8; i++) { OctreeNode *child = node->children[i]; if (!child) continue; numChildren++; preprocess(child); /* Point repulsion not used, weight everything by area */ node->cluster.E += child->cluster.E * child->cluster.area; node->cluster.area += child->cluster.area; Float pointWeight = child->cluster.E.average() * child->cluster.area; node->cluster.p += child->cluster.p * pointWeight; combinedWeight += pointWeight; } if (combinedWeight != 0) node->cluster.p /= combinedWeight; if (node->cluster.area != 0) node->cluster.E /= node->cluster.area; } } MTS_IMPLEMENT_CLASS_S(IrradianceOctree, false, SerializableObject) MTS_NAMESPACE_END