diff options
author | Julien Duroure <julien.duroure@gmail.com> | 2020-03-20 00:44:06 +0300 |
---|---|---|
committer | Julien Duroure <julien.duroure@gmail.com> | 2020-03-20 00:44:06 +0300 |
commit | 191bcee579b30af4098fb2af701470f8b05b6065 (patch) | |
tree | 3fe837f79b4c40b79eb9e4381390f6974b3859a4 | |
parent | dc4c83cffc6b6db19f757db5012050a234f00424 (diff) |
glTF export: manage collection instances / linked collection / armature proxy
13 files changed, 86 insertions, 47 deletions
diff --git a/io_scene_gltf2/__init__.py b/io_scene_gltf2/__init__.py index 01a4402c..b52fe818 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, 2, 50), + "version": (1, 2, 51), 'blender': (2, 82, 7), 'location': 'File > Import-Export', 'description': 'Import-Export as glTF 2.0', diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_export.py b/io_scene_gltf2/blender/exp/gltf2_blender_export.py index 6d9ab8bb..2989ec31 100755 --- a/io_scene_gltf2/blender/exp/gltf2_blender_export.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_export.py @@ -30,7 +30,8 @@ from io_scene_gltf2.io.exp.gltf2_io_user_extensions import export_user_extension def save(context, export_settings): """Start the glTF 2.0 export and saves to content either to a .gltf or .glb file.""" if bpy.context.active_object is not None: - bpy.ops.object.mode_set(mode='OBJECT') + if bpy.context.active_object.mode != "OBJECT": # For linked object, you can't force OBJECT mode + bpy.ops.object.mode_set(mode='OBJECT') original_frame = bpy.context.scene.frame_current if not export_settings['gltf_current_frame']: diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_extract.py b/io_scene_gltf2/blender/exp/gltf2_blender_extract.py index bb7451ad..955c5d13 100755 --- a/io_scene_gltf2/blender/exp/gltf2_blender_extract.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_extract.py @@ -423,7 +423,7 @@ def extract_primitive_pack(a, indices, use_tangents): return result_primitive -def extract_primitives(glTF, blender_mesh, blender_object, blender_vertex_groups, modifiers, export_settings): +def extract_primitives(glTF, blender_mesh, library, blender_object, blender_vertex_groups, modifiers, export_settings): """ Extract primitives from a mesh. Polygons are triangulated and sorted by material. diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_gather.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather.py index f08a379b..c6fd2c38 100755 --- a/io_scene_gltf2/blender/exp/gltf2_blender_gather.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather.py @@ -51,9 +51,13 @@ def __gather_scene(blender_scene, export_settings): nodes=[] ) - for blender_object in blender_scene.objects: - if blender_object.parent is None: - node = gltf2_blender_gather_nodes.gather_node(blender_object, blender_scene, export_settings) + for _blender_object in [obj for obj in blender_scene.objects if obj.proxy is None]: + if _blender_object.parent is None: + blender_object = _blender_object.proxy if _blender_object.proxy else _blender_object + node = gltf2_blender_gather_nodes.gather_node( + blender_object, + blender_object.library.name if blender_object.library else None, + blender_scene, None, export_settings) if node is not None: scene.nodes.append(node) @@ -66,11 +70,17 @@ def __gather_animations(blender_scene, export_settings): animations = [] merged_tracks = {} - for blender_object in blender_scene.objects: + for _blender_object in blender_scene.objects: + + blender_object = _blender_object.proxy if _blender_object.proxy else _blender_object + # First check if this object is exported or not. Do not export animation of not exported object - obj_node = gltf2_blender_gather_nodes.gather_node(blender_object, blender_scene, export_settings) + obj_node = gltf2_blender_gather_nodes.gather_node(blender_object, + blender_object.library.name if blender_object.library else None, + blender_scene, None, export_settings) if obj_node is not None: - animations_, merged_tracks = gltf2_blender_gather_animations.gather_animations(blender_object, merged_tracks, len(animations), export_settings) + # Check was done on armature, but use here the _proxy object, because this is where the animation is + animations_, merged_tracks = gltf2_blender_gather_animations.gather_animations(_blender_object, merged_tracks, len(animations), export_settings) animations += animations_ if export_settings['gltf_nla_strips'] is False: 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 9dfbea34..6edf52cc 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 @@ -72,7 +72,9 @@ def __gather_node(channels: typing.Tuple[bpy.types.FCurve], ) -> gltf2_io.Node: if driver_obj is not None: - return gltf2_blender_gather_nodes.gather_node(driver_obj, None, export_settings) + return gltf2_blender_gather_nodes.gather_node(driver_obj, + driver_obj.library.name if driver_obj.library else None, + None, None, export_settings) if blender_object.type == "ARMATURE": # TODO: get joint from fcurve data_path and gather_joint @@ -84,13 +86,17 @@ def __gather_node(channels: typing.Tuple[bpy.types.FCurve], if isinstance(blender_bone, bpy.types.PoseBone): if export_settings["gltf_def_bones"] is False: - return gltf2_blender_gather_joints.gather_joint(blender_bone, export_settings) + obj = blender_object.proxy if blender_object.proxy else blender_object + return gltf2_blender_gather_joints.gather_joint(obj, 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) + obj = blender_object.proxy if blender_object.proxy else blender_object + return gltf2_blender_gather_joints.gather_jointb(obj, blender_bone, export_settings) - return gltf2_blender_gather_nodes.gather_node(blender_object, None, export_settings) + return gltf2_blender_gather_nodes.gather_node(blender_object, + blender_object.library.name if blender_object.library else None, + None, None, export_settings) def __gather_path(channels: typing.Tuple[bpy.types.FCurve], 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 99a0ef91..6868047e 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 @@ -97,7 +97,8 @@ def gather_animation_channels(blender_action: bpy.types.Action, # Retrieve channels for drivers, if needed - drivers_to_manage = gltf2_blender_gather_drivers.get_sk_drivers(blender_object) + obj_driver = blender_object.proxy if blender_object.proxy else blender_object + drivers_to_manage = gltf2_blender_gather_drivers.get_sk_drivers(obj_driver) for obj, fcurves in drivers_to_manage: channel = __gather_animation_channel( fcurves, diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_sampler_keyframes.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_sampler_keyframes.py index 89559719..6fa5a11d 100755 --- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_sampler_keyframes.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_sampler_keyframes.py @@ -168,7 +168,8 @@ def get_bone_matrix(blender_object_if_armature: typing.Optional[bpy.types.Object # If some drivers must be evaluated, do it here, to avoid to have to change frame by frame later - drivers_to_manage = get_sk_drivers(blender_object_if_armature) + obj_driver = blender_object_if_armature.proxy if blender_object_if_armature.proxy else blender_object_if_armature + drivers_to_manage = get_sk_drivers(obj_driver) for dr_obj, dr_fcurves in drivers_to_manage: vals = get_sk_driver_values(dr_obj, frame, dr_fcurves) diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_gather_cache.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather_cache.py index e82d5929..7f05f751 100755 --- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_cache.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_cache.py @@ -39,7 +39,7 @@ def cached(func): export_settings = args[-1] cache_key_args = args[:-1] - __by_name = [bpy.types.Object, bpy.types.Scene, bpy.types.Material, bpy.types.Action, bpy.types.Mesh] + __by_name = [bpy.types.Object, bpy.types.Scene, bpy.types.Material, bpy.types.Action, bpy.types.Mesh, bpy.types.PoseBone] # we make a tuple from the function arguments so that they can be used as a key to the cache cache_key = () 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 6b693575..a95efb91 100755 --- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_joints.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_joints.py @@ -24,7 +24,7 @@ from io_scene_gltf2.blender.exp import gltf2_blender_gather_skins @cached -def gather_joint(blender_bone, export_settings): +def gather_joint(blender_object, blender_bone, export_settings): """ Generate a glTF2 node from a blender bone, as joints in glTF2 are simply nodes. @@ -59,12 +59,12 @@ def gather_joint(blender_bone, export_settings): if export_settings["gltf_def_bones"] is False: for bone in blender_bone.children: - children.append(gather_joint(bone, export_settings)) + children.append(gather_joint(blender_object, 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)) + children.append(gather_joint(blender_object, 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_mesh.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather_mesh.py index 7194798f..d3f950b2 100755 --- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_mesh.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_mesh.py @@ -25,6 +25,7 @@ from io_scene_gltf2.io.exp.gltf2_io_user_extensions import export_user_extension @cached def gather_mesh(blender_mesh: bpy.types.Mesh, + library: Optional[str], blender_object: Optional[bpy.types.Object], vertex_groups: Optional[bpy.types.VertexGroups], modifiers: Optional[bpy.types.ObjectModifiers], @@ -32,15 +33,15 @@ def gather_mesh(blender_mesh: bpy.types.Mesh, material_names: Tuple[str], export_settings ) -> Optional[gltf2_io.Mesh]: - if not skip_filter and not __filter_mesh(blender_mesh, vertex_groups, modifiers, export_settings): + if not skip_filter and not __filter_mesh(blender_mesh, library, vertex_groups, modifiers, export_settings): return None mesh = gltf2_io.Mesh( - extensions=__gather_extensions(blender_mesh, vertex_groups, modifiers, export_settings), - extras=__gather_extras(blender_mesh, vertex_groups, modifiers, export_settings), - name=__gather_name(blender_mesh, vertex_groups, modifiers, export_settings), - weights=__gather_weights(blender_mesh, vertex_groups, modifiers, export_settings), - primitives=__gather_primitives(blender_mesh, blender_object, vertex_groups, modifiers, material_names, export_settings), + extensions=__gather_extensions(blender_mesh, library, vertex_groups, modifiers, export_settings), + extras=__gather_extras(blender_mesh, library, vertex_groups, modifiers, export_settings), + name=__gather_name(blender_mesh, library, vertex_groups, modifiers, export_settings), + weights=__gather_weights(blender_mesh, library, vertex_groups, modifiers, export_settings), + primitives=__gather_primitives(blender_mesh, library, blender_object, vertex_groups, modifiers, material_names, export_settings), ) if len(mesh.primitives) == 0: @@ -61,6 +62,7 @@ def gather_mesh(blender_mesh: bpy.types.Mesh, def __filter_mesh(blender_mesh: bpy.types.Mesh, + library: Optional[str], vertex_groups: Optional[bpy.types.VertexGroups], modifiers: Optional[bpy.types.ObjectModifiers], export_settings @@ -72,6 +74,7 @@ def __filter_mesh(blender_mesh: bpy.types.Mesh, def __gather_extensions(blender_mesh: bpy.types.Mesh, + library: Optional[str], vertex_groups: Optional[bpy.types.VertexGroups], modifiers: Optional[bpy.types.ObjectModifiers], export_settings @@ -80,6 +83,7 @@ def __gather_extensions(blender_mesh: bpy.types.Mesh, def __gather_extras(blender_mesh: bpy.types.Mesh, + library: Optional[str], vertex_groups: Optional[bpy.types.VertexGroups], modifiers: Optional[bpy.types.ObjectModifiers], export_settings @@ -107,6 +111,7 @@ def __gather_extras(blender_mesh: bpy.types.Mesh, def __gather_name(blender_mesh: bpy.types.Mesh, + library: Optional[str], vertex_groups: Optional[bpy.types.VertexGroups], modifiers: Optional[bpy.types.ObjectModifiers], export_settings @@ -115,6 +120,7 @@ def __gather_name(blender_mesh: bpy.types.Mesh, def __gather_primitives(blender_mesh: bpy.types.Mesh, + library: Optional[str], blender_object: Optional[bpy.types.Object], vertex_groups: Optional[bpy.types.VertexGroups], modifiers: Optional[bpy.types.ObjectModifiers], @@ -122,6 +128,7 @@ def __gather_primitives(blender_mesh: bpy.types.Mesh, export_settings ) -> List[gltf2_io.MeshPrimitive]: return gltf2_blender_gather_primitives.gather_primitives(blender_mesh, + library, blender_object, vertex_groups, modifiers, @@ -130,6 +137,7 @@ def __gather_primitives(blender_mesh: bpy.types.Mesh, def __gather_weights(blender_mesh: bpy.types.Mesh, + library: Optional[str], vertex_groups: Optional[bpy.types.VertexGroups], modifiers: Optional[bpy.types.ObjectModifiers], export_settings 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 2eaf56f5..3b0fab2d 100755 --- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_nodes.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_nodes.py @@ -32,7 +32,7 @@ from io_scene_gltf2.io.exp.gltf2_io_user_extensions import export_user_extension from io_scene_gltf2.io.com.gltf2_io_debug import print_console -def gather_node(blender_object, blender_scene, export_settings): +def gather_node(blender_object, library, blender_scene, dupli_object_parent, export_settings): # custom cache to avoid cache miss when called from animation # with blender_scene=None @@ -41,15 +41,15 @@ def gather_node(blender_object, blender_scene, export_settings): gather_node.__cache = {} gather_node.__export_settings = export_settings - if blender_scene is None and blender_object.name in gather_node.__cache: - return gather_node.__cache[blender_object.name] + if blender_scene is None and (blender_object.name, library) in gather_node.__cache: + return gather_node.__cache[(blender_object.name, library)] - node = __gather_node(blender_object, blender_scene, export_settings) - gather_node.__cache[blender_object.name] = node + node = __gather_node(blender_object, library, blender_scene, dupli_object_parent, export_settings) + gather_node.__cache[(blender_object.name, library)] = node return node @cached -def __gather_node(blender_object, blender_scene, export_settings): +def __gather_node(blender_object, library, blender_scene, dupli_object_parent, export_settings): # If blender_scene is None, we are coming from animation export # Check to know if object is exported is already done, so we don't check # again if object is instanced in scene : this check was already done when exporting object itself @@ -62,7 +62,7 @@ def __gather_node(blender_object, blender_scene, export_settings): extensions=__gather_extensions(blender_object, export_settings), extras=__gather_extras(blender_object, export_settings), matrix=__gather_matrix(blender_object, export_settings), - mesh=__gather_mesh(blender_object, export_settings), + mesh=__gather_mesh(blender_object, library, export_settings), name=__gather_name(blender_object, export_settings), rotation=None, scale=None, @@ -121,19 +121,30 @@ def __gather_camera(blender_object, export_settings): def __gather_children(blender_object, blender_scene, export_settings): children = [] # standard children - for child_object in blender_object.children: - if child_object.parent_bone: + for _child_object in blender_object.children: + if _child_object.parent_bone: # this is handled further down, # as the object should be a child of the specific bone, # not the Armature object continue - node = gather_node(child_object, blender_scene, export_settings) + + child_object = _child_object.proxy if _child_object.proxy else _child_object + + node = gather_node(child_object, + child_object.library.name if child_object.library else None, + blender_scene, None, export_settings) if node is not None: children.append(node) # blender dupli objects if blender_object.instance_type == 'COLLECTION' and blender_object.instance_collection: for dupli_object in blender_object.instance_collection.objects: - node = gather_node(dupli_object, blender_scene, export_settings) + if dupli_object.parent is not None: + continue + if dupli_object.type == "ARMATURE": + continue # There is probably a proxy + node = gather_node(dupli_object, + dupli_object.library.name if dupli_object.library else None, + blender_scene, blender_object.name, export_settings) if node is not None: children.append(node) @@ -147,7 +158,7 @@ def __gather_children(blender_object, blender_scene, export_settings): 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) + joint = gltf2_blender_gather_joints.gather_joint(blender_object, blender_bone, export_settings) children.append(joint) root_joints.append(joint) # handle objects directly parented to bones @@ -165,7 +176,7 @@ def __gather_children(blender_object, blender_scene, export_settings): parent_joint = find_parent_joint(root_joints, child.parent_bone) if not parent_joint: continue - child_node = gather_node(child, None, export_settings) + child_node = gather_node(child, None, None, None, export_settings) if child_node is None: continue blender_bone = blender_object.pose.bones[parent_joint.name] @@ -236,7 +247,7 @@ def __gather_matrix(blender_object, export_settings): return [] -def __gather_mesh(blender_object, export_settings): +def __gather_mesh(blender_object, library, export_settings): if blender_object.type != "MESH": return None @@ -313,6 +324,7 @@ def __gather_mesh(blender_object, export_settings): blender_object_for_skined_data = blender_object result = gltf2_blender_gather_mesh.gather_mesh(blender_mesh, + library, blender_object_for_skined_data, vertex_groups, modifiers, @@ -327,8 +339,6 @@ def __gather_mesh(blender_object, export_settings): def __gather_name(blender_object, export_settings): - if blender_object.instance_type == 'COLLECTION' and blender_object.instance_collection: - return "Duplication_Offset_" + blender_object.name return blender_object.name @@ -364,7 +374,7 @@ def __gather_trans_rot_scale(blender_object, export_settings): sca = gltf2_blender_extract.convert_swizzle_scale(sca, export_settings) if blender_object.instance_type == 'COLLECTION' and blender_object.instance_collection: - trans = -gltf2_blender_extract.convert_swizzle_location( + trans -= gltf2_blender_extract.convert_swizzle_location( blender_object.instance_collection.instance_offset, None, None, export_settings) translation, rotation, scale = (None, None, None) trans[0], trans[1], trans[2] = gltf2_blender_math.round_if_near(trans[0], 0.0), gltf2_blender_math.round_if_near(trans[1], 0.0), \ diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_gather_primitives.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather_primitives.py index cca86432..f841f0e2 100755 --- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_primitives.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_primitives.py @@ -33,6 +33,7 @@ from io_scene_gltf2.io.com.gltf2_io_debug import print_console @cached def gather_primitives( blender_mesh: bpy.types.Mesh, + library: Optional[str], blender_object: Optional[bpy.types.Object], vertex_groups: Optional[bpy.types.VertexGroups], modifiers: Optional[bpy.types.ObjectModifiers], @@ -46,7 +47,7 @@ def gather_primitives( """ primitives = [] - blender_primitives = __gather_cache_primitives(blender_mesh, blender_object, + blender_primitives = __gather_cache_primitives(blender_mesh, library, blender_object, vertex_groups, modifiers, export_settings) for internal_primitive in blender_primitives: @@ -82,6 +83,7 @@ def gather_primitives( @cached def __gather_cache_primitives( blender_mesh: bpy.types.Mesh, + library: Optional[str], blender_object: Optional[bpy.types.Object], vertex_groups: Optional[bpy.types.VertexGroups], modifiers: Optional[bpy.types.ObjectModifiers], @@ -93,7 +95,7 @@ def __gather_cache_primitives( primitives = [] blender_primitives = gltf2_blender_extract.extract_primitives( - None, blender_mesh, blender_object, vertex_groups, modifiers, export_settings) + None, blender_mesh, library, blender_object, vertex_groups, modifiers, export_settings) for internal_primitive in blender_primitives: primitive = { 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 2513b073..fa95e543 100755 --- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_skins.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_skins.py @@ -131,10 +131,10 @@ def __gather_joints(blender_object, export_settings): # 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)) + root_joints.append(gltf2_blender_gather_joints.gather_joint(blender_object, 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] + root_joints = [gltf2_blender_gather_joints.gather_joint(blender_object, i, export_settings) for i in root_joints] # joints is a flat list containing all nodes belonging to the skin joints = [] @@ -147,7 +147,7 @@ def __gather_joints(blender_object, export_settings): 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)) + __collect_joints(gltf2_blender_gather_joints.gather_joint(blender_object, blender_object.pose.bones[child], export_settings)) for joint in root_joints: __collect_joints(joint) |