ronh991 / glTF-Blender-IO-MSFS

My unofficial updates to ASOBO exporter for Blender 3.3, 3.6 and 4.2 LTS
Apache License 2.0
12 stars 0 forks source link

Neutral bone - error on MSFS sim build - Read me #17

Open ronh991 opened 3 months ago

ronh991 commented 3 months ago

Current Behavior

If you have vertices with a armature weighting of zero in vertex groups for armature animations. Blender/Khronos will add a neutral bone to your glTF on export - this will cause an error in the MSFS build, talking about a neutral_bone duplicate naming.

Zero weighting in weight paint causes this issue.

https://github.com/KhronosGroup/glTF-Blender-IO/issues/2303

Expected Behavior

No neutral_bone in glTF.

Steps To Reproduce

Bad vertex group happens in parenting with automatic weights.

Environment

- OS:win 10
- Blender:3.6 and 4.2
- glTF-Blender-IO-MSFS: any that work with 3.6 and 4.2

Anything else?

No response

ronh991 commented 3 months ago

For those brave enough to modify Khronos python code. MAKE BACKUPS!!

The gltf2_blender_gather_primatives_extract.py in the Program Files\Blender Foundation\Blender 4.2\4.2\scripts\addons_core\io_scene_gltf2\blender\exp folder

replace the __get_bone_data function

I just added the code pertaining to pre_meshname variable

    def __get_bone_data(self):

        self.need_neutral_bone = False
        min_influence = 0.0001

        joint_name_to_index = {joint.name: index for index, joint in enumerate(self.skin.joints)}
        group_to_joint = [joint_name_to_index.get(g.name) for g in self.blender_vertex_groups]

        # List of (joint, weight) pairs for each vert
        self.vert_bones = []
        max_num_influences = 0

        prev_meshname = ""
        for vertex in self.blender_mesh.vertices:
            bones = []
            if vertex.groups:
                for group_element in vertex.groups:
                    weight = group_element.weight
                    if weight <= min_influence:
                        continue
                    try:
                        joint = group_to_joint[group_element.group]
                    except Exception:
                        continue
                    if joint is None:
                        continue
                    bones.append((joint, weight))
            bones.sort(key=lambda x: x[1], reverse=True)
            if not bones:
                # Is not assign to any bone
                bones = ((len(self.skin.joints), 1.0),)  # Assign to a joint that will be created later
                self.need_neutral_bone = True
                if prev_meshname != self.blender_mesh.name:
                    print("***** Khronos Core-MSFS Warning neutral_bone added *****", vertex, self.blender_mesh.name)
                    prev_meshname = self.blender_mesh.name
            self.vert_bones.append(bones)
            if len(bones) > max_num_influences:
                max_num_influences = len(bones)

        # How many joint sets do we need? 1 set = 4 influences
        self.num_joint_sets = (max_num_influences + 3) // 4

The system console window will have something like this

13:08:25 | INFO: Primitives created: 8
13:08:25 | INFO: Extracting primitive: Mesh.197
***** Khronos Core-MSFS Warning neutral_bone added ***** <bpy_struct, MeshVertex at 0x000001EFA7AED708> Mesh.197
13:08:25 | INFO: Primitives created: 1
13:08:25 | INFO: Extracting primitive: Mesh.196