GLB file not loaded correctly

Hi,
I have a glb file that not loaded correctly in bjs:

And this is in 3js, no problem:

Attached the glb file link
https://drive.google.com/file/d/10-iPHffZuII0i5p1tDRd3mpZ_iV8jEYu/view?usp=sharing

The Sandbox shows that the file has incorrect specifications:
image

If you click on “More details”:

I’m not sure if Three.js is simply ignoring the error or doing something to try to correct it. @Evgeni_Popov or @bghgary who have a lot of experience w skeletons can explain the behavior better?

I can repro. I don’t think the validation error is causing this problem. I’ll investigate.

If you converted FBX to GLB they work differently. I had similar issue and used blender to correct them some times ago . .

Sorry for the delay, I’m busy with another task right now. I will get to this soon. :crossed_fingers:

I looked at the file, the problem comes from skeleton1 (this is the skeleton used by Ch17_Boots).

skeleton1 is created as follows:
image

The problem is that RightUpLeg is created under RootNode / mixamorig1:Hips. It’s because of this code in _loadBone :

let parentBabylonBone: Nullable<Bone> = null;
if (node.index !== skin.skeleton) {
    if (node.parent && node.parent.index !== -1) {
        parentBabylonBone = this._loadBone(node.parent, skin, babylonSkeleton, babylonBones);
    } else if (skin.skeleton !== undefined) {
        Logger.Warn(`/skins/${skin.index}/skeleton: Skeleton node is not a common root`);
    }
}

When processing RightUpLeg, node.parent && node.parent.index !== -1 is true, so we go up the hierarchy and create mixamorig1:Hips first, then RootNode, because the node hierarchy is :

image

This doesn’t happen for LeftUpLeg because the index of this bone is also the value of skin.skeleton, so node.index !== skin.skeleton is false and we don’t execute the code inside the condition block.

Maybe we shouldn’t go up the hierarchy if node.parent.index isn’t one of the joints? Something like:

if (node.index !== skin.skeleton) {
    if (node.parent && node.parent.index !== -1) {
        if (skin.joints.indexOf(node.parent.index) !== -1) {
            parentBabylonBone = this._loadBone(node.parent, skin, babylonSkeleton, babylonBones);
        }
    } else if (skin.skeleton !== undefined) {
        Logger.Warn(`/skins/${skin.index}/skeleton: Skeleton node is not a common root`);
    }
}

This modification creates a skeleton like the one shown below and solves the problem, but I don’t know if it’s the right fix:
image

1 Like

I don’t use the .glb file format as I usually export .babylon files from Blender using @JCPalmer 's Blender exporter, but I saw this thread and the results shown above seemed a little odd, so I took a look.

I downloaded the file in @Freeman 's first post and imported the file into Blender, simplified the materials in Blender ( it uses very large UDIM textures > than 20Mbs in one case) and exported as a .babylon file. I then viewed both the original file and my .babylon file in the sandbox. Results are Images 1 and 2

Like @Freeman 's original image above, Image 1 it shows the “boot” at the hips!! It also shows what appears to be 8(!!) skeletons with lows of ~2 bones to a high of ~52 bones

Image 2 is a screenshot of my .babylon file in the sandbox. There is one skeleton (65 bones), the boot is in the correct position and the character has a beard (B in Image 2) not seen in either of the two images above. So three.js is also not dealing correctly with the file either.

@Evgeni_Popov is likely correct about the bones in the imported from the skeleton in the .glb file, but what is happening to the beard? To test the skeleton that was being exported from Blender, I added 2 mixamo animations to the character - here is a playground with the animated character :

Animated Worker

I did not adjust or rearrange any bones in the Blender skeleton - just added the animations

I have no idea why I am getting good results after I import the file into Blender then export as a .babylon file. :thinking:

EDIT : The bones in the rig are named like “mixamorig:hips”. Does that “:” interfere with the parsing of the .glb file ?

cheers, gryff :slight_smile:

Image 1 : Screen shot of original .glb file in sandbox :

Image 2 : Screen shot of .babylon file exported from Blender :

And just for @Evgeni_Popov , here is an image of the rig outline from Blender. The foot bone is selected and it shows up in the proper place in the bone hierarchy (A) . Why does the glb file have this abnormal hierarchy?

As I have said above, the “:” does not parse well in game engines like GODOT.

cheers, gryff :slight_smile:

Thanks @gryff!

The “no beard” display is either expected (for some reasons) or a bug in the Blender export, as all the 4 or 5 glTF viewers I tested don’t show the beard.

“:” is not a problem, they are all over the place in Mixamo avatars and we do have other files coming from Mixamo that work well.

Yes, the problem only concerns the glTF parsing code. Let’s see what @bghgary has to say about it.

@Evgeni_Popov : I don’t think it is a bug in the Blender export as the meshes are visible in the Blender display windows before any export… A problem with the Blender "import" maybe? I am using Blender 3.3.1 and the beard has ~7600 vertices. So not an insignificant mesh.

See image below. I have hidden the armature for the picture.

Like you, I await @bghgary thoughts and ideas - and solutions!!

Did you try my playground above?

cheers, gryff :slight_smile:

@Evgeni_Popov ,
The glb file is converted from a fbx file. The fbx file do have hair and beard. As “no beard” display in both bjs and 3js, I thought it was a convert issue.

But it can display in Blender by @gryff , I think the loader doesn’t parse the “beard” correctly as well.

I think it’s a Blender export issue, as none of the 5 or 6 different glTF viewers I’ve used (including the official Khronos viewer) display the hair/beard.

[…] On closer inspection, Blender exports the material for this mesh with alpha=0. If I set alpha=1 for this material (Ch17_hair), it works:

image

1 Like

Finally getting a chance to look at this. I’ll address the easier question first :slight_smile:

Regarding the missing beard, @Evgeni_Popov is right. The glTF material for the C17_hair is this:

    {
      "name": "Ch17_hair",
      "alphaMode": "BLEND",
      "extras": {
        "fromFBX": {
          "shadingModel": "Phong",
          "isTruePBR": false
        }
      },
      "pbrMetallicRoughness": {
        "baseColorTexture": {
          "index": 3,
          "texCoord": 0
        },
        "baseColorFactor": [
          0.800000011920929,
          0.800000011920929,
          0.800000011920929,
          0.0 // *** This is the problem! ***
        ],
        "metallicFactor": 0.400000005960464,
        "roughnessFactor": 0.301511347293854
      }
    }

I don’t know why Blender exporter would do this, so it’s probably better to ask them. Changing this value to 1.0 makes it show up.

I will look at the skeleton issue next.

Regarding the boot issue, this is still an issue with the asset. The reason why it only happens in Babylon is probably because we are the only loader that uses the skeleton property of the glTF which has been incorrectly set in the asset.

It turns out that I was wrong about the glTF Validation errors not causing the problems. The warnings are ignorable, but the first error is the exact source of the issue.

      {
        "code": "SKIN_SKELETON_INVALID",
        "message": "Skeleton node is not a common root.",
        "severity": 0,
        "pointer": "/skins/1/skeleton"
      },

The offending glTF JSON:

    {
      "joints": [
        56,
        57,
        58,
        59,
        60,
        61,
        62,
        63,
        64,
        65
      ],
      "inverseBindMatrices": 49,
      "skeleton": 56 // *** this node is not a common root of the nodes in the list above ***
    },

If this node is not a common root, the loader will load incorrectly for some cases. Changing this value to 1 or removing this property (such that the loader will auto-calculate the common root) fixes the issue.

2 Likes

I have the same issue, thanks for your solution, it works by changing skeleton to 1.
But I am wondering why we need this part if the skeleton can be set to 1. Why can’t we discard this value, what is it used for? thank you so so much.

let parentBabylonBone: Nullable<Bone> = null;
if (node.index !== skin.skeleton) {
    if (node.parent && node.parent.index !== -1) {
        parentBabylonBone = this._loadBone(node.parent, skin, babylonSkeleton, babylonBones);
    } else if (skin.skeleton !== undefined) {
        Logger.Warn(`/skins/${skin.index}/skeleton: Skeleton node is not a common root`);
    }
}

And will we fix this issue in the future?

This property represents the root of the skeleton. Babylon handles skeletons differently than glTF so we have to move of the mesh nodes to accommodate (see here). The root of the skeleton can be specified to be higher than the common ancestor if needed. The loader respects this property for this reason and to save CPU cycles from computing the common ancestor.

I’m not sure there is anything to fix. The glTF is malformed as indicated by the glTF validator. The loader also has a flag called alwaysComputeSkeletonRootNode if you want to always compute the common ancestor and ignore the provided one.

2 Likes

I understand now, thank you so much for your explanation.
I will use this alwaysComputeSkeletonRootNode parameter because most of the files I convert from FBX to GLTF using Godot’s fbx2gltf have this issue.

I use alwaysComputeSkeletonRootNode like this:

const gltfLoader = SceneLoader.GetPluginForExtension('.gltf')
gltfLoader.alwaysComputeSkeletonRootNode = true

It doesn’t seem to be working, am I using it correctly?