GLB file with animation from Blender, Animation Autostart issue

Hi.
I am loading a .glb file from blender like this:

// digital assets
import diamond from "../../assets/glb/pureRhombo.glb";
import { pbrBlockGeometryInfo } from "@babylonjs/core/Shaders/ShadersInclude/pbrBlockGeometryInfo";
//import { GLTFLoaderAnimationStartMode } from "@babylonjs/loaders";

export class ColorDiamond implements CreateSceneClass {
    createScene = async (
        engine: Engine,
        canvas: HTMLCanvasElement
    ): Promise<Scene> => {
        // This creates a basic Babylon Scene object (non-mesh)
        const scene = new Scene(engine);

  
        // SceneLoader
      
         //await SceneLoader.ImportAnimationsAsync("", "", diamond, true,0,undefined);
        await SceneLoader.ImportMeshAsync("", "", diamond, scene, undefined, ".glb");
        const crystalMesh = scene.getMeshByName("RGBVMC.002");

....

This works well until I export an Animation within the .glb file.
Then the same script produces this error:

Uncaught (in promise) RuntimeError: Unable to load from ......: this_1._scene.beginDirectAnimation is not a function
    at RuntimeError.BaseError [as constructor] (babylonBundle.js:95187:42)
    at new RuntimeError (babylonBundle.js:95237:28)
    at errorHandler (babylonBundle.js:48097:46)
    at babylonBundle.js:48151:21

The model itself with animation loads well in the sandbox and other viewers.
The animation starts immediately (which probably is the issue).

Blendergltf export does not offer an option to Play/start/stop a animation and write that out with the export.
So I guess, that is a standard behavior for the export?

I found this:

   BABYLON.SceneLoader.OnPluginActivatedObservable.add(function (plugin) {
        plugin.animationStartMode = BABYLON.GLTFLoaderAnimationStartMode.NONE;
    }, undefined, undefined, undefined, true);

on a PG:

Do I need to do that, or similar when I load a glb file with animation in general?

Cheers.
Werner

Hello! Can you provide us with a playground with your model? :slight_smile:

Hi.
It works well in the JS PG.

We moved it to local development and TS.
There I get the error.

I am not sure how to get the TS script back to PG?

Here is the JS PG

This is the TS script:

import { Engine } from "@babylonjs/core/Engines/engine";
import { Scene } from "@babylonjs/core/scene";
import { ArcRotateCamera } from "@babylonjs/core/Cameras/arcRotateCamera";
import { Vector3, Vector4} from "@babylonjs/core/Maths/math.vector";
import { Color4} from "@babylonjs/core/Maths/math.color";
import { CreateSceneClass } from "../createScene";
import { SceneLoader } from "@babylonjs/core/Loading/sceneLoader";
//import "@babylonjs/inspector";
import { VertexBuffer } from "@babylonjs/core/Buffers";
import { AdvancedDynamicTexture } from "@babylonjs/gui/2D";
import { Button, Control } from "@babylonjs/gui/2D/controls";
import { ActionManager } from "@babylonjs/core/Actions";
import { ExecuteCodeAction } from "@babylonjs/core/Actions";


// required imports
import "@babylonjs/core/Loading/loadingScreen";
import "@babylonjs/loaders";
import "@babylonjs/core/Materials/standardMaterial";
import { PBRMaterial} from "@babylonjs/core/Materials/PBR/pbrMaterial";
import "@babylonjs/core/Materials/Textures/Loaders/envTextureLoader";


// digital assets
import diamond from "../../assets/glb/pureRhombo.glb";
import { pbrBlockGeometryInfo } from "@babylonjs/core/Shaders/ShadersInclude/pbrBlockGeometryInfo";
import { GLTFLoaderAnimationStartMode } from "@babylonjs/loaders";

export class ColorDiamond implements CreateSceneClass {
    createScene = async (
        engine: Engine,
        canvas: HTMLCanvasElement
    ): Promise<Scene> => {
        // This creates a basic Babylon Scene object (non-mesh)
        const scene = new Scene(engine);

        scene.clearColor = new Color4(0.3, 0.3, 0.3);


        // This creates and positions a free camera (non-mesh)
        const camera = new ArcRotateCamera("my first camera", 0, 0, 0, new Vector3(0, 0, 0), scene);
        camera.setPosition(new Vector3(0, 5, -10));

        // This attaches the camera to the canvas
        camera.attachControl(canvas, true);

      
        // SceneLoader
      
         //await SceneLoader.ImportAnimationsAsync("", "", diamond, true,0,undefined);
        await SceneLoader.ImportMeshAsync("", "", diamond, scene, undefined, ".glb");
        const crystalMesh = scene.getMeshByName("RGBVMC.002");
        //const anima = scene.getAnimationGroupByName("RGBV1000Action");
        //anima.play(true);

        //const importResult = await SceneLoader.ImportMeshAsync("","",diamond,scene,undefined,".glb");

        if (crystalMesh == null) {console.log("NO MODEL LOADED");}

   
        var sphereMat = new PBRMaterial("diamMat",scene);
        //var sphere = BABYLON.MeshBuilder.CreateSphere("sphere", {diameter:10, updatable: true}, scene);
        //var sphere = BABYLON.MeshBuilder.CreateBox("box", {size: 5}, scene);
            //If no colors add colors to sphere
        crystalMesh!.material = sphereMat;
        sphereMat.unlit = true;


        ////get original colors, create the Color table from the float table.

        var colors = crystalMesh!.getVerticesData(VertexBuffer.ColorKind);
        var Ncolors:Color4[];
        Ncolors=Array(0);

        console.log("Original Colors", colors); ///// Original colors

        for (var p = 0; p < colors.length / 4; p++) {
            var col = new Color4(colors[(p * 4)], colors[(p * 4) + 1], colors[(p * 4) + 2], colors[(p * 4) + 3]);
            Ncolors.push(col);

        }


        ///generate unique key function
            
            var ColorToKey = function(ucolor:Color4):number
            
            {
                return Math.trunc(ucolor.r * 255.0) +Math.trunc(ucolor.g * 255.0)*256 +Math.trunc(ucolor.b * 255.0)*256*256;
            }  

            var diction = new Map<number, number[]>(); ////// create dictionary

            for (var i=0; i< Ncolors.length; i++)

                {
                    var key = ColorToKey(Ncolors[i]);
                
                    if (!diction.has (key))
                    {
                        var indexAr:number[] = Array(1);
                        indexAr[0] = i;
                        diction.set(key, indexAr);
                    }
                    else
                    {
                        var indexAr=diction.get(key);
                        indexAr.push(i);
                    }


                }

    console.log("Dic",diction); ///// Original colors

        var VCassign = function () {

            console.log("length", colors.length);


            var Acolors = new Array(colors.length);
            var values = Array.from(diction.values());

            for (var j = 0; j < values.length; j++) {

                let newCol = new Vector4(Math.round(Math.random()), Math.round(Math.random()), Math.round(Math.random()), 1);

                var indexAr = values[j];

                for (var i = 0; i < indexAr.length; i++) {
                    Acolors[indexAr[i] * 4] = newCol.x;
                    Acolors[indexAr[i] * 4 + 1] = newCol.y;
                    Acolors[indexAr[i] * 4 + 2] = newCol.z;
                    Acolors[indexAr[i] * 4 + 3] = newCol.w;
                }
                
            }


            // Ncolors.push(colors[(p*4)],colors[(p*4)+1],colors[(p*4)+2],colors[(p*4)+3]);

            crystalMesh.setVerticesData(VertexBuffer.ColorKind, Acolors);
            //console.log("Positions", positions);
            console.log("NColors", Ncolors);
            console.log("AColor", Acolors);

        }


        //GUI Buttons / Invisible
        const adt = AdvancedDynamicTexture.CreateFullscreenUI("UI");
        var buttonHide = Button.CreateSimpleButton("buttonHide", " ");

        buttonHide.height = "200px";
        buttonHide.verticalAlignment = Control.VERTICAL_ALIGNMENT_BOTTOM;
        buttonHide.alpha = 0;
        buttonHide.color = "white";
        buttonHide.thickness = 0;
        buttonHide.onPointerClickObservable.add(() =>
        {
            buttonHide.alpha=0;
            //adt.isVisible = true;
            engine.exitPointerlock();

        VCassign();

        });
        adt.addControl(buttonHide);

        var FSbutton = Button.CreateSimpleButton("but1","")
        //FSbutton.width=1
        FSbutton.horizontalAlignment=Control.HORIZONTAL_ALIGNMENT_CENTER;
        FSbutton.height="100px"
        FSbutton.color="white"
        FSbutton.alpha=0;
        FSbutton.thickness = 0;
        FSbutton.verticalAlignment=Control.VERTICAL_ALIGNMENT_TOP;
        adt.addControl(FSbutton)

        FSbutton.onPointerUpObservable.add(function(){
            engine.switchFullscreen(true);
            engine.exitPointerlock();
            FSbutton.alpha=0;
            //adt.isVisible = true;
        })


    ////////////KEYBOARD input /////////////////
    scene.actionManager = new ActionManager(scene);
    scene.actionManager.registerAction(new ExecuteCodeAction(ActionManager.OnKeyUpTrigger, function (evt) {
      //if ("w" == evt.sourceEvent.key) VCassign();
       VCassign();
       engine.exitPointerlock();
    }));





        return scene;
    };
}

export default new ColorDiamond();

Best. Werner

Hmmm, if it’s working on the PG but not locally that might be an issue with the packages. Let me try the same thing here. How are you constructing your bundle?

We r pretty new to that topic, so I dont know how to describe that?

I started with this

We modified it and building it… uhm.
As I said, not much experienced yet. :roll_eyes:

Which infos would you need?

Oh, starting with the template is a great start! Makes it easier to reproduce :slight_smile: Did you change anything on the package.json file?

I think we didnt.


{
    "name": "babylonjs-typescript-webpack-simple-scene",
    "version": "0.0.1",
    "description": "A simple scene using Babylon.js, typescript and webpack. What could go wrong?",
    "main": "index.ts",
    "dependencies": {
        "@babylonjs/core": "^5.0.2",
        "@babylonjs/inspector": "^5.0.2",
        "@babylonjs/loaders": "^5.0.2",
        "ammo.js": "github:kripken/ammo.js"
    },
    "devDependencies": {
        "@typescript-eslint/eslint-plugin": "^5.12.0",
        "@typescript-eslint/parser": "^5.12",
        "clean-webpack-plugin": "^4.0.0",
        "eslint": "^8.9.0",
        "file-loader": "^6.2.0",
        "html-webpack-plugin": "^5.5.0",
        "source-map-loader": "^3.0.1",
        "ts-loader": "^8.3.0",
        "typescript": "^4.5.5",
        "url-loader": "^4.1.1",
        "webpack": "^5.68.0",
        "webpack-cli": "^4.9.2",
        "webpack-dev-server": "^4.7.4",
        "webpack-merge": "^5.8.0"
    },
    "scripts": {
        "start": "npx webpack serve --config webpack.dev.js",
        "build:dev": "npx webpack --config webpack.dev.js",
        "build": "npx webpack --config webpack.prod.js",
        "lint": "npx eslint . --ext .ts,.tsx"
    },
    "repository": {
        "type": "git",
        "url": "git+https://github.com/RaananW/babylonjs-webpack-es6.git"
    },
    "keywords": [
        "Babylon.js",
        "webpack",
        "getting started",
        "typescript",
        "es6"
    ],
    "author": {
        "name": "Raanan Weber",
        "email": "info@raananweber.com",
        "url": "http://blog.raananweber.com/"
    },
    "license": "Apache-2.0",
    "bugs": {
        "url": "https://github.com/RaananW/babylonjs-webpack-es6/issues"
    },
    "homepage": "https://github.com/RaananW/babylonjs-webpack-es6"
}

Ok :smiley: Can we have access to your model so we can test in our side?

Or even better, if you can put your project in github and share it, it’s better for us in the forum to see what’s going on

huh. That, my programmer has to do.need to wait until tomorrow :wink: (the github)
But here is the model : http://www.ciller.biz/downloads/pureRhombo.glb
I think you need to copy that address into the address bar.

Thanks for checking it… Hope I didnt make a stupid mistake.

I had this error too and importing animatable fixed it (that’s the module that defines the missing beginDirectAnimation function)… :slight_smile:

import "@babylonjs/core/Animations/animatable";
3 Likes

All of those side effects are detailed here:

This is the downside of the way we handled es6 packaging. We will address it soon with a different structure (and a different package)

3 Likes

Thank you for this!
Amazing. Now it runs. Lovely.

1 Like

Hm. I read that before, but there are too many unknowns atm. in general.
So the whole packaging, building, publishing aso. we need to get into.

1 Like