Using the GUI to load Assets

Hello!

I have created two asset managers, each populated with either .stl meshes with materials assigned or bespoke .babylon js files from Blender. I can call these from within my createScene function using the .load() command and everything works as expected.

I am now trying to attach these load() commands to a gui with little success. Basically I want one checkbox on and its linked assets loaded at startup and the other checkbox off and its assets not loaded. the checkboxes should then function as one would expect, loading and unloading the contents of the assetmangers depending on their state.

My first issue is that even if I create an advanceddyanmictexture and nothing else, this single line of code causes the .html not to load. I have placed it within my createScene function as the playground example suggets but I just get a white screen on navigating to the page.

This is pretty fundamental as I can’t test any of the rest of the code without being able to call this first part of the gui. Secondly, I’m not sure of the correct syntax to load / unload assetmanagers using a checkBox. I assume I need a function driven by the checkedchangeobservable watch which in turn gets it’s value from checkbox.ishchecked but again until I can even get the GUI to load I can’t progress.

Fullcode for the createScene function below for reference.

// Add your code here matching the playground format

    var createScene = function () {

        //Create Scene    

        var scene = new BABYLON.Scene(engine);  

        //Material Definition

        var wakeInner = new BABYLON.StandardMaterial("myMaterial", scene);
            wakeInner.diffuseColor = new BABYLON.Color3(0.7, 0.7, 0.7);
            wakeInner.alpha = 0.25;

        var wakeMid = new BABYLON.StandardMaterial("myMaterial", scene);
            wakeMid.diffuseColor = new BABYLON.Color3(0.8, 0.8, 0.8);
            wakeMid.alpha = 0.175;

        var wakeOuter = new BABYLON.StandardMaterial("myMaterial", scene);
            wakeOuter.diffuseColor = new BABYLON.Color3(0.9, 0.9, 0.9);
            wakeOuter.alpha = 0.1;

        //  Create the Asset Managers

        var wakeAssets = new BABYLON.AssetsManager(scene);
        var carAssets = new BABYLON.AssetsManager(scene);

        // Add Meshes to Asset Managers

        var meshTask1 = wakeAssets.addMeshTask("", "", "", "isosurfaces_CpT0pt0Trimmed-20per-rot.stl");

        meshTask1.onSuccess = function (task) {

            task.loadedMeshes[0].material = wakeInner;

        } 

        

        var meshTask2 = wakeAssets.addMeshTask("", "", "", "isosurfaces_CpT0pt4Trimmed-20per-rot.stl");

        meshTask2.onSuccess = function (task) {

            task.loadedMeshes[0].material = wakeMid;

        } 

        var meshTask3 = wakeAssets.addMeshTask("", "", "", "isosurfaces_CpT0pt8Trimmed-20per-rot.stl");

        meshTask3.onSuccess = function (task) {

            task.loadedMeshes[0].material = wakeOuter;

        } 

        var meshTask4 = carAssets.addMeshTask("", "", "", "F12022.babylon");



        // Camera Controls

        var camera = new BABYLON.ArcRotateCamera("camera", 0, 0, 10, new BABYLON.Vector3(), scene);

        camera.setPosition(new BABYLON.Vector3(2, 2, 2));

        camera.attachControl(canvas, true);

        camera.wheelPrecision = 30; 

        camera.useAutoRotationBehavior = true;

        camera.autoRotationBehavior.idleRotationSpeed = 0.25;

        // Light Control

        const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0));

        // GUI

        var advancedTexture = BABYLON.GUI.AdvancedDynamicTexture.CreateFullscreenUI("UI");

        var panel = new BABYLON.GUI.StackPanel();

        panel.width = "200px";

        panel.isVertical = false;

        panel.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_RIGHT;

        panel.verticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_CENTER;

        advancedTexture.addControl(panel);

        var wakeCheckbox = new BABYLON.GUI.Checkbox();

        wakeCheckbox.width = "20px";

        wakeCheckbox.height = "20px";

        wakeCheckbox.isChecked = false;

        wakecheckbox.onIsCheckedChangedObservable.add(function(value) {

            //Code to Load wakeAssets depdning on state

                //wakeAssets.load();

        });

        panel.addControl(wakeCheckbox);

        var carCheckbox = new BABYLON.GUI.Checkbox();

        wakeCheckbox.width = "20px";

        wakeCheckbox.height = "20px";

        wakeCheckbox.isChecked = true;

        wakecheckbox.onIsCheckedChangedObservable.add(function(value) {

            //Code to load carAssets

                //carAssets.load();

        });

        panel.addControl(wakeCheckbox);

                                

        //  Sound Control

        const sound = new BABYLON.Sound("f1-theme", "Formula 1 Theme Live in Concert by Brian Tyler.mp3", scene, null, { loop: true, autoplay: true });

  

        return scene;

    };

You must have an error somewhere: have you looked at the console of the browser?

Also, it will be much easier to help if you can provide a repro in the Playground.

Thanks for your feedback. The error the console throws is:

Uncaught TypeError: Cannot read property ‘AdvancedDynamicTexture’ of undefined
at createScene ((index):49)
at (index):54

This seems to occur in any project as soon as I call the advanceddynamictexture, i.e. even if I only add this single line of code.

var advancedTexture = BABYLON.GUI.AdvancedDynamicTexture.CreateFullscreenUI(“UI”);

Understood regarding the playground. Ill need to cobble something together as I can’t currently share the assets Im working with and also Ive never managed to get the playground to work with local assets but I imagine I can just get it to try and load anything…

Thanks,
Sy

Do I need a new src in the header? At the moment I cam just calling these 3?

src=“https://cdn.babylonjs.com/babylon.js”></script
src=“https://cdn.babylonjs.com/loaders/babylonjs.loaders.min.js”>
src=“https://code.jquery.com/pep/0.4.3/pep.js”>

Yes, you need the gui: https://cdn.babylonjs.com/gui/babylon.gui.min.js

Great - that fixed the first problem but now I need the equivalent of a .setEnabled property for things loaded via a sceneloader or assetmanager.

For example. If I create a sphere thus…

var sphere = BABYLON.MeshBuilder.CreateSphere(“sphere1”, {diameter: 2}, scene);

I can make it visible via a checkbox like this…

myCheckbox.onIsCheckedChangedObservable.add(function(value) {
sphere.setEnabled(value);
});

But is there an equivalent for meshes loaded either via the scene loader like this
BABYLON.SceneLoader.ImportMeshAsync(“box”, “”, “scene.babylon”);

Or for the asset manager after it is loaded? The below for example doesn’t work…
myAssetManager.setEnabled(value);

Or do I have to load the meshes another way?

Thanks,
Sy

I think asset containers are what you need:

Hello,

First of all thank you for your continued support. Thanks to your help I have managed to manually declare an assetContainer and push a sphere into it. I can then add or remove this container from the scene via a checkbox. What I am still struggling with is how to do this with a loaded assetContainer. I have attached a playground for reference.

Line 17 has the alternative way of declaring an assetcontainer via a loaded file. If you uncomment out line 19, the skull loads properly. However, I don’t see how to call container2 from outside this internal function. For example, if you replace container with container2 on lines 49 and 51 it breaks. I’m clearly missing something small and obvious but I cant work out how to call the “loaded” assetContainer from outside.

The required functionality is the skull becoming visible and not visible via the checkbox.

Hope this makes sense?

Thanks,
Sy

https://playground.babylonjs.com/#CCR9FQ#2

I think this one is doing what you want:

https://playground.babylonjs.com/#CCR9FQ#4

2 Likes

Ha ha! Wonderful! Thankyou very much for all your help. I’m learning slowly but the community support is fantastic.

Thanks again,
Sy

2 Likes

Hi again,

Sorry - I thought I had cracked this but I am still having issues. Whilst this works in the playground it is falling down in implementation.

I changed the

var createScene = function() {

to

var createScene = async function() {

at the top of code but the console flags the following error

Uncaught TypeError: scene.render is not a function
at t._renderFrame
at t._renderLoop

I believe there is now some issue with this render loop at the base of the code?

// Register a render loop to repeatedly render the scene
engine.runRenderLoop(function () {
scene.render();
});

If I dont change the initial createScene to async function the code also doesnt work. Sorry for this - I thought I had it working but only in the playground it seems…

Thanks,
Sy

When using async, the object returned is not a scene anymore but a Promise<scene>.

Before your loop, you should do:

const scene = await createScene();

This way, you will get the scene and not the Promise.

An alternate way:

createScene().then((scene) => {
    engine.runRenderLoop(function () {
        scene.render();
    });
});
1 Like

Hi again,

I got the alternative way to work but the first method did not work for me. I’m not sure there is a better or worse way but it working currently!

Thanks again for all your help.
Sy