From 3e316e6efdbbbfcbeb441207d532be6f5b378c28 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Thu, 31 Mar 2011 00:44:20 +0200 Subject: [PATCH] instancing support in the realtine preview --- data/blender/mitsuba/core/__init__.py | 4 +- data/blender/mitsuba/export/__init__.py | 33 ++++-- include/mitsuba/hw/glrenderer.h | 8 +- include/mitsuba/hw/gpugeometry.h | 3 + include/mitsuba/hw/renderer.h | 14 ++- include/mitsuba/hw/vpl.h | 5 +- include/mitsuba/render/scene.h | 8 +- src/converter/collada.cpp | 27 +++-- src/integrators/vpl/vpl.cpp | 15 ++- src/libhw/glrenderer.cpp | 50 +++++++-- src/libhw/renderer.cpp | 5 +- src/libhw/vpl.cpp | 100 +++++++++++------ src/qtgui/preview.cpp | 14 ++- src/shapes/instance.cpp | 140 +++++++++++------------- src/shapes/instance.h | 80 ++++++++++++++ src/shapes/shapegroup.h | 9 +- src/tests/test_quad.cpp | 44 ++++++++ 17 files changed, 392 insertions(+), 167 deletions(-) create mode 100644 src/shapes/instance.h create mode 100644 src/tests/test_quad.cpp diff --git a/data/blender/mitsuba/core/__init__.py b/data/blender/mitsuba/core/__init__.py index b700421b..a9605db6 100644 --- a/data/blender/mitsuba/core/__init__.py +++ b/data/blender/mitsuba/core/__init__.py @@ -197,7 +197,9 @@ class RENDERENGINE_mitsuba(bpy.types.RenderEngine): exporter = MtsExporter(tempdir, matfile, bpy.data.materials, bpy.data.textures) exporter.adj_filename = os.path.join(tempdir, matfile) - exporter.writeHeader() + if not exporter.writeHeader(): + MtsLog('Error while exporting -- check the console for details.') + return; exporter.exportMaterial(pm) exporter.exportPreviewMesh(pm) exporter.writeFooter() diff --git a/data/blender/mitsuba/export/__init__.py b/data/blender/mitsuba/export/__init__.py index dc35972c..ff5a4ce0 100644 --- a/data/blender/mitsuba/export/__init__.py +++ b/data/blender/mitsuba/export/__init__.py @@ -246,9 +246,14 @@ class MtsExporter: self.stack = [] def writeHeader(self): - self.out = open(self.adj_filename, 'w') + try: + self.out = open(self.adj_filename, 'w') + except IOError: + MtsLog('Error: unable to write to file \"%s\"!' % self.adj_filename) + return False self.out.write('\n'); self.openElement('scene') + return True def writeFooter(self): self.closeElement() @@ -308,7 +313,10 @@ class MtsExporter: size_y = lamp.data.size_y mult = mult / (2 * size_x * size_y) filename = "area_luminaire_%d.obj" % idx - + try: + os.mkdir(self.meshes_dir) + except OSError: + pass self.parameter('string', 'filename', { 'value' : 'meshes/%s' % filename}) self.exportWorldTrafo(lamp.matrix_world) @@ -429,9 +437,12 @@ class MtsExporter: def exportEmission(self, obj): lamp = obj.data.materials[0].mitsuba_emission - name = translate_id(obj.data.name) + if obj.data.users > 1: + MtsLog("Error: luminaires cannot be instantiated!") + return mult = lamp.intensity - self.openElement('append', { 'id' : '%s-mesh_0' % name}) + name = translate_id(obj.data.name) + "-mesh_0" + self.openElement('append', { 'id' : name}) self.openElement('luminaire', { 'id' : '%s-emission' % name, 'type' : 'area'}) self.parameter('float', 'samplingWeight', {'value' : '%f' % lamp.samplingWeight}) self.parameter('rgb', 'intensity', { 'value' : "%f %f %f" @@ -486,16 +497,11 @@ class MtsExporter: # Force scene update; NB, scene.update() doesn't work scene.frame_set(scene.frame_current) efutil.export_path = self.xml_filename - try: - os.mkdir(self.meshes_dir) - except OSError: - pass - MtsLog('MtsBlend: Writing COLLADA file to "%s"' % self.dae_filename) - scene.collada_export(self.dae_filename) - MtsLog('MtsBlend: Writing adjustments file to "%s"' % self.adj_filename) - self.writeHeader() + if not self.writeHeader(): + return False + self.exportIntegrator(scene.mitsuba_integrator) self.exportSampler(scene.mitsuba_sampler) for medium in scene.mitsuba_media.media: @@ -513,6 +519,9 @@ class MtsExporter: idx = idx+1 self.writeFooter() (width, height) = resolution(scene) + + MtsLog('MtsBlend: Writing COLLADA file to "%s"' % self.dae_filename) + scene.collada_export(self.dae_filename) MtsLog("MtsBlend: Launching mtsimport") command = ['mtsimport', '-r', '%dx%d' % (width, height), diff --git a/include/mitsuba/hw/glrenderer.h b/include/mitsuba/hw/glrenderer.h index 0b2f062c..9080adb0 100644 --- a/include/mitsuba/hw/glrenderer.h +++ b/include/mitsuba/hw/glrenderer.h @@ -119,7 +119,7 @@ public: * Only transmits positions, hence this is mainly useful for * shadow mapping. */ - void drawAll(); + void drawAll(const std::vector > &geo); /// Blit a screen-sized quad void blitQuad(bool flipVertically); @@ -168,6 +168,12 @@ public: /// Set the current fixed-function pipeline color void setColor(const Spectrum &spec); + /// Push a view transformation onto the matrix stack + void pushTransform(const Transform &trafo); + + /// Pop the last view transformation from the matrix stack + void popTransform(); + /// Flush outstanding rendering commands void flush(); diff --git a/include/mitsuba/hw/gpugeometry.h b/include/mitsuba/hw/gpugeometry.h index d384851c..ccfff314 100644 --- a/include/mitsuba/hw/gpugeometry.h +++ b/include/mitsuba/hw/gpugeometry.h @@ -33,6 +33,9 @@ public: /// Return the name of this geometry object inline std::string getName() const { return m_mesh->getName(); } + /// Return the associated triangle mesh + inline const TriMesh *getTriMesh() const { return m_mesh.get(); } + /// Upload the geometry object virtual void init() = 0; diff --git a/include/mitsuba/hw/renderer.h b/include/mitsuba/hw/renderer.h index cc05d025..24b59ae6 100644 --- a/include/mitsuba/hw/renderer.h +++ b/include/mitsuba/hw/renderer.h @@ -154,7 +154,7 @@ public: * Only transmits positions, hence this is mainly useful for * shadow mapping. */ - virtual void drawAll() = 0; + virtual void drawAll(const std::vector > &geo) = 0; /// Draw a quad using the given texture virtual void blitTexture(const GPUTexture *texture, @@ -217,6 +217,12 @@ public: /// Set the current fixed-function pipeline color virtual void setColor(const Spectrum &spec) = 0; + /// Push a view transformation onto the matrix stack + virtual void pushTransform(const Transform &trafo) = 0; + + /// Pop the last view transformation from the matrix stack + virtual void popTransform() = 0; + /// Flush outstanding rendering commands virtual void flush() = 0; @@ -246,11 +252,9 @@ public: * will transfer the associated geometry to the GPU, * which accelerates later calls to drawTriMesh() */ - void registerGeometry(const TriMesh *mesh); + GPUGeometry *registerGeometry(const TriMesh *mesh); - /** - * Unregister a triangle mesh from the renderer. - */ + /// Unregister a triangle mesh from the renderer. void unregisterGeometry(const TriMesh *mesh); /// Set the log level diff --git a/include/mitsuba/hw/vpl.h b/include/mitsuba/hw/vpl.h index 96aa3fd5..6a63e5e4 100644 --- a/include/mitsuba/hw/vpl.h +++ b/include/mitsuba/hw/vpl.h @@ -56,7 +56,7 @@ public: void unbind(); /// Return all bound triangle meshes - inline const std::vector &getMeshes() const { return m_meshes; } + inline const std::vector > &getMeshes() const { return m_meshes; } /// Return the shadow cube map for debugging purposes inline GPUTexture *getShadowMap() { return m_shadowMap; } @@ -271,7 +271,8 @@ private: VPLProgramConfiguration m_targetConfig; ref m_backgroundProgram; VPLDependencyNode m_backgroundDependencies; - std::vector m_meshes; + std::vector > m_meshes; + std::vector > m_drawList; }; MTS_NAMESPACE_END diff --git a/include/mitsuba/render/scene.h b/include/mitsuba/render/scene.h index f8a7af48..dd55e1cb 100644 --- a/include/mitsuba/render/scene.h +++ b/include/mitsuba/render/scene.h @@ -37,9 +37,11 @@ MTS_NAMESPACE_BEGIN /** - * Scene data structure: holds information on surfaces, luminaires - * and participating media and coordinates rendering jobs. Also provides - * useful query routines mostly used by the integrator implementations. + * \brief Principal scene data structure + * + * Holds information on surfaces, luminaires and participating media and + * coordinates rendering jobs. This class also provides useful query routines + * that are mostly used by the \ref Integrator implementations. */ class MTS_EXPORT_RENDER Scene : public NetworkedObject { public: diff --git a/src/converter/collada.cpp b/src/converter/collada.cpp index 6cf3b5d9..af88b435 100644 --- a/src/converter/collada.cpp +++ b/src/converter/collada.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -224,7 +225,6 @@ VertexData *fetchVertexData(Transform transform, result->typeToOffset[EUV] = offset; result->typeToOffsetInStream[EUV] = offsetInStream; result->typeToCount[EUV] = size; - cout << "Got texture coordinates.." << endl; } else { SLog(EWarn, "Found multiple sets of texture coordinates - ignoring!"); } @@ -420,7 +420,7 @@ void writeGeometry(ColladaContext &ctx, const std::string &prefixName, std::stri } SAssert(triangleIdx == 0); - SLog(EInfo, "\"%s/%s\": Converted " SIZE_T_FMT " triangles, " SIZE_T_FMT + SLog(EDebug, "\"%s/%s\": Converted " SIZE_T_FMT " triangles, " SIZE_T_FMT " vertices (merged " SIZE_T_FMT " vertices).", prefixName.c_str(), id.c_str(), triangles.size(), vertexBuffer.size(), numMerged); @@ -516,7 +516,7 @@ void exportAnimation(ColladaContext &ctx, const fs::path &path, const std::strin continue; trafo->addTrack(track); } - SLog(EInfo, "Writing animation track \"%s\"", path.filename().c_str()); + SLog(EDebug, "Writing animation track \"%s\"", path.filename().c_str()); ref fs = new FileStream(path, FileStream::ETruncReadWrite); trafo->serialize(fs); } @@ -537,7 +537,7 @@ void loadGeometry(ColladaContext &ctx, const std::string &instanceName, } TriangleMap triMap; - SLog(EInfo, "Converting geometry \"%s\" (instantiated by %s)..", identifier.c_str(), + SLog(EDebug, "Converting geometry \"%s\" (instantiated by %s)..", identifier.c_str(), prefixName == "" ? "/" : prefixName.c_str()); domMesh *mesh = geom.getMesh().cast(); if (!mesh) @@ -938,7 +938,7 @@ void loadLight(ColladaContext &ctx, Transform transform, domLight &light) { } } - SLog(EInfo, "Converting light \"%s\" ..", identifier.c_str()); + SLog(EDebug, "Converting light \"%s\" ..", identifier.c_str()); char *end_ptr = NULL; // Lights in Mitsuba point along the positive Z axis (COLLADA: neg. Z) @@ -1039,7 +1039,7 @@ void loadImage(ColladaContext &ctx, domImage &image) { } } - SLog(EInfo, "Converting texture \"%s\" ..", identifier.c_str()); + SLog(EDebug, "Converting texture \"%s\" ..", identifier.c_str()); std::string filename = cdom::uriToFilePath(image.getInit_from()->getValue().str()); if (ctx.fileToId.find(filename) != ctx.fileToId.end()) { @@ -1098,7 +1098,7 @@ void loadCamera(ColladaContext &ctx, Transform transform, domCamera &camera) { } } - SLog(EInfo, "Converting camera \"%s\" ..", identifier.c_str()); + SLog(EDebug, "Converting camera \"%s\" ..", identifier.c_str()); Float aspect = 1.0f; int xres=768; @@ -1188,7 +1188,7 @@ void loadNode(ColladaContext &ctx, Transform transform, domNode &node, std::stri } } prefixName = prefixName + std::string("/") + identifier; - SLog(EInfo, "Converting node \"%s\" ..", identifier.c_str()); + SLog(EDebug, "Converting node \"%s\" ..", identifier.c_str()); daeTArray > children = node.getChildren(); /* Parse transformations */ @@ -1341,7 +1341,7 @@ void loadAnimation(ColladaContext &ctx, domAnimation &anim) { identifier = formatString("unnamedAnimation_%i", unnamedCtr); } } - SLog(EInfo, "Loading animation \"%s\" ..", identifier.c_str()); + SLog(EDebug, "Loading animation \"%s\" ..", identifier.c_str()); domChannel_Array &channels = anim.getChannel_array(); for (size_t i=0; i times; @@ -1606,7 +1606,10 @@ void GeometryConverter::convertCollada(const fs::path &inputFile, ctx.cvt = this; ctx.trackIndex = 0; + ref timer = new Timer(); + if (m_importMaterials) { + SLog(EInfo, "Importing materials .."); domLibrary_images_Array &libraryImages = document->getLibrary_images_array(); for (size_t i=0; igetImage_array(); @@ -1623,6 +1626,7 @@ void GeometryConverter::convertCollada(const fs::path &inputFile, } if (m_importAnimations) { + SLog(EInfo, "Importing animations .."); domLibrary_animations_Array &libraryAnimations = document->getLibrary_animations_array(); for (size_t i=0; igetAnimation_array(); @@ -1632,6 +1636,7 @@ void GeometryConverter::convertCollada(const fs::path &inputFile, mergeRotations(ctx); } + SLog(EInfo, "Importing scene .."); for (size_t i=0; isecond->decRef(); + SLog(EInfo, "Done, took %s", timeToString(timer->getMilliseconds()/1000.0f).c_str()); + os << "" << endl; gluDeleteTess(tess); diff --git a/src/integrators/vpl/vpl.cpp b/src/integrators/vpl/vpl.cpp index 58dc0ccf..48cdebe1 100644 --- a/src/integrators/vpl/vpl.cpp +++ b/src/integrators/vpl/vpl.cpp @@ -51,20 +51,25 @@ public: /// Draw the full scene using additive blending and shadow maps void drawShadowedScene(const Scene *scene, const VPL &vpl) { + const std::vector > meshes = m_shaderManager->getMeshes(); const ProjectiveCamera *camera = static_cast(scene->getCamera()); Point2 jitter(0.5f - m_random->nextFloat(), 0.5f - m_random->nextFloat()); Transform projectionTransform = camera->getGLProjectionTransform(jitter); m_renderer->setCamera(projectionTransform.getMatrix(), camera->getViewTransform().getMatrix()); Transform clipToWorld = camera->getViewTransform().inverse() * projectionTransform.inverse(); - const std::vector meshes = m_shaderManager->getMeshes(); Point camPos = scene->getCamera()->getPosition(); m_renderer->beginDrawingMeshes(); for (unsigned int j=0; jconfigure(vpl, meshes[j]->getBSDF(), - meshes[j]->getLuminaire(), camPos, - !meshes[j]->hasVertexNormals()); - m_renderer->drawTriMesh(meshes[j]); + const TriMesh *mesh = meshes[j].first; + bool hasTransform = !meshes[j].second.isIdentity(); + m_shaderManager->configure(vpl, mesh->getBSDF(), mesh->getLuminaire(), + camPos, !mesh->hasVertexNormals()); + if (hasTransform) + m_renderer->pushTransform(meshes[j].second); + m_renderer->drawTriMesh(mesh); + if (hasTransform) + m_renderer->popTransform(); m_shaderManager->unbind(); } m_renderer->endDrawingMeshes(); diff --git a/src/libhw/glrenderer.cpp b/src/libhw/glrenderer.cpp index 5d2146de..c91d7a80 100644 --- a/src/libhw/glrenderer.cpp +++ b/src/libhw/glrenderer.cpp @@ -529,13 +529,22 @@ void GLRenderer::endDrawingMeshes() { } } -void GLRenderer::drawAll() { +void GLRenderer::drawAll(const std::vector > &geo) { + GLfloat temp[16]; GLRenderer::beginDrawingMeshes(true); - std::map::iterator it; + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + std::vector >::const_iterator it; if (m_capabilities->isSupported(RendererCapabilities::EBindless)) { - for (it = m_geometry.begin(); it != m_geometry.end(); ++it) { - const TriMesh *mesh = static_cast((*it).first); - const GLGeometry *geometry = static_cast((*it).second); + for (it = geo.begin(); it != geo.end(); ++it) { + const GLGeometry *geometry = static_cast(it->first); + const TriMesh *mesh = geometry->getTriMesh(); + int pos=0; + for (int j=0; j<4; j++) + for (int i=0; i<4; i++) + temp[pos++] = (GLfloat) it->second.getMatrix().m[i][j]; + glLoadMatrixf(temp); + int stride = geometry->m_stride; if (stride != m_stride) { glVertexFormatNV(3, GL_FLOAT, stride); @@ -568,11 +577,17 @@ void GLRenderer::drawAll() { finish(); } } + glPopMatrix(); } } else { - for (it = m_geometry.begin(); it != m_geometry.end(); ++it) { - const TriMesh *mesh = static_cast((*it).first); - const GLGeometry *geometry = static_cast((*it).second); + for (it = geo.begin(); it != geo.end(); ++it) { + const GLGeometry *geometry = static_cast(it->first); + const TriMesh *mesh = geometry->getTriMesh(); + int pos=0; + for (int j=0; j<4; j++) + for (int i=0; i<4; i++) + temp[pos++] = (GLfloat) it->second.getMatrix().m[i][j]; + glLoadMatrixf(temp); glBindBuffer(GL_ARRAY_BUFFER, geometry->m_vertexID); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, geometry->m_indexID); @@ -601,9 +616,11 @@ void GLRenderer::drawAll() { finish(); } } + glPopMatrix(); } } GLRenderer::endDrawingMeshes(); + glPopMatrix(); } void GLRenderer::blitTexture(const GPUTexture *tex, bool flipVertically, @@ -965,6 +982,23 @@ void GLRenderer::setColorMask(bool value) { glColorMask(flag, flag, flag, flag); } +void GLRenderer::pushTransform(const Transform &trafo) { + const Matrix4x4 &matrix = trafo.getMatrix(); + GLfloat temp[16]; + int pos=0; + for (int j=0; j<4; j++) + for (int i=0; i<4; i++) + temp[pos++] = (GLfloat) matrix.m[i][j]; + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glMultMatrixf(temp); +} + +void GLRenderer::popTransform() { + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); +} + void GLRenderer::flush() { glFlush(); } diff --git a/src/libhw/renderer.cpp b/src/libhw/renderer.cpp index db2a462b..540326b3 100644 --- a/src/libhw/renderer.cpp +++ b/src/libhw/renderer.cpp @@ -97,9 +97,9 @@ void Renderer::unregisterShaderForResource(const HWResource *resource) { } } -void Renderer::registerGeometry(const TriMesh *mesh) { +GPUGeometry *Renderer::registerGeometry(const TriMesh *mesh) { if (!m_capabilities->isSupported(RendererCapabilities::EVertexBufferObjects)) - return; + return NULL; GPUGeometry *geometry; if (m_geometry.find(mesh) == m_geometry.end()) { @@ -110,6 +110,7 @@ void Renderer::registerGeometry(const TriMesh *mesh) { geometry = m_geometry[mesh]; } geometry->incRef(); + return geometry; } void Renderer::unregisterGeometry(const TriMesh *mesh) { diff --git a/src/libhw/vpl.cpp b/src/libhw/vpl.cpp index 118d1c77..d1008066 100644 --- a/src/libhw/vpl.cpp +++ b/src/libhw/vpl.cpp @@ -20,6 +20,7 @@ #include #include #include +#include "../shapes/instance.h" MTS_NAMESPACE_BEGIN @@ -41,7 +42,7 @@ void VPLShaderManager::init() { m_shadowProgram->setSource(GPUProgram::EVertexProgram, "void main() {\n" - " gl_Position = gl_Vertex;\n" + " gl_Position = gl_ModelViewMatrix * gl_Vertex;\n" "}" ); @@ -94,7 +95,7 @@ void VPLShaderManager::init() { "uniform vec4 depthVec;\n" "varying float depth;\n" "void main() {\n" - " gl_Position = cubeMapTransform * gl_Vertex;\n" + " gl_Position = gl_ModelViewMatrix * (cubeMapTransform * gl_Vertex);\n" " depth = dot(depthVec, gl_Vertex);\n" "}\n" ); @@ -120,15 +121,36 @@ void VPLShaderManager::init() { for (size_t i=0; i triMesh = shapes[i]->createTriMesh(); - if (!triMesh) + if (!triMesh) { + std::string shapeClass = shapes[i]->getClass()->getName(); + if (shapeClass == "Instance") { + const Instance *instance = static_cast(shapes[i]); + const std::vector &subShapes = + instance->getShapeGroup()->getKDTree()->getShapes(); + for (size_t j=0; j(subShapes[j])->createTriMesh(); + if (!triMesh) + continue; + GPUGeometry *gpuGeo = m_renderer->registerGeometry(triMesh); + Shader *shader = triMesh->hasBSDF() ? + m_renderer->registerShaderForResource(triMesh->getBSDF()) : NULL; + if (shader != NULL && !shader->isComplete()) + m_renderer->unregisterShaderForResource(triMesh->getBSDF()); + m_meshes.push_back(std::make_pair(triMesh.get(), instance->getWorldTransform())); + if (gpuGeo) + m_drawList.push_back(std::make_pair(gpuGeo, instance->getWorldTransform())); + } + } continue; - m_renderer->registerGeometry(triMesh); + } + GPUGeometry *gpuGeo = m_renderer->registerGeometry(triMesh); Shader *shader = triMesh->hasBSDF() ? m_renderer->registerShaderForResource(triMesh->getBSDF()) : NULL; if (shader != NULL && !shader->isComplete()) m_renderer->unregisterShaderForResource(triMesh->getBSDF()); - triMesh->incRef(); - m_meshes.push_back(triMesh); + m_meshes.push_back(std::make_pair(triMesh.get(), Transform())); + if (gpuGeo) + m_drawList.push_back(std::make_pair(gpuGeo, Transform())); } for (size_t i=0; i::iterator it = m_programs.begin(); + it != m_programs.end(); ++it) { + (*it).second.program->cleanup(); + (*it).second.program->decRef(); + } + + if (m_shadowMap) + m_shadowMap->cleanup(); + + if (m_backgroundProgram) { + m_backgroundProgram->cleanup(); + m_backgroundProgram = NULL; + } + + const std::vector luminaires = m_scene->getLuminaires(); + + for (size_t i=0; iunregisterGeometry(m_meshes[i].first); + m_renderer->unregisterShaderForResource(m_meshes[i].first->getBSDF()); + } + + m_meshes.clear(); + m_drawList.clear(); + + for (size_t i=0; iunregisterShaderForResource(luminaires[i]); + m_initialized = false; +} + + void VPLShaderManager::setVPL(const VPL &vpl) { Point p = vpl.its.p + vpl.its.shFrame.n * 0.01; Intersection its; @@ -224,6 +277,9 @@ void VPLShaderManager::setVPL(const VPL &vpl) { m_nearClip = nearClip; m_invClipRange = 1/(farClip-nearClip); Transform lightViewTrafo, lightProjTrafo = Transform::glPerspective(90.0f, nearClip, farClip); + Matrix4x4 identity; + identity.setIdentity(); + m_renderer->setCamera(identity, identity); m_shadowMap->activateTarget(); if (m_singlePass && m_shadowProgram != NULL) { @@ -252,7 +308,7 @@ void VPLShaderManager::setVPL(const VPL &vpl) { (-viewMatrix.m[2][3] - m_nearClip) * m_invClipRange )); } - m_renderer->drawAll(); + m_renderer->drawAll(m_drawList); m_shadowProgram->unbind(); } else { /* Old-fashioned: render 6 times, once for each cube map face */ @@ -278,7 +334,7 @@ void VPLShaderManager::setVPL(const VPL &vpl) { m_shadowMap->activateSide(i); m_shadowMap->clear(); - m_renderer->drawAll(); + m_renderer->drawAll(m_drawList); } m_altShadowProgram->unbind(); @@ -572,33 +628,5 @@ void VPLShaderManager::unbind() { } } -void VPLShaderManager::cleanup() { - for (std::map::iterator it = m_programs.begin(); - it != m_programs.end(); ++it) { - (*it).second.program->cleanup(); - (*it).second.program->decRef(); - } - - if (m_shadowMap) - m_shadowMap->cleanup(); - - if (m_backgroundProgram) { - m_backgroundProgram->cleanup(); - m_backgroundProgram = NULL; - } - - const std::vector luminaires = m_scene->getLuminaires(); - - for (size_t i=0; iunregisterGeometry(m_meshes[i]); - m_renderer->unregisterShaderForResource(m_meshes[i]->getBSDF()); - m_meshes[i]->decRef(); - } - m_meshes.clear(); - for (size_t i=0; iunregisterShaderForResource(luminaires[i]); - m_initialized = false; -} - MTS_IMPLEMENT_CLASS(VPLShaderManager, false, Object) MTS_NAMESPACE_END diff --git a/src/qtgui/preview.cpp b/src/qtgui/preview.cpp index d13b3d0a..b4588cdc 100644 --- a/src/qtgui/preview.cpp +++ b/src/qtgui/preview.cpp @@ -464,7 +464,7 @@ void PreviewThread::run() { } void PreviewThread::oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl) { - const std::vector meshes = m_shaderManager->getMeshes(); + const std::vector > meshes = m_shaderManager->getMeshes(); m_shaderManager->setVPL(vpl); @@ -488,9 +488,15 @@ void PreviewThread::oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl) { m_framebuffer->clear(); m_renderer->beginDrawingMeshes(); for (size_t j=0; jconfigure(vpl, meshes[j]->getBSDF(), - meshes[j]->getLuminaire(), camPos, !meshes[j]->hasVertexNormals()); - m_renderer->drawTriMesh(meshes[j]); + const TriMesh *mesh = meshes[j].first; + bool hasTransform = !meshes[j].second.isIdentity(); + m_shaderManager->configure(vpl, mesh->getBSDF(), + mesh->getLuminaire(), camPos, !mesh->hasVertexNormals()); + if (hasTransform) + m_renderer->pushTransform(meshes[j].second); + m_renderer->drawTriMesh(mesh); + if (hasTransform) + m_renderer->popTransform(); m_shaderManager->unbind(); } m_renderer->endDrawingMeshes(); diff --git a/src/shapes/instance.cpp b/src/shapes/instance.cpp index 172cbaf9..4310d88d 100644 --- a/src/shapes/instance.cpp +++ b/src/shapes/instance.cpp @@ -16,93 +16,85 @@ along with this program. If not, see . */ -#include "shapegroup.h" +#include "instance.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::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(); - } +Instance::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 Instance::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!"); - } +void Instance::configure() { + if (!m_shapeGroup) + Log(EError, "A reference to a 'shapegroup' must be specified!"); +} - AABB getAABB() const { - const ShapeKDTree *kdtree = m_shapeGroup->getKDTree(); - const AABB &aabb = kdtree->getAABB(); - if (!aabb.isValid()) // the geometry group is empty - return aabb; - AABB result; - for (int i=0; i<8; ++i) - result.expandBy(m_objectToWorld(aabb.getCorner(i))); - return result; - } +AABB Instance::getAABB() const { + const ShapeKDTree *kdtree = m_shapeGroup->getKDTree(); + const AABB &aabb = kdtree->getAABB(); + if (!aabb.isValid()) // the geometry group is empty + return aabb; + 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; - } +Float Instance::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); - } +void Instance::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 ShapeKDTree *kdtree = m_shapeGroup->getKDTree(); - Ray ray; - m_worldToObject(_ray, ray); - return kdtree->rayIntersect(ray, mint, maxt, t, temp); - } +bool Instance::rayIntersect(const Ray &_ray, Float mint, + Float maxt, Float &t, void *temp) const { + const ShapeKDTree *kdtree = m_shapeGroup->getKDTree(); + Ray ray; + m_worldToObject(_ray, ray); + return kdtree->rayIntersect(ray, mint, maxt, t, temp); +} - bool rayIntersect(const Ray &_ray, Float mint, Float maxt) const { - const ShapeKDTree *kdtree = m_shapeGroup->getKDTree(); - Ray ray; - m_worldToObject(_ray, ray); - return kdtree->rayIntersect(ray, mint, maxt); - } +bool Instance::rayIntersect(const Ray &_ray, Float mint, Float maxt) const { + const ShapeKDTree *kdtree = m_shapeGroup->getKDTree(); + Ray ray; + m_worldToObject(_ray, ray); + return kdtree->rayIntersect(ray, mint, maxt); +} - void fillIntersectionRecord(const Ray &ray, - const void *temp, Intersection &its) const { - const ShapeKDTree *kdtree = m_shapeGroup->getKDTree(); - kdtree->fillIntersectionRecord(ray, temp, its); - its.shFrame.n = normalize(m_objectToWorld(its.shFrame.n)); - its.shFrame.s = normalize(m_objectToWorld(its.shFrame.s)); - its.shFrame.t = normalize(m_objectToWorld(its.shFrame.t)); - its.geoFrame = Frame(normalize(m_objectToWorld(its.geoFrame.n))); - its.wi = its.shFrame.toLocal(-ray.d); - its.dpdu = m_objectToWorld(its.dpdu); - its.dpdv = m_objectToWorld(its.dpdv); - } - - MTS_DECLARE_CLASS() -private: - ref m_shapeGroup; - Transform m_objectToWorld, m_worldToObject; -}; +void Instance::fillIntersectionRecord(const Ray &ray, + const void *temp, Intersection &its) const { + const ShapeKDTree *kdtree = m_shapeGroup->getKDTree(); + kdtree->fillIntersectionRecord(ray, temp, its); + its.shFrame.n = normalize(m_objectToWorld(its.shFrame.n)); + its.shFrame.s = normalize(m_objectToWorld(its.shFrame.s)); + its.shFrame.t = normalize(m_objectToWorld(its.shFrame.t)); + its.geoFrame = Frame(normalize(m_objectToWorld(its.geoFrame.n))); + its.wi = its.shFrame.toLocal(-ray.d); + its.dpdu = m_objectToWorld(its.dpdu); + its.dpdv = m_objectToWorld(its.dpdv); +} MTS_IMPLEMENT_CLASS_S(Instance, false, Shape) MTS_EXPORT_PLUGIN(Instance, "Instanced geometry"); diff --git a/src/shapes/instance.h b/src/shapes/instance.h new file mode 100644 index 00000000..f8ad245f --- /dev/null +++ b/src/shapes/instance.h @@ -0,0 +1,80 @@ +/* + 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 + +/** + * \brief Geometry instancing support (to be used in conjunction + * with the \c shapegroup plugin) + */ +class Instance : public Shape { +public: + /// Create a new instance based on properties from an XML file + Instance(const Properties &props); + + /// Unserialize from a binary data stream + Instance(Stream *stream, InstanceManager *manager); + + /// Serialize to a binary data stream + void serialize(Stream *stream, InstanceManager *manager) const; + + /** \brief Configure this object (called _once_ after construction + and addition of all child ConfigurableObjects.) */ + void configure(); + + /// Return the object-to-world transformation used by this instance + inline Transform getWorldTransform() const { return m_objectToWorld; } + + /// Add a child ConfigurableObject + void addChild(const std::string &name, ConfigurableObject *child); + + /// Return a pointer to the associated \ref ShapeGroup + inline ShapeGroup* getShapeGroup() { return m_shapeGroup; } + + /// Return a pointer to the associated \ref ShapeGroup (const version) + inline const ShapeGroup* getShapeGroup() const { return m_shapeGroup.get(); } + + // ============================================================= + //! @{ \name Implementation of the Shape interface + // ============================================================= + + AABB getAABB() const; + + Float getSurfaceArea() const; + + bool rayIntersect(const Ray &_ray, Float mint, + Float maxt, Float &t, void *temp) const; + + bool rayIntersect(const Ray &_ray, Float mint, Float maxt) const; + + void fillIntersectionRecord(const Ray &ray, + const void *temp, Intersection &its) const; + + + //! @} + // ============================================================= + + MTS_DECLARE_CLASS() +private: + ref m_shapeGroup; + Transform m_objectToWorld, m_worldToObject; +}; + +MTS_NAMESPACE_END diff --git a/src/shapes/shapegroup.h b/src/shapes/shapegroup.h index 2c8b5807..41104f59 100644 --- a/src/shapes/shapegroup.h +++ b/src/shapes/shapegroup.h @@ -25,10 +25,11 @@ 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. + * separate KD-tree. + * + * This shape doesn't actually generate any intersectable + * geometry on its own. Instead, the "instance" plugin must + * be used to create references to the geometry stored inside it. */ class ShapeGroup : public Shape { public: diff --git a/src/tests/test_quad.cpp b/src/tests/test_quad.cpp new file mode 100644 index 00000000..578ff85d --- /dev/null +++ b/src/tests/test_quad.cpp @@ -0,0 +1,44 @@ +/* + 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 + +MTS_NAMESPACE_BEGIN + +class TestQuadrature : public TestCase { +public: + MTS_BEGIN_TESTCASE() + MTS_DECLARE_TEST(test01_quad) + MTS_END_TESTCASE() + + Float testF(Float t) const { + return std::sin(t); + } + + void test01_quad() { + GaussLobattoIntegrator quad(1024, 0, 1e-6f); + Float result = quad.integrate(boost::bind(&TestQuadrature::testF, this, _1), 0, 10); + Float ref = 2 * std::pow(std::sin(5), 2); + assertEqualsEpsilon(result, ref, 1e-6f); + } +}; + +MTS_EXPORT_TESTCASE(TestQuadrature, "Testcase for quadrature routines") +MTS_NAMESPACE_END