diff --git a/io_scene_gltf2/__init__.py b/io_scene_gltf2/__init__.py index 48574ef41405e3d283add83a35a5df0620592c68..3852f105756b59b322d245ad92f86ac75b62d596 100755 --- a/io_scene_gltf2/__init__.py +++ b/io_scene_gltf2/__init__.py @@ -15,7 +15,7 @@ bl_info = { 'name': 'glTF 2.0 format', 'author': 'Julien Duroure, Norbert Nopper, Urs Hanselmann, Moritz Becher, Benjamin SchmithĂĽsen, Jim Eckerlein, and many external contributors', - "version": (1, 0, 5), + "version": (1, 0, 6), 'blender': (2, 81, 6), 'location': 'File > Import-Export', 'description': 'Import-Export as glTF 2.0', @@ -257,6 +257,12 @@ class ExportGLTF2_Base: default=True ) + export_def_bones: BoolProperty( + name='Export Deformation bones only', + description='Export Deformation bones only (and needed bones for hierarchy)', + default=False + ) + export_current_frame: BoolProperty( name='Use Current Frame', description='Export the scene in the current animation frame', @@ -390,11 +396,16 @@ class ExportGLTF2_Base: if self.export_animations: export_settings['gltf_frame_range'] = self.export_frame_range export_settings['gltf_force_sampling'] = self.export_force_sampling + if self.export_force_sampling: + export_settings['gltf_def_bones'] = self.export_def_bones + else: + export_settings['gltf_def_bones'] = False export_settings['gltf_nla_strips'] = self.export_nla_strips else: export_settings['gltf_frame_range'] = False export_settings['gltf_move_keyframes'] = False export_settings['gltf_force_sampling'] = False + export_settings['gltf_def_bones'] = False export_settings['gltf_skins'] = self.export_skins if self.export_skins: export_settings['gltf_all_vertex_influences'] = self.export_all_influences @@ -643,6 +654,10 @@ class GLTF_PT_export_animation_export(bpy.types.Panel): layout.prop(operator, 'export_force_sampling') layout.prop(operator, 'export_nla_strips') + row = layout.row() + row.active = operator.export_force_sampling + row.prop(operator, 'export_def_bones') + class GLTF_PT_export_animation_shapekeys(bpy.types.Panel): bl_space_type = 'FILE_BROWSER' diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_channel_target.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_channel_target.py index 04028d20805e4b5453636348d4b9f603e93a0806..fa0f9976db418081bed81dedb51619cb2cea8625 100755 --- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_channel_target.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_channel_target.py @@ -19,7 +19,7 @@ from io_scene_gltf2.io.com import gltf2_io from io_scene_gltf2.blender.exp.gltf2_blender_gather_cache import cached from io_scene_gltf2.blender.exp import gltf2_blender_gather_nodes from io_scene_gltf2.blender.exp import gltf2_blender_gather_joints - +from io_scene_gltf2.blender.exp import gltf2_blender_gather_skins @cached def gather_animation_channel_target(channels: typing.Tuple[bpy.types.FCurve], @@ -66,7 +66,12 @@ def __gather_node(channels: typing.Tuple[bpy.types.FCurve], blender_bone = blender_object.path_resolve(channels[0].data_path.rsplit('.', 1)[0]) if isinstance(blender_bone, bpy.types.PoseBone): - return gltf2_blender_gather_joints.gather_joint(blender_bone, export_settings) + if export_settings["gltf_def_bones"] is False: + return gltf2_blender_gather_joints.gather_joint(blender_bone, export_settings) + else: + bones, _, _ = gltf2_blender_gather_skins.get_bone_tree(None, blender_object) + if blender_bone.name in [b.name for b in bones]: + return gltf2_blender_gather_joints.gather_joint(blender_bone, export_settings) return gltf2_blender_gather_nodes.gather_node(blender_object, None, export_settings) diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_channels.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_channels.py index edee0971627e3e3a521d938f9990271a599dee3f..611cd74a4de78fc9f7a10f5f549b922aef37d831 100755 --- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_channels.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_channels.py @@ -22,6 +22,7 @@ from io_scene_gltf2.blender.exp.gltf2_blender_gather_cache import cached from io_scene_gltf2.blender.exp import gltf2_blender_gather_animation_samplers from io_scene_gltf2.blender.exp import gltf2_blender_gather_animation_channel_target from io_scene_gltf2.blender.exp import gltf2_blender_get +from io_scene_gltf2.blender.exp import gltf2_blender_gather_skins @cached @@ -58,7 +59,14 @@ def gather_animation_channels(blender_action: bpy.types.Action, return [] # Then bake all bones - for bone in blender_object.data.bones: + bones_to_be_animated = [] + if export_settings["gltf_def_bones"] is False: + bones_to_be_animated = blender_object.data.bones + else: + bones_to_be_animated, _, _ = gltf2_blender_gather_skins.get_bone_tree(None, blender_object) + bones_to_be_animated = [blender_object.pose.bones[b.name] for b in bones_to_be_animated] + + for bone in bones_to_be_animated: for p in ["location", "rotation_quaternion", "scale"]: channel = __gather_animation_channel( (), diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_gather_joints.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather_joints.py index 2059ea88977fdebac996126948d279abbccf6b4d..dce70c31c0f058d8a4ce7faa006f8947a2412201 100755 --- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_joints.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_joints.py @@ -20,6 +20,7 @@ from io_scene_gltf2.io.com import gltf2_io from io_scene_gltf2.io.com import gltf2_io_debug from io_scene_gltf2.blender.exp import gltf2_blender_extract from io_scene_gltf2.blender.com import gltf2_blender_math +from io_scene_gltf2.blender.exp import gltf2_blender_gather_skins @cached @@ -55,8 +56,15 @@ def gather_joint(blender_bone, export_settings): # traverse into children children = [] - for bone in blender_bone.children: - children.append(gather_joint(bone, export_settings)) + + if export_settings["gltf_def_bones"] is False: + for bone in blender_bone.children: + children.append(gather_joint(bone, export_settings)) + else: + _, children_, _ = gltf2_blender_gather_skins.get_bone_tree(None, blender_bone.id_data) + if blender_bone.name in children_.keys(): + for bone in children_[blender_bone.name]: + children.append(gather_joint(blender_bone.id_data.pose.bones[bone], export_settings)) # finally add to the joints array containing all the joints in the hierarchy return gltf2_io.Node( diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_gather_nodes.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather_nodes.py index 327450277a9e98770925a232fd088dd91d07c7c1..8af73b5d766ceace88981d266c7fd95d6f73e89e 100755 --- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_nodes.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_nodes.py @@ -135,7 +135,12 @@ def __gather_children(blender_object, blender_scene, export_settings): # blender bones if blender_object.type == "ARMATURE": root_joints = [] - for blender_bone in blender_object.pose.bones: + if export_settings["gltf_def_bones"] is False: + bones = blender_object.pose.bones + else: + bones, _, _ = gltf2_blender_gather_skins.get_bone_tree(None, blender_object) + bones = [blender_object.pose.bones[b.name] for b in bones] + for blender_bone in bones: if not blender_bone.parent: joint = gltf2_blender_gather_joints.gather_joint(blender_bone, export_settings) children.append(joint) diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_gather_skins.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather_skins.py index 59af7d7208b3c86d65427e116d2ce7b63409906f..18503fddefe7d25b8b27409fe5d07da9bf8a77b5 100755 --- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_skins.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_skins.py @@ -67,11 +67,14 @@ def __gather_inverse_bind_matrices(blender_object, export_settings): axis_basis_change = mathutils.Matrix( ((1.0, 0.0, 0.0, 0.0), (0.0, 0.0, 1.0, 0.0), (0.0, -1.0, 0.0, 0.0), (0.0, 0.0, 0.0, 1.0))) - # build the hierarchy of nodes out of the bones - root_bones = [] - for blender_bone in blender_object.pose.bones: - if not blender_bone.parent: - root_bones.append(blender_bone) + if export_settings['gltf_def_bones'] is False: + # build the hierarchy of nodes out of the bones + root_bones = [] + for blender_bone in blender_object.pose.bones: + if not blender_bone.parent: + root_bones.append(blender_bone) + else: + _, children_, root_bones = get_bone_tree(None, blender_object) matrices = [] @@ -86,8 +89,13 @@ def __gather_inverse_bind_matrices(blender_object, export_settings): ).inverted() matrices.append(inverse_bind_matrix) - for child in bone.children: - __collect_matrices(child) + if export_settings['gltf_def_bones'] is False: + for child in bone.children: + __collect_matrices(child) + else: + if bone.name in children_.keys(): + for child in children_[bone.name]: + __collect_matrices(blender_object.pose.bones[child]) # start with the "root" bones and recurse into children, in the same ordering as the how joints are gathered for root_bone in root_bones: @@ -114,18 +122,28 @@ def __gather_inverse_bind_matrices(blender_object, export_settings): def __gather_joints(blender_object, export_settings): root_joints = [] - # build the hierarchy of nodes out of the bones - for blender_bone in blender_object.pose.bones: - if not blender_bone.parent: - root_joints.append(gltf2_blender_gather_joints.gather_joint(blender_bone, export_settings)) + if export_settings['gltf_def_bones'] is False: + # build the hierarchy of nodes out of the bones + for blender_bone in blender_object.pose.bones: + if not blender_bone.parent: + root_joints.append(gltf2_blender_gather_joints.gather_joint(blender_bone, export_settings)) + else: + _, children_, root_joints = get_bone_tree(None, blender_object) + root_joints = [gltf2_blender_gather_joints.gather_joint(i, export_settings) for i in root_joints] # joints is a flat list containing all nodes belonging to the skin joints = [] def __collect_joints(node): joints.append(node) - for child in node.children: - __collect_joints(child) + if export_settings['gltf_def_bones'] is False: + for child in node.children: + __collect_joints(child) + else: + if node.name in children_.keys(): + for child in children_[node.name]: + __collect_joints(gltf2_blender_gather_joints.gather_joint(blender_object.pose.bones[child], export_settings)) + for joint in root_joints: __collect_joints(joint) @@ -140,3 +158,30 @@ def __gather_skeleton(blender_object, export_settings): # In the future support the result of https://github.com/KhronosGroup/glTF/pull/1195 return None # gltf2_blender_gather_nodes.gather_node(blender_object, blender_scene, export_settings) +@cached +def get_bone_tree(blender_dummy, blender_object): + + bones = [] + children = {} + root_bones = [] + + def get_parent(bone): + bones.append(bone.name) + if bone.parent is not None: + if bone.parent.name not in children.keys(): + children[bone.parent.name] = [] + children[bone.parent.name].append(bone.name) + get_parent(bone.parent) + else: + root_bones.append(bone.name) + + for bone in [b for b in blender_object.data.bones if b.use_deform is True]: + get_parent(bone) + + # remove duplicates + for k, v in children.items(): + children[k] = list(set(v)) + list_ = list(set(bones)) + root_ = list(set(root_bones)) + return [blender_object.data.bones[b] for b in list_], children, [blender_object.pose.bones[b] for b in root_] +