def __gather_node(channels: typing.Tuple[bpy.types.FCurve], blender_object: bpy.types.Object, export_settings, bake_bone: typing.Union[str, None], driver_obj ) -> gltf2_io.Node: if driver_obj is not None: 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 if bake_bone is not None: blender_bone = blender_object.pose.bones[bake_bone] else: blender_bone = blender_object.path_resolve(channels[0].data_path.rsplit('.', 1)[0]) if isinstance(blender_bone, bpy.types.PoseBone): if export_settings["gltf_def_bones"] is False: 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]: 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, blender_object.library.name if blender_object.library else None, None, None, export_settings)
def __gather_scene(blender_scene, export_settings): scene = gltf2_io.Scene( extensions=None, extras=__gather_extras(blender_scene, export_settings), name=blender_scene.name, nodes=[] ) vtree = gltf2_blender_gather_tree.VExportTree(export_settings) vtree.construct(blender_scene) vtree.search_missing_armature() # In case armature are no parented correctly export_user_extensions('vtree_before_filter_hook', export_settings, vtree) # Now, we can filter tree if needed vtree.filter() export_user_extensions('vtree_after_filter_hook', export_settings, vtree) export_settings['vtree'] = vtree for r in [vtree.nodes[r] for r in vtree.roots]: node = gltf2_blender_gather_nodes.gather_node( r, export_settings) if node is not None: scene.nodes.append(node) export_user_extensions('gather_scene_hook', export_settings, scene, blender_scene) return scene
def __gather_animations(blender_scene, export_settings): animations = [] for blender_object in blender_scene.objects: # 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) if obj_node is not None: animations += gltf2_blender_gather_animations.gather_animations(blender_object, export_settings) return animations
def __gather_node(channels: typing.Tuple[bpy.types.FCurve], blender_object: bpy.types.Object, export_settings ) -> gltf2_io.Node: if blender_object.type == "ARMATURE": # TODO: get joint from fcurve data_path and gather_joint blender_bone = blender_object.path_resolve(channels[0].data_path.rsplit('.', 1)[0]) return gltf2_blender_gather_joints.gather_joint(blender_bone, export_settings) return gltf2_blender_gather_nodes.gather_node(blender_object, export_settings)
def __gather_scene(blender_scene, export_settings): scene = gltf2_io.Scene( extensions=None, extras=__gather_extras(blender_scene, export_settings), name=None, nodes=[] ) for _blender_object in [obj for obj in blender_scene.objects if obj.proxy is None]: if _blender_object.type == "ARMATURE": # extract the root bone from the armature armature = _blender_object blender_object = _blender_object.proxy if _blender_object.proxy else _blender_object for bone in blender_object.pose.bones: # sometimes there can be more than one bone at root level if bone.parent is None: joint = gltf2_blender_gather_joints.gather_joint(blender_object, bone, export_settings) if joint is not None: scene.nodes.append(joint) elif _blender_object.type == "MESH": if _blender_object.parent is None: # skip if the object is not a child continue if _blender_object.parent.parent is None: # add skinned meshes and meshes with a parent bone to the scene blender_object = _blender_object.proxy if _blender_object.proxy else _blender_object modifiers = {m.type: m for m in blender_object.modifiers} if ("ARMATURE" not in modifiers or modifiers["ARMATURE"].object is None) and not blender_object.parent_bone == "": # for some reason the value for no parent bone is an empty string instead of None continue 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) elif _blender_object.type == "EMPTY": # in rare cases where there is more than one root bone, if there is an empty that is a direct child of an armature and has no parent bone, we export it if _blender_object.parent_bone == "" and _blender_object.parent.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) export_user_extensions('gather_scene_hook', export_settings, scene, blender_scene) return scene
def __gather_node(channels: typing.Tuple[bpy.types.FCurve], blender_object: bpy.types.Object, export_settings ) -> gltf2_io.Node: if blender_object.type == "ARMATURE": # TODO: get joint from fcurve data_path and gather_joint 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) return gltf2_blender_gather_nodes.gather_node(blender_object, export_settings)
def gather_node_property(export_settings, blender_object, target, property_name, property_definition, hubs_config): blender_object = getattr(target, property_name) if blender_object: return gltf2_blender_gather_nodes.gather_node( blender_object, blender_object.library.name if blender_object.library else None, blender_object.users_scene[0], None, export_settings) else: return None
def __gather_animations(blender_scene, anim_scene, export_settings): 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_object.library.name if blender_object.library else None, blender_scene, None, export_settings) animations = gltf2_blender_gather_animations.gather_animations(anim_scene, export_settings) return animations
def gather_node_property(export_settings, blender_object, target, property_name, property_definition, hubs_config): blender_object = getattr(target, property_name) if blender_object: node = gltf2_blender_gather_nodes.gather_node( blender_object, blender_object.library.name if blender_object.library else None, blender_object.users_scene[0], None, export_settings) return {"__mhc_link_type": "node", "index": node} else: return None
def __gather_scene(blender_scene, export_settings): scene = gltf2_io.Scene( extensions=None, extras=__gather_extras(blender_scene, export_settings), name=blender_scene.name, 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) if node is not None: scene.nodes.append(node) return scene
def __gather_scene(blender_scene, export_settings): scene = gltf2_io.Scene( extensions=None, extras=__gather_extras(blender_scene, export_settings), name=blender_scene.name, nodes=[] ) for blender_object in blender_scene.objects: if blender_object.parent is None: node = gltf2_blender_gather_nodes.gather_node(blender_object, export_settings) if node is not None: scene.nodes.append(node) return scene
def __gather_node(channels: typing.Tuple[bpy.types.FCurve], blender_object: bpy.types.Object, export_settings, bake_bone: typing.Union[str, None] ) -> gltf2_io.Node: if blender_object.type == "ARMATURE": # TODO: get joint from fcurve data_path and gather_joint if bake_bone is not None: blender_bone = blender_object.pose.bones[bake_bone] else: 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) return gltf2_blender_gather_nodes.gather_node(blender_object, None, export_settings)
def __gather_scene(blender_scene, export_settings): scene = gltf2_io.Scene(extensions=None, extras=None, name=blender_scene.name, nodes=[]) for blender_object in blender_scene.objects: if blender_object.parent is None: node = gltf2_blender_gather_nodes.gather_node( blender_object, export_settings) if node is not None: scene.nodes.append(node) # TODO: materials, textures, images # TODO: animations # TODO: lights # TODO: asset? return scene
def __gather_animations(blender_scene, export_settings): animations = [] for blender_object in blender_scene.objects: # 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) if obj_node is not None: animations += gltf2_blender_gather_animations.gather_animations( blender_object, export_settings) # if none of those two actions have been selected, # let's merge indivudual animations into one single with multiple channels all_actions = export_settings['gltf_all_actions'] nla_strips = export_settings['gltf_nla_strips'] if not all_actions and not nla_strips: scene_animation = __merge_animations(blender_scene, animations, export_settings) animations = [] animations.append(scene_animation) return animations
def __gather_scene(blender_scene, export_settings): scene = gltf2_io.Scene( extensions=None, extras=__gather_extras(blender_scene, export_settings), name=blender_scene.name, nodes=[] ) 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) export_user_extensions('gather_scene_hook', export_settings, scene, blender_scene) return scene
def __gather_materials(blender_scene, export_settings): materials = [] for _blender_object in blender_scene.objects: blender_object = _blender_object.proxy if _blender_object.proxy else _blender_object # Check if this object is exclude from view layer 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 None: continue for slot in blender_object.material_slots: # Check if this slot as assigned material if slot.material is None: continue double_sided = not slot.material.use_backface_culling materials.append(gltf2_blender_gather_materials.gather_material(slot.material, double_sided, export_settings)) return materials
def __gather_animations(blender_scene, export_settings): animations = [] merged_tracks = {} 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_object.library.name if blender_object.library else None, blender_scene, None, export_settings) if obj_node is not None: # 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: # Fake an animation with all animations of the scene merged_tracks = {} merged_tracks['Animation'] = [] for idx, animation in enumerate(animations): merged_tracks['Animation'].append(idx) to_delete_idx = [] for merged_anim_track in merged_tracks.keys(): if len(merged_tracks[merged_anim_track]) < 2: # There is only 1 animation in the track # If name of the track is not a default name, use this name for action if len(merged_tracks[merged_anim_track]) != 0: animations[merged_tracks[merged_anim_track] [0]].name = merged_anim_track continue base_animation_idx = None offset_sampler = 0 for idx, anim_idx in enumerate(merged_tracks[merged_anim_track]): if idx == 0: base_animation_idx = anim_idx animations[anim_idx].name = merged_anim_track already_animated = [] for channel in animations[anim_idx].channels: already_animated.append( (channel.target.node, channel.target.path)) continue to_delete_idx.append(anim_idx) # Merging extras # Warning, some values can be overwritten if present in multiple merged animations if animations[anim_idx].extras is not None: for k in animations[anim_idx].extras.keys(): if animations[base_animation_idx].extras is None: animations[base_animation_idx].extras = {} animations[base_animation_idx].extras[k] = animations[ anim_idx].extras[k] offset_sampler = len(animations[base_animation_idx].samplers) for sampler in animations[anim_idx].samplers: animations[base_animation_idx].samplers.append(sampler) for channel in animations[anim_idx].channels: if (channel.target.node, channel.target.path) in already_animated: print_console( "WARNING", "Some strips have same channel animation ({}), on node {} !" .format(channel.target.path, channel.target.node.name)) continue animations[base_animation_idx].channels.append(channel) animations[base_animation_idx].channels[ -1].sampler = animations[base_animation_idx].channels[ -1].sampler + offset_sampler already_animated.append( (channel.target.node, channel.target.path)) new_animations = [] if len(to_delete_idx) != 0: for idx, animation in enumerate(animations): if idx in to_delete_idx: continue new_animations.append(animation) else: new_animations = animations return new_animations
def __gather_animations(blender_scene, export_settings): animations = [] merged_tracks = {} for blender_object in blender_scene.objects: # 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) if obj_node is not None: 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: # Fake an animation witha all animations of the scene merged_tracks = {} merged_tracks['Animation'] = [] for idx, animation in enumerate(animations): merged_tracks['Animation'].append(idx) to_delete_idx = [] for merged_anim_track in merged_tracks.keys(): if len(merged_tracks[merged_anim_track]) < 2: continue base_animation_idx = None offset_sampler = 0 for idx, anim_idx in enumerate(merged_tracks[merged_anim_track]): if idx == 0: base_animation_idx = anim_idx animations[anim_idx].name = merged_anim_track already_animated = [] for channel in animations[anim_idx].channels: already_animated.append( (channel.target.node, channel.target.path)) continue to_delete_idx.append(anim_idx) offset_sampler = len(animations[base_animation_idx].samplers) for sampler in animations[anim_idx].samplers: animations[base_animation_idx].samplers.append(sampler) for channel in animations[anim_idx].channels: if (channel.target.node, channel.target.path) in already_animated: print_console( "WARNING", "Some strips have same channel animation ({}), on node {} !" .format(channel.target.path, channel.target.node.name)) continue animations[base_animation_idx].channels.append(channel) animations[base_animation_idx].channels[ -1].sampler = animations[base_animation_idx].channels[ -1].sampler + offset_sampler already_animated.append( (channel.target.node, channel.target.path)) new_animations = [] if len(to_delete_idx) != 0: for idx, animation in enumerate(animations): if idx in to_delete_idx: continue new_animations.append(animation) else: new_animations = animations return new_animations
def __gather_node(action_group: bpy.types.ActionGroup, blender_object: bpy.types.Object, export_settings) -> gltf2_io.Node: return gltf2_blender_gather_nodes.gather_node(blender_object, export_settings)