C4D animation glTF load error

Hi,
Please need urgent help or suggestion to fix the issue with loading a glTF model.
This model was purchased from sketchFab, and, it is working in three.js but not in Babylon.js. We recently moved our code from threejs to babylonjs.
Model: 3d Animated Realistic Human Heart - V2.0 - Buy Royalty Free 3D model by Doctor Jana (@docjana) [168b474] - Sketchfab StoreScreen.zip (2.6 MB)

Does BabylonJS not supports C4D animation?
If I remove the animation section from the glTF file, then the file gets loaded without any errors in the console and the model is appearing correctly.
Please see attached threeJS and BabylonJs recording with the animation on.

This model with animation is required for the upcoming UAT of the app we developed with Babylonjs.
Looking forward for your help!!
Thanks

pinging @bghgary

I can see from the movie errors in the console log: would it be possible to copy and paste everything in a post?

I can see this error:
Cannot add more vertex attributes for mesh 0

This error is raised when the number of attributes for a mesh is greater than the number of attributes supported by the graphic card, and is raised by the code that prepare attributes for morph targets:

public static PrepareAttributesForMorphTargets(attribs: string[], mesh: AbstractMesh, defines: any): void {
    var influencers = defines["NUM_MORPH_INFLUENCERS"];

    if (influencers > 0 && EngineStore.LastCreatedEngine) {
        var maxAttributesCount = EngineStore.LastCreatedEngine.getCaps().maxVertexAttribs;
        var manager = (<Mesh>mesh).morphTargetManager;
        var normal = manager && manager.supportsNormals && defines["NORMAL"];
        var tangent = manager && manager.supportsTangents && defines["TANGENT"];
        var uv = manager && manager.supportsUVs && defines["UV1"];
        for (var index = 0; index < influencers; index++) {
            attribs.push(VertexBuffer.PositionKind + index);

            if (normal) {
                attribs.push(VertexBuffer.NormalKind + index);
            }

            if (tangent) {
                attribs.push(VertexBuffer.TangentKind + index);
            }

            if (uv) {
                attribs.push(VertexBuffer.UVKind + "_" + index);
            }

            if (attribs.length > maxAttributesCount) {
                Logger.Error("Cannot add more vertex attributes for mesh " + mesh.name);
            }
        }
    }
}

It seems there are too many morph influencers and too many attributes end up created…

babylonjsconsole.zip (188.6 KB)
Thank you so much for looking into this.
Attached is the error from the console.
Sorry the text file may be hard to read, there are lot of errors on the console.
Please let me know if you require me to share the screen at any stage or so.
Thanks

I’m on it.

1 Like

That’s definitely a problem with too many vertex attributes, so too many influencers:

Error: ERROR: Implementation limit of 16 MAX_VERTEX_ATTRIBS (e.g., number of generic plus conventional active vec4 attributes) exceeded, shader uses up to vec4 attribute 19.

There are 8 influencers, each one being a position+normal, so 16 vertex attributes. But there are also 5 other vertex attributes coming from the regular mesh (position, normal, tangent, uv, uv2), so it amounts to 21 vertex attributes, which exceeds the limit.

I can see this in the gltf code:

for (let index = 0; index < primitive.targets.length; index++) {
    const weight = node.weights ? node.weights[index] : mesh.weights ? mesh.weights[index] : 0;
    const name = targetNames ? targetNames[index] : `morphTarget${index}`;
    babylonMesh.morphTargetManager.addTarget(new MorphTarget(name, weight, babylonMesh.getScene()));
    // TODO: tell the target whether it has positions, normals, tangents
}

See the todo: maybe it has something to do with the problem (maybe the gltf disables normal morphing and those should not be set as influencers, for eg)?

I’m afraid my knowledge of gltf and morph targets stops here, I will let @bghgary answer more throughly.

Still, one thing you can try is to remove the 6 last targets from the target manager, so you get 16-6+5=15 attributes in the end, which should be fine.

To do this, after the mesh is loaded:

var mtm = mesh.morphTargetManager;
var i = 6;
while (i-- > 0) {
    mtm.removeTarget(mtm.getTarget(mtm.numTargets - 1));
}

Is there any way you can send me the model? It would go much faster if I can repro it.

Sadly as this was purchased from sketchfab, and we are bound their licence agreement.
these are the animation
“animations”: [
{
“channels”: [
{
“sampler”: 0,
“target”: {
“node”: 7,
“path”: “weights”
}
},
{
“sampler”: 1,
“target”: {
“node”: 8,
“path”: “weights”
}
},
{
“sampler”: 2,
“target”: {
“node”: 9,
“path”: “weights”
}
}
],
“name”: “C4D Animation Take”,
“samplers”: [
{
“input”: 150,
“interpolation”: “LINEAR”,
“output”: 151
},
{
“input”: 152,
“interpolation”: “LINEAR”,
“output”: 153
},
{
“input”: 154,
“interpolation”: “LINEAR”,
“output”: 155
}
]
}
],

I’m not a lawyer, but Sketchfab’s standard license doesn’t seem to disallow sharing the model for debugging purposes. Anyways, your call on this. I will try to see if I can figure it out. If you can at least share with me the glTF file (without the bins or images), that would help also.

Perhaps another option is if you can make a capture with Spector.js?

This todo is not related. This is just a comment that we need to tell the shaders in advance about the morph targets so that the compileMaterials flag works properly for morph targets.

1 Like

I’ve contacted the author in a comment on Sketchfab. Hopefully, the author will allow me to debug the model.

Will now check with Sketchfab about sharing the file for debugging purposes.
I will try Spector.js - haven’t used it before, let me see how it works.
Thanks again for the such wonderful, dedicated BJS team.

1 Like

Sadly the author has not been responding, we have been chasing with this issue
for couple of months now.

If you do capture with Spector.js, please capture for both Babylon.js and three. I’d like to see the difference in behavior.

But like @Evgeni_Popov says, it appears from the logs that there are 8 morph targets active at a time, which ends up passing the limit of vertex attributes. I’m not sure this should be handled from the loader as the loader can’t easy tell how many morph targets will be active in the animation. Perhaps we can drop the normals from the morph targets or drop the number of morph targets from the engine side? @Deltakosh would it be okay to give a warning but then drop morph targets (either by dropping less important attributes or dropping the number of morph targets) when there are too many?

It does work in 3js because they limit morph targets to max 4 position + 4 normals or 8 positions, but they never use more than 8 attributes:

'#ifdef USE_MORPHTARGETS',

'	attribute vec3 morphTarget0;',
'	attribute vec3 morphTarget1;',
'	attribute vec3 morphTarget2;',
'	attribute vec3 morphTarget3;',

'	#ifdef USE_MORPHNORMALS',

'		attribute vec3 morphNormal0;',
'		attribute vec3 morphNormal1;',
'		attribute vec3 morphNormal2;',
'		attribute vec3 morphNormal3;',

'	#else',

'		attribute vec3 morphTarget4;',
'		attribute vec3 morphTarget5;',
'		attribute vec3 morphTarget6;',
'		attribute vec3 morphTarget7;',

'	#endif',
'#endif',

So, I think to get the same result as 3js, you can do:

var mtm = mesh.morphTargetManager;
var i = 8;
while (i-- > 0) {
    mtm.removeTarget(mtm.getTarget(mtm.numTargets - 1));
}

to remove the last 4 position + 4 normals from the morph target manager and keep only the first 4 + 4.

1 Like

FWIW

The morph targets section in the glTF spec has an implementation note on this:

Implementation note: The number of morph targets is not limited in glTF. A conformant client implementation must support at least eight morphed attributes. This means that it has to support at least eight morph targets that contain a POSITION attribute, or four morph targets that contain a POSITION and a NORMAL attribute, or two morph targets that contain POSITION , NORMAL and TANGENT attributes. For assets that contain a higher number of morphed attributes, renderers may choose to either fully support them (for example, by performing the morph computations in software), or to only use the eight attributes of the morph targets with the highest weights.

Perhaps, we should limit to 8 morph attributes. I can do this in the loader. But in any case, the author of the glTF model should avoid using more than 8 morph attributes as it won’t work in all cases.

1 Like

@lizzl If three only supports 8 morph attributes, it probably is dropping the extra morph attributes. Does the model still animate properly in three?