diff --git a/utils/exporters/blender/addons/io_three/__init__.py b/utils/exporters/blender/addons/io_three/__init__.py index 15b4129ed86e4502aa7c9838fd3e572b24536b6b..b8a05893cb3158a047e05ac7053d812368623fae 100644 --- a/utils/exporters/blender/addons/io_three/__init__.py +++ b/utils/exporters/blender/addons/io_three/__init__.py @@ -303,6 +303,7 @@ def save_settings_export(properties): constants.EMBED_ANIMATION: properties.option_embed_animation, constants.LIGHTS: properties.option_lights, constants.CAMERAS: properties.option_cameras, + constants.HIERARCHY: properties.option_hierarchy, constants.MORPH_TARGETS: properties.option_animation_morph, constants.ANIMATION: properties.option_animation_skeletal, @@ -447,6 +448,10 @@ def restore_settings_export(properties): properties.option_cameras = settings.get( constants.CAMERAS, constants.EXPORT_OPTIONS[constants.CAMERAS]) + + properties.option_hierarchy = settings.get( + constants.HIERARCHY, + constants.EXPORT_OPTIONS[constants.HIERARCHY]) ## } ## Animation { @@ -638,6 +643,11 @@ class ExportThree(bpy.types.Operator, ExportHelper): description="Export default scene cameras", default=False) + option_hierarchy = BoolProperty( + name="Hierarchy", + description="Export object hierarchy", + default=False) + option_animation_morph = BoolProperty( name="Morph animation", description="Export animation (morphs)", @@ -811,6 +821,9 @@ class ExportThree(bpy.types.Operator, ExportHelper): row.prop(self.properties, 'option_cameras') ## } + row = layout.row() + row.prop(self.properties, 'option_hierarchy') + layout.separator() ## Settings { diff --git a/utils/exporters/blender/addons/io_three/constants.py b/utils/exporters/blender/addons/io_three/constants.py index 146ebee7b31c8519977cb2f5fd36af4ce06a2b4b..caa3d88ed6100cdc8dff77be10195476bdeb61ac 100644 --- a/utils/exporters/blender/addons/io_three/constants.py +++ b/utils/exporters/blender/addons/io_three/constants.py @@ -60,6 +60,7 @@ SKIN_WEIGHTS = 'skinWeights' LOGGING = 'logging' CAMERAS = 'cameras' LIGHTS = 'lights' +HIERARCHY = 'hierarchy' FACE_MATERIALS = 'faceMaterials' SKINNING = 'skinning' COPY_TEXTURES = 'copyTextures' @@ -110,6 +111,7 @@ EXPORT_OPTIONS = { MORPH_TARGETS: False, CAMERAS: False, LIGHTS: False, + HIERARCHY: False, COPY_TEXTURES: True, TEXTURE_FOLDER: '', LOGGING: DEBUG, @@ -160,6 +162,7 @@ POINT_LIGHT = 'PointLight' SPOT_LIGHT = 'SpotLight' HEMISPHERE_LIGHT = 'HemisphereLight' MESH = 'Mesh' +EMPTY = 'Empty' SPRITE = 'Sprite' DEFAULT_METADATA = { diff --git a/utils/exporters/blender/addons/io_three/exporter/api/object.py b/utils/exporters/blender/addons/io_three/exporter/api/object.py index ab7d40dcc609d84dabf2ac00d01b5ed3bee65c01..2e6c0cd5639516db2e9413810a8d06268e76cc18 100644 --- a/utils/exporters/blender/addons/io_three/exporter/api/object.py +++ b/utils/exporters/blender/addons/io_three/exporter/api/object.py @@ -2,6 +2,7 @@ import math import mathutils import bpy from bpy import data, context, types +from bpy_extras.io_utils import axis_conversion from .. import constants, logger, utilities, exceptions from .constants import ( MESH, @@ -225,14 +226,8 @@ def position(obj, options): """ logger.debug('object.position(%s)', obj) - vector = _decompose_matrix(obj)[0] - vector = (vector.x, vector.y, vector.z) - - round_off, round_val = utilities.rounding(options) - if round_off: - vector = utilities.round_off(vector, round_val) - - return vector + vector = matrix(obj, options).to_translation() + return (vector.x, vector.y, vector.z) @_object @@ -250,23 +245,35 @@ def receive_shadow(obj): return False +AXIS_CONVERSION = axis_conversion(to_forward='Z', to_up='Y').to_4x4() + @_object -def rotation(obj, options): +def matrix(obj, options): """ :param obj: :param options: """ - logger.debug('object.rotation(%s)', obj) - vector = _decompose_matrix(obj)[1].to_euler(ZYX) - vector = (vector.x, vector.y, vector.z) + logger.debug('object.matrix(%s)', obj) + if options.get(constants.HIERARCHY, False) and obj.parent: + parent_inverted = obj.parent.matrix_world.inverted(mathutils.Matrix()) + return parent_inverted * obj.matrix_world + else: + return AXIS_CONVERSION * obj.matrix_world + - round_off, round_val = utilities.rounding(options) - if round_off: - vector = utilities.round_off(vector, round_val) +@_object +def rotation(obj, options): + """ + + :param obj: + :param options: - return vector + """ + logger.debug('object.rotation(%s)', obj) + vector = matrix(obj, options).to_euler(ZYX) + return (vector.x, vector.y, vector.z) @_object @@ -278,14 +285,8 @@ def scale(obj, options): """ logger.debug('object.scale(%s)', obj) - vector = _decompose_matrix(obj)[2] - vector = (vector.x, vector.y, vector.z) - - round_off, round_val = utilities.rounding(options) - if round_off: - vector = utilities.round_off(vector, round_val) - - return vector + vector = matrix(obj, options).to_scale() + return (vector.x, vector.y, vector.z) @_object @@ -477,24 +478,6 @@ def extracted_meshes(): return [key for key in _MESH_MAP.keys()] -def _decompose_matrix(obj, local=False): - """ - - :param obj: - :param local: (Default value = False) - - """ - rotate_x_pi2 = mathutils.Quaternion((1.0, 0.0, 0.0), - math.radians(-90.0)) - rotate_x_pi2 = rotate_x_pi2.to_matrix().to_4x4() - - if local: - matrix = rotate_x_pi2 * obj.matrix_local - else: - matrix = rotate_x_pi2 * obj.matrix_world - return matrix.decompose() - - def _on_visible_layer(obj, visible_layers): """ diff --git a/utils/exporters/blender/addons/io_three/exporter/object.py b/utils/exporters/blender/addons/io_three/exporter/object.py index a69c43fc7b31e57da91f7a8107d8f09e1061a9d4..3da492f540f442bc0983faa6de8c182142e58842 100644 --- a/utils/exporters/blender/addons/io_three/exporter/object.py +++ b/utils/exporters/blender/addons/io_three/exporter/object.py @@ -68,14 +68,13 @@ class Object(base_classes.BaseNode): logger.debug("Object()._node_setup()") self[constants.NAME] = api.object.name(self.node) - self[constants.POSITION] = api.object.position( - self.node, self.options) + transform = api.object.matrix(self.node, self.options) + matrix = [] + for col in range(0, 4): + for row in range(0, 4): + matrix.append(transform[row][col]) - self[constants.ROTATION] = api.object.rotation( - self.node, self.options) - - self[constants.SCALE] = api.object.scale( - self.node, self.options) + self[constants.MATRIX] = matrix self[constants.VISIBLE] = api.object.visible(self.node) @@ -120,11 +119,12 @@ class Object(base_classes.BaseNode): elif self[constants.TYPE] in lights: self._init_light() - #for child in api.object.children(self.node, self.scene.valid_types): - # if not self.get(constants.CHILDREN): - # self[constants.CHILDREN] = [Object(child, parent=self)] - # else: - # self[constants.CHILDREN].append(Object(child, parent=self)) + if self.options.get(constants.HIERARCHY, False): + for child in api.object.children(self.node, self.scene.valid_types): + if not self.get(constants.CHILDREN): + self[constants.CHILDREN] = [Object(child, parent=self)] + else: + self[constants.CHILDREN].append(Object(child, parent=self)) def _root_setup(self): """Applies to a root/scene object""" diff --git a/utils/exporters/blender/addons/io_three/exporter/scene.py b/utils/exporters/blender/addons/io_three/exporter/scene.py index 6fbf3e3641e28935db1068a418693aabf0334871..cb78709ad703d3a357dcd71fefa82c496350d6ba 100644 --- a/utils/exporters/blender/addons/io_three/exporter/scene.py +++ b/utils/exporters/blender/addons/io_three/exporter/scene.py @@ -39,6 +39,9 @@ class Scene(base_classes.BaseScene): """ valid_types = [api.constants.MESH] + if self.options.get(constants.HIERARCHY, False): + valid_types.append(api.constants.EMPTY) + if self.options.get(constants.CAMERAS): logger.info("Adding cameras to valid object types") valid_types.append(api.constants.CAMERA) @@ -207,7 +210,12 @@ class Scene(base_classes.BaseScene): self[constants.UUID] = utilities.id_from_name(scene_name) objects = [] - for node in api.object.nodes(self.valid_types, self.options): + if self.options.get(constants.HIERARCHY, False): + nodes = api.object.assemblies(self.valid_types, self.options) + else: + nodes = api.object.nodes(self.valid_types, self.options) + + for node in nodes: logger.info("Parsing object %s", node) obj = object_.Object(node, parent=self[constants.OBJECT]) objects.append(obj)