def __gather_joints(blender_object, export_settings): root_joints = [] 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) 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) return joints
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): 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)
def __gather_joints(blender_object, export_settings): # # the skeletal hierarchy groups below a 'root' joint # # TODO: add transform? # torso = gltf2_io.Node( # camera=None, # children=[], # extensions={}, # extras=None, # matrix=[], # mesh=None, # name="Skeleton_" + blender_object.name, # rotation=None, # scale=None, # skin=None, # translation=None, # weights=None # ) 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)) # 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) for joint in root_joints: __collect_joints(joint) return joints
def __gather_children(blender_object, export_settings): children = [] # standard children for child_object in blender_object.children: node = gather_node(child_object, export_settings) if node is not None: children.append(node) # blender dupli objects if bpy.app.version < (2, 80, 0): if blender_object.dupli_type == 'GROUP' and blender_object.dupli_group: for dupli_object in blender_object.dupli_group.objects: node = gather_node(dupli_object, export_settings) if node is not None: children.append(node) else: 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, export_settings) if node is not None: children.append(node) # blender bones if blender_object.type == "ARMATURE": for blender_bone in blender_object.pose.bones: if not blender_bone.parent: children.append(gltf2_blender_gather_joints.gather_joint(blender_bone, export_settings)) return children
def __gather_joints(blender_object, export_settings): # the skeletal hierarchy groups below a 'root' joint # TODO: add transform? torso = gltf2_io.Node( camera=None, children=[], extensions={}, extras=None, matrix=[], mesh=None, name="Skeleton_" + blender_object.name, rotation=None, scale=None, skin=None, translation=None, weights=None ) # build the hierarchy of nodes out of the bones for blender_bone in blender_object.pose.bones: torso.children.append(gltf2_blender_gather_joints.gather_joint(blender_bone, export_settings)) # 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) __collect_joints(torso) return joints
def __gather_skeleton(armature, joints, export_settings): # returns the root bone node blender_scene = bpy.data.scenes[ 0] # there should only ever be one scene for MSFS return gltf2_blender_gather_joints.gather_joint( armature, armature.pose.bones[joints[0].name], export_settings ) # there are some situations where there are 2 bones at the root level, so we use the first joint in the skin
def __collect_joints(node): joints.append(node) 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))
def __gather_joints(blender_object, export_settings): bones = [group.name for group in blender_object.vertex_groups] # get bones in skin modifiers = {m.type: m for m in blender_object.modifiers} armature = modifiers["ARMATURE"].object root_joints = [] if export_settings['gltf_def_bones'] is False: # build the hierarchy of nodes out of the bones for blender_bone in armature.pose.bones: if not blender_bone.parent: root_joints.append( gltf2_blender_gather_joints.gather_joint( armature, blender_bone, export_settings)) else: _, children_, root_joints = get_bone_tree(None, armature) root_joints = [ gltf2_blender_gather_joints.gather_joint(armature, 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) if export_settings['gltf_def_bones'] is False: for child in node.children: if child.name in bones: __collect_joints(child) else: if node.name in children_.keys(): for child in children_[node.name]: if child.name in bones: __collect_joints( gltf2_blender_gather_joints.gather_joint( armature, armature.pose.bones[child], export_settings)) for joint in root_joints: __collect_joints(joint) return joints
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_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_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)) # 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) for joint in root_joints: __collect_joints(joint) return joints
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_children(blender_object, blender_scene, export_settings): children = [] # standard children 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 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: 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) # blender bones if blender_object.type == "ARMATURE": root_joints = [] 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_object, blender_bone, export_settings) children.append(joint) root_joints.append(joint) # handle objects directly parented to bones direct_bone_children = [ child for child in blender_object.children if child.parent_bone ] def find_parent_joint(joints, name): for joint in joints: if joint.name == name: return joint parent_joint = find_parent_joint(joint.children, name) if parent_joint: return parent_joint return None for child in direct_bone_children: # find parent joint parent_joint = find_parent_joint(root_joints, child.parent_bone) if not parent_joint: continue 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] # fix rotation if export_settings[gltf2_blender_export_keys.YUP]: rot = child_node.rotation if rot is None: rot = [0, 0, 0, 1] rot_quat = Quaternion(rot) axis_basis_change = 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))) mat = gltf2_blender_math.multiply(child.matrix_parent_inverse, child.matrix_basis) mat = gltf2_blender_math.multiply(mat, axis_basis_change) _, rot_quat, _ = mat.decompose() child_node.rotation = [ rot_quat[1], rot_quat[2], rot_quat[3], rot_quat[0] ] # fix translation (in blender bone's tail is the origin for children) trans, _, _ = child.matrix_local.decompose() if trans is None: trans = [0, 0, 0] # bones go down their local y axis if blender_bone.matrix.to_scale()[1] >= 1e-6: bone_tail = [ 0, blender_bone.length / blender_bone.matrix.to_scale()[1], 0 ] else: bone_tail = [0, 0, 0] # If scale is 0, tail == head child_node.translation = [ trans[idx] + bone_tail[idx] for idx in range(3) ] parent_joint.children.append(child_node) return children
def __gather_children(blender_object, blender_scene, export_settings): children = [] # standard children 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) if node is not None: children.append(node) # blender dupli objects if bpy.app.version < (2, 80, 0): if blender_object.dupli_type == 'GROUP' and blender_object.dupli_group: for dupli_object in blender_object.dupli_group.objects: node = gather_node(dupli_object, blender_scene, export_settings) if node is not None: children.append(node) else: 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 node is not None: children.append(node) # blender bones if blender_object.type == "ARMATURE": root_joints = [] for blender_bone in blender_object.pose.bones: if not blender_bone.parent: joint = gltf2_blender_gather_joints.gather_joint( blender_bone, export_settings) children.append(joint) root_joints.append(joint) # handle objects directly parented to bones direct_bone_children = [ child for child in blender_object.children if child.parent_bone ] def find_parent_joint(joints, name): for joint in joints: if joint.name == name: return joint parent_joint = find_parent_joint(joint.children, name) if parent_joint: return parent_joint return None for child in direct_bone_children: # find parent joint parent_joint = find_parent_joint(root_joints, child.parent_bone) if not parent_joint: continue child_node = gather_node(child, None, export_settings) if child_node is None: continue blender_bone = blender_object.pose.bones[parent_joint.name] # fix rotation if export_settings[gltf2_blender_export_keys.YUP]: rot = child_node.rotation if rot is None: rot = [0, 0, 0, 1] rot_quat = Quaternion(rot) axis_basis_change = 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))) mat = gltf2_blender_math.multiply(axis_basis_change, child.matrix_basis) mat = gltf2_blender_math.multiply(child.matrix_parent_inverse, mat) _, rot_quat, _ = mat.decompose() child_node.rotation = [ rot_quat[1], rot_quat[2], rot_quat[3], rot_quat[0] ] # fix translation (in blender bone's tail is the origin for children) trans, _, _ = child.matrix_local.decompose() if trans is None: trans = [0, 0, 0] # bones go down their local y axis bone_tail = [0, blender_bone.length, 0] child_node.translation = [ trans[idx] + bone_tail[idx] for idx in range(3) ] parent_joint.children.append(child_node) return children
def __gather_children(blender_object, blender_scene, export_settings): children = [] # standard children 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 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: 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) # blender bones if blender_object.type == "ARMATURE": root_joints = [] 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_object, blender_bone, export_settings) children.append(joint) root_joints.append(joint) # handle objects directly parented to bones direct_bone_children = [ child for child in blender_object.children if child.parent_bone ] def find_parent_joint(joints, name): for joint in joints: if joint.name == name: return joint parent_joint = find_parent_joint(joint.children, name) if parent_joint: return parent_joint return None for child in direct_bone_children: # find parent joint parent_joint = find_parent_joint(root_joints, child.parent_bone) if not parent_joint: continue child_node = gather_node(child, None, None, None, export_settings) if child_node is None: continue parent_joint.children.append(child_node) return children