135 lines
3.9 KiB
C++
135 lines
3.9 KiB
C++
#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; i<numSamples; ++i)
|
|
addSample(IrradianceSample(stream));
|
|
preprocess();
|
|
}
|
|
|
|
IrradianceOctree::~IrradianceOctree() {
|
|
delete m_root;
|
|
}
|
|
|
|
void IrradianceOctree::serialize(Stream *stream, InstanceManager *manager) const {
|
|
m_root->aabb.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<IrradianceSample> 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
|