diff --git a/schema/scene.xsd b/schema/scene.xsd index d39f4eaa..cf712b76 100644 --- a/schema/scene.xsd +++ b/schema/scene.xsd @@ -98,20 +98,12 @@ - - - - - - - - - - + + diff --git a/src/converter/collada.cpp b/src/converter/collada.cpp index b8640447..58da730c 100644 --- a/src/converter/collada.cpp +++ b/src/converter/collada.cpp @@ -1621,20 +1621,22 @@ void GeometryConverter::convertCollada(const fs::path &inputFile, } } - domLibrary_animations_Array &libraryAnimations = document->getLibrary_animations_array(); - for (size_t i=0; igetAnimation_array(); - for (size_t j=0; jgetLibrary_animations_array(); + for (size_t i=0; igetAnimation_array(); + for (size_t j=0; jsecond->decRef(); diff --git a/src/converter/converter.cpp b/src/converter/converter.cpp index 36b274ea..8de406e0 100644 --- a/src/converter/converter.cpp +++ b/src/converter/converter.cpp @@ -195,9 +195,11 @@ void GeometryConverter::convert(const fs::path &inputFile, if (id != "" && nodeMap.find(id) != nodeMap.end()) { DOMNode *node = nodeMap[id], *parent = node->getParentNode(); if (strcmp(nodeName, "append") == 0) { - DOMNode *node = nodeMap[id]; for (DOMNode *child2 = child->getFirstChild(); child2 != 0; child2=child2->getNextSibling()) node->insertBefore(doc->importNode(child2, true), NULL); + } else if (strcmp(nodeName, "prepend") == 0) { + for (DOMNode *child2 = child->getFirstChild(); child2 != 0; child2=child2->getNextSibling()) + node->insertBefore(doc->importNode(child2, true), node->getFirstChild()); } else if (parent == insertBeforeNode->getParentNode()) { parent->removeChild(node); docRoot->insertBefore(doc->importNode(child, true), insertBeforeNode); @@ -212,10 +214,13 @@ void GeometryConverter::convert(const fs::path &inputFile, } DOMLSSerializer *serializer = impl->createLSSerializer(); - DOMConfiguration *serConf(serializer->getDomConfig()); - DOMLSOutput *output = impl->createLSOutput(); + DOMConfiguration *serConf = serializer->getDomConfig(); serConf->setParameter(XMLUni::fgDOMErrorHandler, &errorHandler); - serConf->setParameter(XMLUni::fgDOMWRTFormatPrettyPrint, true); + if (serConf->canSetParameter(XMLUni::fgDOMWRTFormatPrettyPrint, true)) + serConf->setParameter(XMLUni::fgDOMWRTFormatPrettyPrint, true); + if (serConf->canSetParameter(XMLUni::fgDOMWRTXercesPrettyPrint, true)) + serConf->setParameter(XMLUni::fgDOMWRTXercesPrettyPrint, true); + DOMLSOutput *output = impl->createLSOutput(); XMLFormatTarget *target = new LocalFileFormatTarget(outputFile.file_string().c_str()); output->setByteStream(target); serializer->write(doc, output); diff --git a/src/converter/converter.h b/src/converter/converter.h index 00dc4c4a..6ebec4ad 100644 --- a/src/converter/converter.h +++ b/src/converter/converter.h @@ -28,6 +28,8 @@ public: m_xres = m_yres = -1; m_filmType = "exrfilm"; m_packGeometry = true; + m_importMaterials = true; + m_importAnimations = false; } void convert(const fs::path &inputFile, @@ -42,6 +44,7 @@ public: inline void setResolution(int xres, int yres) { m_xres = xres; m_yres = yres; } inline void setPackGeometry(bool packGeometry) { m_packGeometry = packGeometry; } inline void setImportMaterials(bool importMaterials) { m_importMaterials = importMaterials; } + inline void setImportAnimations(bool importAnimations) { m_importAnimations = importAnimations; } inline void setFilmType(const std::string &filmType) { m_filmType = filmType; } inline const fs::path &getFilename() const { return m_filename; } private: @@ -52,7 +55,8 @@ private: const fs::path &textureDirectory, const fs::path &meshesDirectory); public: - bool m_srgb, m_mapSmallerSide, m_importMaterials; + bool m_srgb, m_mapSmallerSide; + bool m_importMaterials, m_importAnimations; int m_xres, m_yres; fs::path m_filename, m_outputDirectory; std::string m_filmType; diff --git a/src/converter/mtsimport.cpp b/src/converter/mtsimport.cpp index 2724666f..c3fce045 100644 --- a/src/converter/mtsimport.cpp +++ b/src/converter/mtsimport.cpp @@ -56,6 +56,7 @@ void help() { << " -v Be more verbose" << endl << endl << " -s Assume that colors are in sRGB space." << endl << endl << " -m Map the larger image side to the full field of view" << endl << endl + << " -z Import animations" << endl << endl << " -y Don't pack all geometry data into a single file" << endl << endl << " -n Don't import any materials (an adjustments file will be necessary)" << endl << endl << " -l Override the type of film (e.g. 'exrfilm', 'pngfilm', ..)" << endl << endl @@ -70,12 +71,12 @@ int colladaMain(int argc, char **argv) { std::string filmType = "exrfilm"; FileResolver *fileResolver = Thread::getThread()->getFileResolver(); ELogLevel logLevel = EInfo; - bool packGeometry = true; - bool importMaterials = true; + bool packGeometry = true, importMaterials = true, + importAnimations = false; optind = 1; - while ((optchar = getopt(argc, argv, "snvyhmr:a:l:")) != -1) { + while ((optchar = getopt(argc, argv, "snzvyhmr:a:l:")) != -1) { switch (optchar) { case 'a': { std::vector paths = tokenize(optarg, ";"); @@ -92,6 +93,9 @@ int colladaMain(int argc, char **argv) { case 'n': importMaterials = false; break; + case 'z': + importAnimations = true; + break; case 'v': logLevel = EDebug; break; @@ -132,6 +136,7 @@ int colladaMain(int argc, char **argv) { converter.setSRGB(srgb); converter.setResolution(xres, yres); converter.setImportMaterials(importMaterials); + converter.setImportAnimations(importAnimations); converter.setMapSmallerSide(mapSmallerSide); converter.setPackGeometry(packGeometry); converter.setFilmType(filmType); diff --git a/tools/blender/mitsuba/export/adjustments.py b/tools/blender/mitsuba/export/adjustments.py index af76f533..fba4346b 100644 --- a/tools/blender/mitsuba/export/adjustments.py +++ b/tools/blender/mitsuba/export/adjustments.py @@ -215,6 +215,17 @@ class MtsAdjustments: self.out.write('\t\t\n') self.out.write('\n') + def exportCameraSettings(self, scene, camera): + if scene.mitsuba_integrator.motionblur: + frameTime = 1.0/scene.render.fps + shuttertime = scene.mitsuba_integrator.shuttertime + shutterOpen = (scene.frame_current - shuttertime/2) * frameTime + shutterClose = (scene.frame_current + shuttertime/2) * frameTime + self.out.write('\t\n' % translate_id(camera.name)) + self.out.write('\t\t\n' % shutterOpen) + self.out.write('\t\t\n' % shutterClose) + self.out.write('\t\n') + def export(self, scene): idx = 0 self.writeHeader() @@ -228,6 +239,8 @@ class MtsAdjustments: self.exportMaterial(mat) if len(obj.data.materials) > 0 and obj.data.materials[0].mitsuba_emission.use_emission: self.exportEmission(obj) + elif obj.type == 'CAMERA': + self.exportCameraSettings(scene, obj) idx = idx+1 self.writeFooter() diff --git a/tools/blender/mitsuba/operators/__init__.py b/tools/blender/mitsuba/operators/__init__.py index 5ae467a7..616e7728 100644 --- a/tools/blender/mitsuba/operators/__init__.py +++ b/tools/blender/mitsuba/operators/__init__.py @@ -184,9 +184,11 @@ class EXPORT_OT_mitsuba(bpy.types.Operator): MtsLog("MtsBlend: Launching mtsimport") try: - process = subprocess.Popen( - [mtsimport_binary, '-r', '%dx%d' % (width, height), - '-n', '-l', 'pngfilm', mts_dae_file, mts_xml_file, mts_adj_file], + command = [mtsimport_binary, '-r', '%dx%d' % (width, height), + '-n', '-l', 'pngfilm', mts_dae_file, mts_xml_file, mts_adj_file] + if scene.mitsuba_integrator.motionblur: + command += ['-z'] + process = subprocess.Popen(command, env = env, cwd = mts_path ) diff --git a/tools/blender/mitsuba/properties/integrator.py b/tools/blender/mitsuba/properties/integrator.py index d532a86f..7391fd1e 100644 --- a/tools/blender/mitsuba/properties/integrator.py +++ b/tools/blender/mitsuba/properties/integrator.py @@ -28,8 +28,13 @@ class mitsuba_integrator(declarative_property_group): controls = [ 'type', - 'sampleCount' + ['motionblur', + 'shuttertime'] ] + + visibility = { + 'shuttertime': { 'motionblur': True } + } properties = [ { @@ -43,6 +48,24 @@ class mitsuba_integrator(declarative_property_group): ('path', 'Path tracer', 'path'), ], 'save_in_preset': True + }, + { + 'type': 'bool', + 'attr': 'motionblur', + 'name': 'Motion Blur', + 'description': 'Should motion blur be enabled?', + 'default' : False, + 'save_in_preset': True + }, + { + 'type': 'float', + 'attr': 'shuttertime', + 'name': 'Shutter time', + 'description': 'Amount of time, for which the shutter remains open (measured in frames)', + 'save_in_preset': True, + 'min': 0, + 'max': 100, + 'default': 1 } ] diff --git a/tools/blender/mitsuba/ui/materials/__init__.py b/tools/blender/mitsuba/ui/materials/__init__.py index f1565d64..8b4e64e8 100644 --- a/tools/blender/mitsuba/ui/materials/__init__.py +++ b/tools/blender/mitsuba/ui/materials/__init__.py @@ -16,7 +16,7 @@ # # ##### END GPL LICENSE BLOCK ##### -import bpy, copy +import bpy from properties_material import MaterialButtonsPanel from extensions_framework.ui import property_group_renderer @@ -27,13 +27,20 @@ material_cache = {} cached_spp = None cached_depth = None +def copy(value): + if value == None or isinstance(value, str) or isinstance(value, bool) \ + or isinstance(value, float) or isinstance(value, int): + return value + elif getattr(value, '__len__', False): + return list(value) + else: + raise Exception("Copy: don't know how to handle '%s'" % str(vlaue)) + class mitsuba_material_base(MaterialButtonsPanel, property_group_renderer): COMPAT_ENGINES = {'mitsuba'} MTS_PROPS = ['type'] - def draw(self, context): - if not hasattr(context, 'material'): - return + def validate(self, context): global material_cache mat = context.material if mat.name in material_cache: @@ -45,15 +52,20 @@ class mitsuba_material_base(MaterialButtonsPanel, property_group_renderer): mat = self.get_contents(mat) repaint = False for prop in self.MTS_PROPS: - prop_value = getattr(mat, prop) + prop_value = copy(getattr(mat, prop)) prop_cache_value = mat_cached[prop] if prop in mat_cached else None if prop_cache_value != prop_value: - mat_cached[prop] = copy.copy(prop_value) + mat_cached[prop] = prop_value repaint = True if repaint: # Cause a repaint MtsLog("Forcing a repaint") context.material.preview_render_type = context.material.preview_render_type + + def draw(self, context): + if not hasattr(context, 'material'): + return + self.validate(context) return super().draw(context) def get_contents(self, mat): @@ -93,10 +105,10 @@ class mitsuba_material_sub(MaterialButtonsPanel, property_group_renderer): repaint = False for prop_entry in props: prop = prop_entry['attr'] - prop_value = getattr(mat, prop) if hasattr(mat, prop) else None + prop_value = copy(getattr(mat, prop) if hasattr(mat, prop) else None) prop_cache_value = mat_cached[prop] if prop in mat_cached else None - if prop_cache_value != prop_value: - mat_cached[prop] = copy.copy(prop_value) + if prop_cache_value != copy(prop_value): + mat_cached[prop] = prop_value repaint = True if repaint: # Cause a repaint diff --git a/tools/blender/mitsuba/ui/materials/emission.py b/tools/blender/mitsuba/ui/materials/emission.py index 295854b2..8a4a1f01 100644 --- a/tools/blender/mitsuba/ui/materials/emission.py +++ b/tools/blender/mitsuba/ui/materials/emission.py @@ -41,3 +41,4 @@ class emission(mitsuba_material_base, bpy.types.Panel): if hasattr(context, "material"): mat = active_node_mat(context.material) self.layout.prop(mat.mitsuba_emission, "use_emission", text="") + self.validate(context)