miscellaneous bugfixes

metadata
Wenzel Jakob 2010-11-21 02:50:15 +01:00
parent 221e063330
commit d631da2187
13 changed files with 112 additions and 338 deletions

View File

@ -148,7 +148,7 @@ class RENDERENGINE_mitsuba(bpy.types.RenderEngine, engine_base):
adj.exportMaterial(pm) adj.exportMaterial(pm)
adj.exportPreviewMesh(pm) adj.exportPreviewMesh(pm)
adj.writeFooter() adj.writeFooter()
(mts_path, tail) = os.path.split(bpy.path.abspath(scene.mitsuba_engine.binary_path)) mts_path = scene.mitsuba_engine.binary_path
mitsuba_binary = os.path.join(mts_path, "mitsuba") mitsuba_binary = os.path.join(mts_path, "mitsuba")
env = copy.copy(os.environ) env = copy.copy(os.environ)
mts_render_libpath = os.path.join(mts_path, "src/librender") mts_render_libpath = os.path.join(mts_path, "src/librender")
@ -238,7 +238,7 @@ class RENDERENGINE_mitsuba(bpy.types.RenderEngine, engine_base):
return return
if scene.mitsuba_engine.export_mode == 'render': if scene.mitsuba_engine.export_mode == 'render':
(mts_path, tail) = os.path.split(bpy.path.abspath(scene.mitsuba_engine.binary_path)) mts_path = scene.mitsuba_engine.binary_path
mtsgui_binary = os.path.join(mts_path, "mtsgui") mtsgui_binary = os.path.join(mts_path, "mtsgui")
mitsuba_binary = os.path.join(mts_path, "mitsuba") mitsuba_binary = os.path.join(mts_path, "mitsuba")
env = copy.copy(os.environ) env = copy.copy(os.environ)

View File

@ -171,7 +171,7 @@ class EXPORT_OT_mitsuba(bpy.types.Operator):
self.report({'ERROR'}, 'Mitsuba binary path must be specified!') self.report({'ERROR'}, 'Mitsuba binary path must be specified!')
return {'CANCELLED'} return {'CANCELLED'}
(mts_path, tail) = os.path.split(bpy.path.abspath(scene.mitsuba_engine.binary_path)) mts_path = scene.mitsuba_engine.binary_path
mtsimport_binary = os.path.join(mts_path, "mtsimport") mtsimport_binary = os.path.join(mts_path, "mtsimport")
env = copy.copy(os.environ) env = copy.copy(os.environ)
mts_render_libpath = os.path.join(mts_path, "src/librender") mts_render_libpath = os.path.join(mts_path, "src/librender")

View File

@ -1,228 +0,0 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program 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, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
import bpy
class MitsubaCheckOp(bpy.types.Operator):
bl_idname = 'mts.check'
bl_label = 'Check scene'
def reportWarning(self, msg):
self.report({'WARNING'}, msg)
print("MtsBlend: %s" % msg)
def _check_lamp(self, lamp):
hasErrors = False
if lamp.type == 'POINT' and lamp.falloff_type != 'INVERSE_SQUARE':
self.reportWarning('Point light "%s" needs to have inverse square falloff' % lamp.name)
hasErrors = True
if hasErrors:
self.reportWarning('Encountered one or more problems -- check the console')
else:
self.report({'INFO'}, "No problems found")
def execute(self, context):
scene = bpy.data.scenes[0]
for obj in scene.objects:
if obj.type == 'LAMP':
self._check_lamp(obj.data)
return {'FINISHED'}
# Basic Mitsuba integration based on the POV-Ray add-on
# Piggybacks on the COLLADA exporter to get most things done
class MitsubaRender(bpy.types.RenderEngine):
bl_idname = 'MITSUBA_RENDER'
bl_label = "Mitsuba"
def _export_worldtrafo(self, adjfile, trafo):
adjfile.write('\t\t<transform name="toWorld">\n')
adjfile.write('\t\t\t<matrix value="')
for j in range(0,4):
for i in range(0,4):
adjfile.write("%f " % trafo[i][j])
adjfile.write('"/>\n\t\t</transform>\n')
def _export_lamp(self, adjfile, lamp, idx):
if lamp.data.type == 'POINT':
adjfile.write('\t<luminaire id="%s-light" type="point">\n' % lamp.data.name)
mult = lamp.data.energy * lamp.data.distance * lamp.data.distance / 2
self._export_worldtrafo(adjfile, lamp.matrix_world)
adjfile.write('\t\t<rgb name="intensity" value="%f %f %f"/>\n'
% (lamp.data.color.r*mult, lamp.data.color.g*mult, lamp.data.color.b*mult))
adjfile.write('\t</luminaire>\n')
elif lamp.data.type == 'AREA':
adjfile.write('\t<shape type="obj">\n')
size_x = lamp.data.size
size_y = lamp.data.size
if lamp.data.shape == 'RECTANGLE':
size_y = lamp.data.size_y
path = os.path.join(os.path.join(self._temp_dir, 'meshes'), "_area_luminaire_%d.obj" % idx)
adjfile.write('\t\t<string name="filename" value="%s"/>\n' % path)
self._export_worldtrafo(adjfile, lamp.matrix_world)
adjfile.write('\n\t\t<luminaire id="%s-light" type="area">\n' % lamp.data.name)
mult = lamp.data.energy * lamp.data.distance * lamp.data.distance / (size_x * size_y)
adjfile.write('\t\t\t<rgb name="intensity" value="%f %f %f"/>\n'
% (lamp.data.color.r*mult, lamp.data.color.g*mult, lamp.data.color.b*mult))
adjfile.write('\t\t</luminaire>\n')
adjfile.write('\t</shape>\n')
objFile = open(path, 'w')
objFile.write('v %f %f 0\n' % (-size_x/2, -size_y/2))
objFile.write('v %f %f 0\n' % ( size_x/2, -size_y/2))
objFile.write('v %f %f 0\n' % ( size_x/2, size_y/2))
objFile.write('v %f %f 0\n' % (-size_x/2, size_y/2))
objFile.write('f 4 3 2 1\n')
objFile.close()
def _export(self, scene):
import tempfile
self._temp_dir = tempfile.mkdtemp(prefix='mitsuba_');
self._temp_dae = os.path.join(self._temp_dir, 'scene.dae')
self._temp_xml = os.path.join(self._temp_dir, 'scene.xml')
self._temp_adj = os.path.join(self._temp_dir, 'scene_adjustments.xml')
self._temp_out = os.path.join(self._temp_dir, 'scene.png')
os.mkdir(os.path.join(self._temp_dir, 'meshes'))
print("MtsBlend: Writing COLLADA file")
while True:
try:
bpy.ops.wm.collada_export(filepath=self._temp_dae, check_existing=False)
break
except SystemError:
# Weird SystemError (Operator bpy.ops.wm.collada_export.poll()
# failed, context is incorrect) -> try again
print("MtsBlend: Retrying")
time.sleep(0.1)
print("MtsBlend: Writing adjustments file")
adjfile = open(self._temp_adj, 'w')
adjfile.write('<adjustments>\n');
idx = 0
for obj in scene.objects:
if obj.type == 'LAMP':
self._export_lamp(adjfile, obj, idx)
idx = idx+1
adjfile.write('</adjustments>\n');
adjfile.close()
def _render(self):
scene = bpy.data.scenes[0]
(mts_path, tail) = os.path.split(bpy.path.abspath(scene.mts_path))
mtsimport_binary = os.path.join(mts_path, "mtsimport")
mitsuba_binary = os.path.join(mts_path, "mitsuba")
mts_render_libpath = os.path.join(mts_path, "src/librender")
mts_core_libpath = os.path.join(mts_path, "src/libcore")
mts_hw_libpath = os.path.join(mts_path, "src/libhw")
env = copy.copy(os.environ)
env['LD_LIBRARY_PATH'] = mts_core_libpath + ":" + mts_render_libpath + ":" + mts_hw_libpath
render = scene.render
width = int(render.resolution_x * render.resolution_percentage * 0.01)
height = int(render.resolution_y * render.resolution_percentage * 0.01)
try:
print("MtsBlend: Launching mtsimport")
process = subprocess.Popen(
[mtsimport_binary, '-s', '-r', '%dx%d' % (width, height),
'-l', 'pngfilm',
self._temp_dae, self._temp_xml,
self._temp_adj],
env = env,
cwd = self._temp_dir
)
if process.wait() != 0:
print("MtsBlend: mtsimport returned with a nonzero status")
return False
self._process = subprocess.Popen(
[mitsuba_binary, self._temp_xml, '-o', self._temp_out],
env = env,
cwd = self._temp_dir
)
except OSError:
print("MtsBlend: Could not execute '%s', possibly Mitsuba isn't installed" % mtsimport_binary)
return False
return True
def _cleanup(self):
print("Not cleaning up")
#shutil.rmtree(self._temp_dir)
def render(self, scene):
self._export(scene)
if not self._render():
self.update_stats("", "MtsBlend: Unable to render (please check the console)")
return
r = scene.render
x = int(r.resolution_x * r.resolution_percentage * 0.01)
y = int(r.resolution_y * r.resolution_percentage * 0.01)
DELAY = 0.02
# Wait for the file to be created
while not os.path.exists(self._temp_out):
if self.test_break():
try:
self._process.terminate()
except:
pass
break
if self._process.poll() != None:
self.update_stats("", "MtsBlend: Failed to render (check console)")
break
time.sleep(DELAY)
if os.path.exists(self._temp_out):
self.update_stats("", "MtsBlend: Rendering")
prev_size = -1
def update_image():
result = self.begin_result(0, 0, x, y)
layer = result.layers[0]
try:
print("Loading %s" % self._temp_out)
layer.load_from_file(self._temp_out)
except:
pass
self.end_result(result)
while True:
if self._process.poll() is not None:
update_image()
break
if self.test_break():
try:
self._process.terminate()
except:
pass
break
new_size = os.path.getsize(self._temp_out)
if new_size != prev_size:
update_image()
prev_size = new_size
time.sleep(DELAY)
self._cleanup()

View File

@ -62,6 +62,8 @@ class engine(render_described_context, bpy.types.Panel):
binary_path = context.scene.mitsuba_engine.binary_path binary_path = context.scene.mitsuba_engine.binary_path
if binary_path != "" and cached_binary_path != binary_path: if binary_path != "" and cached_binary_path != binary_path:
binary_path = os.path.abspath(efutil.filesystem_path(binary_path)) binary_path = os.path.abspath(efutil.filesystem_path(binary_path))
if os.path.isfile(binary_path):
(binary_path, tail) = os.path.split(binary_path)
actualChange = cached_binary_path != None actualChange = cached_binary_path != None
cached_binary_path = binary_path cached_binary_path = binary_path
context.scene.mitsuba_engine.binary_path = binary_path context.scene.mitsuba_engine.binary_path = binary_path

8
doc/blender.tex Normal file
View File

@ -0,0 +1,8 @@
\section{Blender integration}
% List of things to explain
\subsection{Installing on OSX}
On Mac OS, either copy or symlink the plugin directory (\code{data/blender/mitsuba}) into the appropriate place of the
Blender application bundle (e.g. \code{blender.app/Contents/MacOS/}\textbf{<BLENDER VERSION>}\code{/scripts/addons/mitsuba}).
When specifying the Mitsuba executable path, note that you must again provide
the path to the binary within the application bundle, e.g. \code{/Applications/Mitsuba.app/Contents/MacOS/mitsuba}

View File

@ -45,7 +45,7 @@ class Instanced;
class Integrator; class Integrator;
struct Intersection; struct Intersection;
class IrradianceCache; class IrradianceCache;
template <typename AABBType> class AbstractKDTree; template <typename AABBType> class KDTreeBase;
template <typename AABBType, typename Derived> class GenericKDTree; template <typename AABBType, typename Derived> class GenericKDTree;
class KDTree; class KDTree;
class LocalWorker; class LocalWorker;

View File

@ -46,8 +46,8 @@
//#define MTS_KD_MAILBOX_MASK (MTS_KD_MAILBOX_SIZE-1) //#define MTS_KD_MAILBOX_MASK (MTS_KD_MAILBOX_SIZE-1)
#if defined(MTS_KD_DEBUG) #if defined(MTS_KD_DEBUG)
#define KDAssert(expr) Assert(expr) #define KDAssert(expr) SAssert(expr)
#define KDAssertEx(expr, text) AssertEx(expr, text) #define KDAssertEx(expr, text) SAssertEx(expr, text)
#else #else
#define KDAssert(expr) #define KDAssert(expr)
#define KDAssertEx(expr, text) #define KDAssertEx(expr, text)
@ -433,7 +433,7 @@ private:
* This class defines the byte layout for KD-tree nodes and * This class defines the byte layout for KD-tree nodes and
* provides methods for querying the tree structure. * provides methods for querying the tree structure.
*/ */
template <typename AABBType> class AbstractKDTree : public Object { template <typename AABBType> class KDTreeBase : public Object {
public: public:
/// Index number format (max 2^32 prims) /// Index number format (max 2^32 prims)
typedef uint32_t index_type; typedef uint32_t index_type;
@ -616,7 +616,7 @@ public:
MTS_DECLARE_CLASS() MTS_DECLARE_CLASS()
protected: protected:
virtual ~AbstractKDTree() { } virtual ~KDTreeBase() { }
protected: protected:
KDNode *m_nodes; KDNode *m_nodes;
AABBType m_aabb, m_tightAABB; AABBType m_aabb, m_tightAABB;
@ -629,6 +629,9 @@ protected:
#pragma float_control(precise, on) #pragma float_control(precise, on)
#endif #endif
#define KDLog(level, fmt, ...) Thread::getThread()->getLogger()->log(level, KDTreeBase<AABB>::m_theClass, \
__FILE__, __LINE__, fmt, ## __VA_ARGS__)
/** /**
* \brief SAH KD-tree acceleration data structure for fast ray-object * \brief SAH KD-tree acceleration data structure for fast ray-object
* intersection computations. * intersection computations.
@ -680,7 +683,7 @@ protected:
* \author Wenzel Jakob * \author Wenzel Jakob
*/ */
template <typename AABBType, typename Derived> template <typename AABBType, typename Derived>
class GenericKDTree : public AbstractKDTree<AABBType> { class GenericKDTree : public KDTreeBase<AABBType> {
protected: protected:
// Some forward declarations // Some forward declarations
struct MinMaxBins; struct MinMaxBins;
@ -688,9 +691,9 @@ protected:
struct EdgeEventOrdering; struct EdgeEventOrdering;
public: public:
typedef typename AbstractKDTree<AABBType>::size_type size_type; typedef typename KDTreeBase<AABBType>::size_type size_type;
typedef typename AbstractKDTree<AABBType>::index_type index_type; typedef typename KDTreeBase<AABBType>::index_type index_type;
typedef typename AbstractKDTree<AABBType>::KDNode KDNode; typedef typename KDTreeBase<AABBType>::KDNode KDNode;
typedef typename AABBType::value_type value_type; typedef typename AABBType::value_type value_type;
typedef typename AABBType::point_type point_type; typedef typename AABBType::point_type point_type;
typedef typename AABBType::vector_type vector_type; typedef typename AABBType::vector_type vector_type;
@ -918,8 +921,6 @@ public:
* and fitting the SAH cost model to the collected statistics. * and fitting the SAH cost model to the collected statistics.
*/ */
void findCosts(Float &traversalCost, Float &intersectionCost); void findCosts(Float &traversalCost, Float &intersectionCost);
MTS_DECLARE_CLASS()
protected: protected:
/** /**
* \brief Build a KD-tree over the supplied geometry * \brief Build a KD-tree over the supplied geometry
@ -929,23 +930,23 @@ protected:
void buildInternal() { void buildInternal() {
/* Some samity checks */ /* Some samity checks */
if (this->isBuilt()) if (this->isBuilt())
Log(EError, "The kd-tree has already been built!"); KDLog(EError, "The kd-tree has already been built!");
if (m_traversalCost <= 0) if (m_traversalCost <= 0)
Log(EError, "The traveral cost must be > 0"); KDLog(EError, "The traveral cost must be > 0");
if (m_intersectionCost <= 0) if (m_intersectionCost <= 0)
Log(EError, "The intersection cost must be > 0"); KDLog(EError, "The intersection cost must be > 0");
if (m_emptySpaceBonus <= 0 || m_emptySpaceBonus > 1) if (m_emptySpaceBonus <= 0 || m_emptySpaceBonus > 1)
Log(EError, "The empty space bonus must be in [0, 1]"); KDLog(EError, "The empty space bonus must be in [0, 1]");
if (m_stopPrims < 0) if (m_stopPrims < 0)
Log(EError, "The stopping primitive count must be >= 0"); KDLog(EError, "The stopping primitive count must be >= 0");
if (m_exactPrimThreshold < 0) if (m_exactPrimThreshold < 0)
Log(EError, "The exact primitive threshold must be >= 0"); KDLog(EError, "The exact primitive threshold must be >= 0");
if (m_minMaxBins <= 1) if (m_minMaxBins <= 1)
Log(EError, "The number of min-max bins must be > 2"); KDLog(EError, "The number of min-max bins must be > 2");
size_type primCount = cast()->getPrimitiveCount(); size_type primCount = cast()->getPrimitiveCount();
if (primCount == 0) { if (primCount == 0) {
Log(EWarn, "kd-tree contains no geometry!"); KDLog(EWarn, "kd-tree contains no geometry!");
// +1 shift is for alignment purposes (see KDNode::getSibling) // +1 shift is for alignment purposes (see KDNode::getSibling)
this->m_nodes = static_cast<KDNode *>(allocAligned(sizeof(KDNode) * 2))+1; this->m_nodes = static_cast<KDNode *>(allocAligned(sizeof(KDNode) * 2))+1;
this->m_nodes[0].initLeafNode(0, 0); this->m_nodes[0].initLeafNode(0, 0);
@ -959,7 +960,7 @@ protected:
m_maxDepth = (int) (8 + 1.3f * log2i(primCount)); m_maxDepth = (int) (8 + 1.3f * log2i(primCount));
m_maxDepth = std::min(m_maxDepth, (size_type) MTS_KD_MAXDEPTH); m_maxDepth = std::min(m_maxDepth, (size_type) MTS_KD_MAXDEPTH);
Log(EDebug, "Creating a preliminary index list (%s)", KDLog(EDebug, "Creating a preliminary index list (%s)",
memString(primCount * sizeof(index_type)).c_str()); memString(primCount * sizeof(index_type)).c_str());
OrderedChunkAllocator &leftAlloc = ctx.leftAlloc; OrderedChunkAllocator &leftAlloc = ctx.leftAlloc;
@ -973,29 +974,29 @@ protected:
indices[i] = i; indices[i] = i;
} }
Log(EDebug, "Computed scene bounds in %i ms", KDLog(EDebug, "Computed scene bounds in %i ms",
timer->getMilliseconds()); timer->getMilliseconds());
Log(EDebug, ""); KDLog(EDebug, "");
Log(EDebug, "kd-tree configuration:"); KDLog(EDebug, "kd-tree configuration:");
Log(EDebug, " Traversal cost : %.2f", m_traversalCost); KDLog(EDebug, " Traversal cost : %.2f", m_traversalCost);
Log(EDebug, " Intersection cost : %.2f", m_intersectionCost); KDLog(EDebug, " Intersection cost : %.2f", m_intersectionCost);
Log(EDebug, " Empty space bonus : %.2f", m_emptySpaceBonus); KDLog(EDebug, " Empty space bonus : %.2f", m_emptySpaceBonus);
Log(EDebug, " Max. tree depth : %i", m_maxDepth); KDLog(EDebug, " Max. tree depth : %i", m_maxDepth);
Log(EDebug, " Scene bounding box (min) : %s", KDLog(EDebug, " Scene bounding box (min) : %s",
aabb.min.toString().c_str()); aabb.min.toString().c_str());
Log(EDebug, " Scene bounding box (max) : %s", KDLog(EDebug, " Scene bounding box (max) : %s",
aabb.max.toString().c_str()); aabb.max.toString().c_str());
Log(EDebug, " Min-max bins : %i", m_minMaxBins); KDLog(EDebug, " Min-max bins : %i", m_minMaxBins);
Log(EDebug, " Greedy SAH optimization : use for <= %i primitives", KDLog(EDebug, " Greedy SAH optimization : use for <= %i primitives",
m_exactPrimThreshold); m_exactPrimThreshold);
Log(EDebug, " Perfect splits : %s", m_clip ? "yes" : "no"); KDLog(EDebug, " Perfect splits : %s", m_clip ? "yes" : "no");
Log(EDebug, " Retract bad splits : %s", KDLog(EDebug, " Retract bad splits : %s",
m_retract ? "yes" : "no"); m_retract ? "yes" : "no");
Log(EDebug, " Stopping primitive count : %i", m_stopPrims); KDLog(EDebug, " Stopping primitive count : %i", m_stopPrims);
Log(EDebug, " Build tree in parallel : %s", KDLog(EDebug, " Build tree in parallel : %s",
m_parallelBuild ? "yes" : "no"); m_parallelBuild ? "yes" : "no");
Log(EDebug, ""); KDLog(EDebug, "");
size_type procCount = getProcessorCount(); size_type procCount = getProcessorCount();
if (procCount == 1) if (procCount == 1)
@ -1010,7 +1011,7 @@ protected:
} }
} }
Log(EInfo, "Constructing a SAH kd-tree (%i primitives) ..", primCount); KDLog(EInfo, "Constructing a SAH kd-tree (%i primitives) ..", primCount);
m_indirectionLock = new Mutex(); m_indirectionLock = new Mutex();
KDNode *prelimRoot = ctx.nodes.allocate(1); KDNode *prelimRoot = ctx.nodes.allocate(1);
@ -1030,17 +1031,17 @@ protected:
m_builders[i]->join(); m_builders[i]->join();
} }
Log(EInfo, "Finished -- took %i ms.", timer->getMilliseconds()); KDLog(EInfo, "Finished -- took %i ms.", timer->getMilliseconds());
Log(EDebug, ""); KDLog(EDebug, "");
Log(EDebug, "Temporary memory statistics:"); KDLog(EDebug, "Temporary memory statistics:");
Log(EDebug, " Classification storage : %s", KDLog(EDebug, " Classification storage : %s",
memString((ctx.classStorage.size() * (1+procCount))).c_str()); memString((ctx.classStorage.size() * (1+procCount))).c_str());
Log(EDebug, " Indirection entries : " SIZE_T_FMT " (%s)", KDLog(EDebug, " Indirection entries : " SIZE_T_FMT " (%s)",
m_indirections.size(), memString(m_indirections.capacity() m_indirections.size(), memString(m_indirections.capacity()
* sizeof(KDNode *)).c_str()); * sizeof(KDNode *)).c_str());
Log(EDebug, " Main thread:"); KDLog(EDebug, " Main thread:");
ctx.printStats(); ctx.printStats();
size_t totalUsage = m_indirections.capacity() size_t totalUsage = m_indirections.capacity()
* sizeof(KDNode *) + ctx.size(); * sizeof(KDNode *) + ctx.size();
@ -1049,7 +1050,7 @@ protected:
ctx.leftAlloc.cleanup(); ctx.leftAlloc.cleanup();
ctx.rightAlloc.cleanup(); ctx.rightAlloc.cleanup();
for (size_type i=0; i<m_builders.size(); ++i) { for (size_type i=0; i<m_builders.size(); ++i) {
Log(EDebug, " Worker thread %i:", i+1); KDLog(EDebug, " Worker thread %i:", i+1);
BuildContext &subCtx = m_builders[i]->getContext(); BuildContext &subCtx = m_builders[i]->getContext();
subCtx.printStats(); subCtx.printStats();
totalUsage += subCtx.size(); totalUsage += subCtx.size();
@ -1057,11 +1058,11 @@ protected:
subCtx.rightAlloc.cleanup(); subCtx.rightAlloc.cleanup();
ctx.accumulateStatisticsFrom(subCtx); ctx.accumulateStatisticsFrom(subCtx);
} }
Log(EDebug, " Total: %s", memString(totalUsage).c_str()); KDLog(EDebug, " Total: %s", memString(totalUsage).c_str());
Log(EDebug, ""); KDLog(EDebug, "");
timer->reset(); timer->reset();
Log(EDebug, "Optimizing memory layout .."); KDLog(EDebug, "Optimizing memory layout ..");
std::stack<boost::tuple<const KDNode *, KDNode *, std::stack<boost::tuple<const KDNode *, KDNode *,
const BuildContext *, AABBType> > stack; const BuildContext *, AABBType> > stack;
@ -1133,7 +1134,7 @@ protected:
float split = node->getSplit(); float split = node->getSplit();
bool result = target->initInnerNode(axis, split, children - target); bool result = target->initInnerNode(axis, split, children - target);
if (!result) if (!result)
Log(EError, "Cannot represent relative pointer -- " KDLog(EError, "Cannot represent relative pointer -- "
"too many primitives?"); "too many primitives?");
Float tmp = aabb.min[axis]; Float tmp = aabb.min[axis];
@ -1148,7 +1149,7 @@ protected:
KDAssert(nodePtr == ctx.innerNodeCount + ctx.leafNodeCount); KDAssert(nodePtr == ctx.innerNodeCount + ctx.leafNodeCount);
KDAssert(indexPtr == m_indexCount); KDAssert(indexPtr == m_indexCount);
Log(EDebug, "Finished -- took %i ms.", timer->getMilliseconds()); KDLog(EDebug, "Finished -- took %i ms.", timer->getMilliseconds());
/* Free some more memory */ /* Free some more memory */
ctx.nodes.clear(); ctx.nodes.clear();
@ -1167,7 +1168,7 @@ protected:
m_builders.clear(); m_builders.clear();
} }
Log(EDebug, ""); KDLog(EDebug, "");
Float rootSA = aabb.getSurfaceArea(); Float rootSA = aabb.getSurfaceArea();
expTraversalSteps /= rootSA; expTraversalSteps /= rootSA;
@ -1184,42 +1185,42 @@ protected:
+ Vector(Epsilon, Epsilon, Epsilon); + Vector(Epsilon, Epsilon, Epsilon);
this->m_bsphere = aabb.getBSphere(); this->m_bsphere = aabb.getBSphere();
Log(EDebug, "Structural kd-tree statistics:"); KDLog(EDebug, "Structural kd-tree statistics:");
Log(EDebug, " Parallel work units : " SIZE_T_FMT, KDLog(EDebug, " Parallel work units : " SIZE_T_FMT,
m_interface.threadMap.size()); m_interface.threadMap.size());
Log(EDebug, " Node storage cost : %s", KDLog(EDebug, " Node storage cost : %s",
memString(nodePtr * sizeof(KDNode)).c_str()); memString(nodePtr * sizeof(KDNode)).c_str());
Log(EDebug, " Index storage cost : %s", KDLog(EDebug, " Index storage cost : %s",
memString(indexPtr * sizeof(index_type)).c_str()); memString(indexPtr * sizeof(index_type)).c_str());
Log(EDebug, " Inner nodes : %i", ctx.innerNodeCount); KDLog(EDebug, " Inner nodes : %i", ctx.innerNodeCount);
Log(EDebug, " Leaf nodes : %i", ctx.leafNodeCount); KDLog(EDebug, " Leaf nodes : %i", ctx.leafNodeCount);
Log(EDebug, " Nonempty leaf nodes : %i", KDLog(EDebug, " Nonempty leaf nodes : %i",
ctx.nonemptyLeafNodeCount); ctx.nonemptyLeafNodeCount);
std::ostringstream oss; std::ostringstream oss;
oss << " Leaf node histogram : "; oss << " Leaf node histogram : ";
for (size_type i=0; i<primBucketCount; i++) { for (size_type i=0; i<primBucketCount; i++) {
oss << i << "(" << primBuckets[i] << ") "; oss << i << "(" << primBuckets[i] << ") ";
if ((i+1)%4==0 && i+1<primBucketCount) { if ((i+1)%4==0 && i+1<primBucketCount) {
Log(EDebug, "%s", oss.str().c_str()); KDLog(EDebug, "%s", oss.str().c_str());
oss.str(""); oss.str("");
oss << " "; oss << " ";
} }
} }
Log(EDebug, "%s", oss.str().c_str()); KDLog(EDebug, "%s", oss.str().c_str());
Log(EDebug, ""); KDLog(EDebug, "");
Log(EDebug, "Qualitative kd-tree statistics:"); KDLog(EDebug, "Qualitative kd-tree statistics:");
Log(EDebug, " Retracted splits : %i", ctx.retractedSplits); KDLog(EDebug, " Retracted splits : %i", ctx.retractedSplits);
Log(EDebug, " Pruned primitives : %i", ctx.pruned); KDLog(EDebug, " Pruned primitives : %i", ctx.pruned);
Log(EDebug, " Largest leaf node : %i primitives", KDLog(EDebug, " Largest leaf node : %i primitives",
maxPrimsInLeaf); maxPrimsInLeaf);
Log(EDebug, " Avg. prims/nonempty leaf : %.2f", KDLog(EDebug, " Avg. prims/nonempty leaf : %.2f",
ctx.primIndexCount / (Float) ctx.nonemptyLeafNodeCount); ctx.primIndexCount / (Float) ctx.nonemptyLeafNodeCount);
Log(EDebug, " Expected traversals/ray : %.2f", expTraversalSteps); KDLog(EDebug, " Expected traversals/ray : %.2f", expTraversalSteps);
Log(EDebug, " Expected leaf visits/ray : %.2f", expLeavesVisited); KDLog(EDebug, " Expected leaf visits/ray : %.2f", expLeavesVisited);
Log(EDebug, " Expected prim. visits/ray : %.2f", KDLog(EDebug, " Expected prim. visits/ray : %.2f",
expPrimitivesIntersected); expPrimitivesIntersected);
Log(EDebug, " Final SAH cost : %.2f", sahCost); KDLog(EDebug, " Final SAH cost : %.2f", sahCost);
Log(EDebug, ""); KDLog(EDebug, "");
} }
protected: protected:
@ -1365,16 +1366,16 @@ protected:
} }
void printStats() { void printStats() {
Log(EDebug, " Left events : " SIZE_T_FMT " chunks (%s)", KDLog(EDebug, " Left events : " SIZE_T_FMT " chunks (%s)",
leftAlloc.getChunkCount(), leftAlloc.getChunkCount(),
memString(leftAlloc.size()).c_str()); memString(leftAlloc.size()).c_str());
Log(EDebug, " Right events : " SIZE_T_FMT " chunks (%s)", KDLog(EDebug, " Right events : " SIZE_T_FMT " chunks (%s)",
rightAlloc.getChunkCount(), rightAlloc.getChunkCount(),
memString(rightAlloc.size()).c_str()); memString(rightAlloc.size()).c_str());
Log(EDebug, " kd-tree nodes : " SIZE_T_FMT " entries, " KDLog(EDebug, " kd-tree nodes : " SIZE_T_FMT " entries, "
SIZE_T_FMT " blocks (%s)", nodes.size(), nodes.blockCount(), SIZE_T_FMT " blocks (%s)", nodes.size(), nodes.blockCount(),
memString(nodes.capacity() * sizeof(KDNode)).c_str()); memString(nodes.capacity() * sizeof(KDNode)).c_str());
Log(EDebug, " Indices : " SIZE_T_FMT " entries, " KDLog(EDebug, " Indices : " SIZE_T_FMT " entries, "
SIZE_T_FMT " blocks (%s)", indices.size(), SIZE_T_FMT " blocks (%s)", indices.size(),
indices.blockCount(), memString(indices.capacity() indices.blockCount(), memString(indices.capacity()
* sizeof(index_type)).c_str()); * sizeof(index_type)).c_str());
@ -2021,7 +2022,7 @@ protected:
if (m_clip && (pos < nodeAABB.min[axis] if (m_clip && (pos < nodeAABB.min[axis]
|| pos > nodeAABB.max[axis])) { || pos > nodeAABB.max[axis])) {
/* When primitive clipping is active, this should never happen! */ /* When primitive clipping is active, this should never happen! */
Log(EError, "Internal error: edge event is out of bounds"); KDLog(EError, "Internal error: edge event is out of bounds");
} }
#endif #endif
} }
@ -3184,7 +3185,7 @@ template <typename AABBType, typename Derived>
} }
} }
Log(EDebug, "Fitting to " SIZE_T_FMT " samples (" SIZE_T_FMT KDLog(EDebug, "Fitting to " SIZE_T_FMT " samples (" SIZE_T_FMT
" intersections)", idx, nIntersections); " intersections)", idx, nIntersections);
/* Solve using normal equations */ /* Solve using normal equations */
@ -3200,7 +3201,7 @@ template <typename AABBType, typename Derived>
} }
M.m[3][3] = 1.0f; M.m[3][3] = 1.0f;
bool success = M.invert(Minv); bool success = M.invert(Minv);
Assert(success); SAssert(success);
Transform(Minv, M)(rhs, x); Transform(Minv, M)(rhs, x);
@ -3219,17 +3220,17 @@ template <typename AABBType, typename Derived>
avgRdtsc += b[k]; avgRdtsc += b[k];
avgRdtsc /= idx; avgRdtsc /= idx;
Log(EDebug, "Least squares fit:"); KDLog(EDebug, "Least squares fit:");
Log(EDebug, " Constant overhead = %.2f", x[0]); KDLog(EDebug, " Constant overhead = %.2f", x[0]);
Log(EDebug, " Traversal cost = %.2f", x[1]); KDLog(EDebug, " Traversal cost = %.2f", x[1]);
Log(EDebug, " Intersection cost = %.2f", x[2]); KDLog(EDebug, " Intersection cost = %.2f", x[2]);
Log(EDebug, " Average rdtsc value = %.2f", avgRdtsc); KDLog(EDebug, " Average rdtsc value = %.2f", avgRdtsc);
Log(EDebug, " Avg. residual = %.2f", avgResidual); KDLog(EDebug, " Avg. residual = %.2f", avgResidual);
x *= 10/x[1]; x *= 10/x[1];
Log(EDebug, "Re-scaled:"); KDLog(EDebug, "Re-scaled:");
Log(EDebug, " Constant overhead = %.2f", x[0]); KDLog(EDebug, " Constant overhead = %.2f", x[0]);
Log(EDebug, " Traversal cost = %.2f", x[1]); KDLog(EDebug, " Traversal cost = %.2f", x[1]);
Log(EDebug, " Intersection cost = %.2f", x[2]); KDLog(EDebug, " Intersection cost = %.2f", x[2]);
delete[] A; delete[] A;
delete[] b; delete[] b;
@ -3238,20 +3239,11 @@ template <typename AABBType, typename Derived>
} }
template <typename AABBType> template <typename AABBType>
Class *AbstractKDTree<AABBType>::m_theClass Class *KDTreeBase<AABBType>::m_theClass
= new Class("AbstractKDTree", true, "Object"); = new Class("KDTreeBase", true, "Object");
template <typename AABBType> template <typename AABBType>
const Class *AbstractKDTree<AABBType>::getClass() const { const Class *KDTreeBase<AABBType>::getClass() const {
return m_theClass;
}
template <typename AABBType, typename Derived>
Class *GenericKDTree<AABBType, Derived>::m_theClass
= new Class("GenericKDTree", true, "AbstractKDTree");
template <typename AABBType, typename Derived>
const Class *GenericKDTree<AABBType, Derived>::getClass() const {
return m_theClass; return m_theClass;
} }

View File

@ -252,7 +252,7 @@ public:
* the interactive walkthrough. The default implementation * the interactive walkthrough. The default implementation
* simply returns NULL. * simply returns NULL.
*/ */
virtual const AbstractKDTree<AABB> *getKDTree() const; virtual const KDTreeBase<AABB> *getKDTree() const;
/** /**
* \brief Create a triangle mesh approximation of this shape * \brief Create a triangle mesh approximation of this shape

View File

@ -300,5 +300,5 @@ void KDTree::rayIntersectPacketIncoherent(const RayPacket4 &packet,
#endif #endif
MTS_IMPLEMENT_CLASS(KDTree, false, GenericKDTree) MTS_IMPLEMENT_CLASS(KDTree, false, KDTreeBase)
MTS_NAMESPACE_END MTS_NAMESPACE_END

View File

@ -101,7 +101,7 @@ void Shape::addChild(const std::string &name, ConfigurableObject *child) {
} }
} }
const AbstractKDTree<AABB> *Shape::getKDTree() const { const KDTreeBase<AABB> *Shape::getKDTree() const {
return NULL; return NULL;
} }

View File

@ -541,14 +541,14 @@ void PreviewThread::oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl) {
} }
} }
void PreviewThread::oglRenderKDTree(const AbstractKDTree<AABB> *kdtree) { void PreviewThread::oglRenderKDTree(const KDTreeBase<AABB> *kdtree) {
std::stack<boost::tuple<const AbstractKDTree<AABB>::KDNode *, AABB, uint32_t> > stack; std::stack<boost::tuple<const KDTreeBase<AABB>::KDNode *, AABB, uint32_t> > stack;
stack.push(boost::make_tuple(kdtree->getRoot(), kdtree->getTightAABB(), 0)); stack.push(boost::make_tuple(kdtree->getRoot(), kdtree->getTightAABB(), 0));
Float brightness = 10.0f; Float brightness = 10.0f;
while (!stack.empty()) { while (!stack.empty()) {
const AbstractKDTree<AABB>::KDNode *node = boost::get<0>(stack.top()); const KDTreeBase<AABB>::KDNode *node = boost::get<0>(stack.top());
AABB aabb = boost::get<1>(stack.top()); AABB aabb = boost::get<1>(stack.top());
int level = boost::get<2>(stack.top()); int level = boost::get<2>(stack.top());
stack.pop(); stack.pop();

View File

@ -75,7 +75,7 @@ protected:
/// Render a single VPL using OpenGL /// Render a single VPL using OpenGL
void oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl); void oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl);
/// Render a wireframe visualization of a kd-tree /// Render a wireframe visualization of a kd-tree
void oglRenderKDTree(const AbstractKDTree<AABB> *kdtree); void oglRenderKDTree(const KDTreeBase<AABB> *kdtree);
/// Render a single VPL using real-time coherent ray tracing /// Render a single VPL using real-time coherent ray tracing
void rtrtRenderVPL(PreviewQueueEntry &target, const VPL &vpl); void rtrtRenderVPL(PreviewQueueEntry &target, const VPL &vpl);
private: private:

View File

@ -705,7 +705,7 @@ public:
return mesh.get(); return mesh.get();
} }
const AbstractKDTree<AABB> *getKDTree() const { const KDTreeBase<AABB> *getKDTree() const {
return m_kdtree.get(); return m_kdtree.get();
} }