From 57d13dfe7bb28805f185ff69ec84a3622436d11e Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Fri, 12 Nov 2010 03:15:32 +0100 Subject: [PATCH] partial support for geometry instancing --- SConstruct | 3 +- include/mitsuba/render/fwd.h | 1 + include/mitsuba/render/kdtree.h | 1 + schema/scene.xsd | 1 + src/shapes/instance.cpp | 124 ++++++++++++++++++++++++++++++++ src/shapes/shapegroup.cpp | 86 ++++++++++++++++++++++ src/shapes/shapegroup.h | 67 +++++++++++++++++ 7 files changed, 282 insertions(+), 1 deletion(-) create mode 100644 src/shapes/instance.cpp create mode 100644 src/shapes/shapegroup.cpp create mode 100644 src/shapes/shapegroup.h diff --git a/SConstruct b/SConstruct index e4e43dd3..0817a38c 100644 --- a/SConstruct +++ b/SConstruct @@ -530,7 +530,8 @@ plugins += env.SharedLibrary('plugins/serialized', ['src/shapes/serialized.cpp'] plugins += env.SharedLibrary('plugins/sphere', ['src/shapes/sphere.cpp']) plugins += env.SharedLibrary('plugins/cylinder', ['src/shapes/cylinder.cpp']) plugins += env.SharedLibrary('plugins/hair', ['src/shapes/hair.cpp']) -#plugins += env.SharedLibrary('plugins/group', ['src/shapes/group.cpp']) +plugins += env.SharedLibrary('plugins/shapegroup', ['src/shapes/shapegroup.cpp']) +plugins += env.SharedLibrary('plugins/instance', ['src/shapes/instance.cpp']) # Samplers plugins += env.SharedLibrary('plugins/independent', ['src/samplers/independent.cpp']) diff --git a/include/mitsuba/render/fwd.h b/include/mitsuba/render/fwd.h index 3a1431d3..659b99eb 100644 --- a/include/mitsuba/render/fwd.h +++ b/include/mitsuba/render/fwd.h @@ -34,6 +34,7 @@ class GatherPhotonProcess; class HemisphereSampler; class HWResource; class ImageBlock; +class Instanced; class Integrator; struct Intersection; class IrradianceCache; diff --git a/include/mitsuba/render/kdtree.h b/include/mitsuba/render/kdtree.h index c6ea91b6..a7004a5e 100644 --- a/include/mitsuba/render/kdtree.h +++ b/include/mitsuba/render/kdtree.h @@ -63,6 +63,7 @@ MTS_NAMESPACE_BEGIN */ class MTS_EXPORT_RENDER KDTree : public GenericKDTree { friend class GenericKDTree; + friend class Instance; public: /// Create an empty kd-tree KDTree(); diff --git a/schema/scene.xsd b/schema/scene.xsd index 33b92dff..eb22d6e0 100644 --- a/schema/scene.xsd +++ b/schema/scene.xsd @@ -101,6 +101,7 @@ + diff --git a/src/shapes/instance.cpp b/src/shapes/instance.cpp new file mode 100644 index 00000000..ad63f45b --- /dev/null +++ b/src/shapes/instance.cpp @@ -0,0 +1,124 @@ +/* + 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 "shapegroup.h" + +MTS_NAMESPACE_BEGIN + +class Instance : public Shape { +public: + Instance(const Properties &props) : Shape(props) { + m_objectToWorld = props.getTransform("toWorld", Transform()); + m_worldToObject = m_objectToWorld.inverse(); + } + + Instance(Stream *stream, InstanceManager *manager) + : Shape(stream, manager) { + m_shapeGroup = static_cast(manager->getInstance(stream)); + m_objectToWorld = Transform(stream); + m_worldToObject = m_objectToWorld.inverse(); + } + + void serialize(Stream *stream, InstanceManager *manager) const { + Shape::serialize(stream, manager); + m_objectToWorld.serialize(stream); + manager->serialize(stream, m_shapeGroup.get()); + } + + void configure() { + if (!m_shapeGroup) + Log(EError, "A reference to a 'shapegroup' must be specified!"); + } + + AABB getAABB() const { + const KDTree *kdtree = m_shapeGroup->getKDTree(); + const AABB &aabb = kdtree->getAABB(); + AABB result; + for (int i=0; i<8; ++i) + result.expandBy(m_objectToWorld(aabb.getCorner(i))); + return result; + } + + Float getSurfaceArea() const { + Log(EError, "Instance::getSurfaceArea(): not supported!"); + return 0.0f; + } + + void addChild(const std::string &name, ConfigurableObject *child) { + const Class *cClass = child->getClass(); + if (cClass->getName() == "ShapeGroup") { + m_shapeGroup = static_cast(child); + } else { + Shape::addChild(name, child); + } + } + + bool rayIntersect(const Ray &_ray, Float _mint, + Float _maxt, Float &t, void *temp) const { + const KDTree *kdtree = m_shapeGroup->getKDTree(); + Ray ray; + m_worldToObject(_ray, ray); + Float mint, maxt, tempT = std::numeric_limits::infinity(); + + if (kdtree->m_aabb.rayIntersect(ray, mint, maxt)) { + if (_mint > mint) mint = _mint; + if (_maxt < maxt) maxt = _maxt; + + if (EXPECT_TAKEN(maxt > mint)) { + if (kdtree->rayIntersectHavran(ray, mint, maxt, tempT, temp)) { + t = tempT; + return true; + } + } + } + return false; + } + + bool rayIntersect(const Ray &_ray, Float _mint, Float _maxt) const { + const KDTree *kdtree = m_shapeGroup->getKDTree(); + Ray ray; + m_worldToObject(_ray, ray); + Float mint, maxt, tempT = std::numeric_limits::infinity(); + + if (kdtree->m_aabb.rayIntersect(ray, mint, maxt)) { + if (_mint > mint) mint = _mint; + if (_maxt < maxt) maxt = _maxt; + + if (EXPECT_TAKEN(maxt > mint)) { + if (kdtree->rayIntersectHavran(ray, mint, maxt, tempT, NULL)) + return true; + } + } + return false; + } + + void fillIntersectionRecord(const Ray &ray, Float t, + const void *temp, Intersection &its) const { + const KDTree *kdtree = m_shapeGroup->getKDTree(); + Log(EError, "fillIntersectionRecord(): Unsupported!"); + } + + MTS_DECLARE_CLASS() +private: + ref m_shapeGroup; + Transform m_objectToWorld, m_worldToObject; +}; + +MTS_IMPLEMENT_CLASS_S(Instance, false, Shape) +MTS_EXPORT_PLUGIN(Instance, "Instanced geometry"); +MTS_NAMESPACE_END diff --git a/src/shapes/shapegroup.cpp b/src/shapes/shapegroup.cpp new file mode 100644 index 00000000..2fe50646 --- /dev/null +++ b/src/shapes/shapegroup.cpp @@ -0,0 +1,86 @@ +/* + 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 "shapegroup.h" + +MTS_NAMESPACE_BEGIN + +ShapeGroup::ShapeGroup(const Properties &props) : Shape(props) { + m_kdtree = new KDTree(); +} + +ShapeGroup::ShapeGroup(Stream *stream, InstanceManager *manager) + : Shape(stream, manager) { + m_kdtree = new KDTree(); + size_t shapeCount = stream->readUInt(); + for (size_t i=0; iaddShape(static_cast(manager->getInstance(stream))); + configure(); +} + +void ShapeGroup::serialize(Stream *stream, InstanceManager *manager) const { + Shape::serialize(stream, manager); + const std::vector &shapes = m_kdtree->getShapes(); + stream->writeUInt((uint32_t) shapes.size()); + for (size_t i=0; iserialize(stream, shapes[i]); +} + +void ShapeGroup::configure() { + if (!m_kdtree->isBuilt()) + m_kdtree->build(); +} + +AABB ShapeGroup::getAABB() const { + return AABB(); +} + +Float ShapeGroup::getSurfaceArea() const { + return 0.0f; +} + +void ShapeGroup::addChild(const std::string &name, ConfigurableObject *child) { + const Class *cClass = child->getClass(); + if (cClass->derivesFrom(ShapeGroup::m_theClass) || cClass->getName() == "ShapeInstance") { + Log(EError, "Nested instancing is not supported!"); + } else if (cClass->derivesFrom(Shape::m_theClass)) { + Shape *shape = static_cast(child); + if (shape->isCompound()) { + int index = 0; + do { + ref element = shape->getElement(index++); + if (element == NULL) + break; + addChild("", element); + } while (true); + } else { + m_kdtree->addShape(shape); + } + } else { + Shape::addChild(name, child); + } +} + +bool ShapeGroup::isCompound() const { + // this shape reduces to nothing (compound, no children) + return true; +} + +MTS_IMPLEMENT_CLASS_S(ShapeGroup, false, Shape) +MTS_EXPORT_PLUGIN(ShapeGroup, "Grouped geometry for instancing"); +MTS_NAMESPACE_END diff --git a/src/shapes/shapegroup.h b/src/shapes/shapegroup.h new file mode 100644 index 00000000..a304701e --- /dev/null +++ b/src/shapes/shapegroup.h @@ -0,0 +1,67 @@ +/* + 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 +#include +#include +#include + +MTS_NAMESPACE_BEGIN + +/** + * \brief "Fake" shape that groups sub-shapes into a + * separate KD-tree. When this shape is used by itself, + * it doesn't actually generate any intersectable geometry. + * Instead, the "instance" plugin must be used to create + * references to the geometry stored inside it. + */ +class ShapeGroup : public Shape { +public: + /// Create a new shape group + ShapeGroup(const Properties &props); + + /// Unserialize from a binary data stream + ShapeGroup(Stream *stream, InstanceManager *manager); + + /// Serialize to a binary data stream + void serialize(Stream *stream, InstanceManager *manager) const; + + /// Build the internal KD-tree + void configure(); + + /// Add a child object + void addChild(const std::string &name, ConfigurableObject *child); + + /// Return whether or not the shape is a compound object + bool isCompound() const; + + /// Returns an invalid AABB + AABB getAABB() const; + + /// Returns the surface area + Float getSurfaceArea() const; + + /// Return a pointer to the internal KD-tree + inline const KDTree *getKDTree() const { return m_kdtree.get(); } + + MTS_DECLARE_CLASS() +private: + ref m_kdtree; +}; + +MTS_NAMESPACE_END