jupyter-widgets / pythreejs

A Jupyter - Three.js bridge
https://pythreejs.readthedocs.io
Other
934 stars 185 forks source link

Setting Bone Inverses #391

Open aliascc opened 1 year ago

aliascc commented 1 year ago

Hi,

I'm trying to add the inverse bind matrices to the skeleton but I am having the following problems (btw, I'm not an expect in JS. I'm trying to build some interactive 3D examples in Jupyter notebooks that use animations and this is the last step. Loading directly from GLTF sadly is not an option):

The Skeleton Model doesn't have the option to add it to it. I tried modifying the three-class-config to the following (adding boneInverses: new Types.ArrayBuffer('float32', [null, 16], {nullable: true}),):

Skeleton: {
        relativePath: './objects/Skeleton',
        properties: {
            bones: new Types.ThreeTypeArray('Bone'),
            boneInverses: new Types.ArrayBuffer('float32', [null, 16], {nullable: true}),
        },
        constructorArgs: ['bones', 'boneInverses'],
    },
  1. When creating an instance, I get a flat array instead of a 2D array (i.e. if I send 3 matrices4x4 I would expect a dimension of [3,16] but I get [48] which causes problems in the init function of the Skeleton. a. Any way to force the dimensions to be respected as stated in the three-class-config? b. Would it be ok to create a Skeleton.js next to Skeleton_autogen.js and extend constructThreeObject ? So I make sure to send the correct 2D array? Would this cause any issues?

  2. Even getting around problem 1 (which I tried and seemed to be working), I get an issue when I try to bind the Skeleton to the SkinnedMeshModel here:

    assignSkeleton(obj, key, value) {
        if (value) {
            obj.bind(value);
            obj.scale.multiplyScalar(1);
        }
    }

Calling the bind function for the SkinnedMesh expects the skeleton and bindMatrix but only the skeleton gets send:

bind( skeleton, bindMatrix ) {

        this.skeleton = skeleton;

        if ( bindMatrix === undefined ) {
            this.updateMatrixWorld( true );

            this.skeleton.calculateInverses();

            bindMatrix = this.matrixWorld;

        }

As it expects bindMatrix to be defined and it is not, it will override the inverse bind matrices by calling this.skeleton.calculateInverses() function

I haven't been able to get around this issue, as I don't want to break the current behavior. I've thought of maybe setting a boolean before assigning the skeleton using a different function but I don't really understand how the calls are made to JS, because a function I tried to set always got called after the assignment.

vidartf commented 1 year ago

Hi,

Thanks for taking the time to write a detailed issue, and sorry for not replying to it sooner. Here are some comments that I hope are helpful: