How do I switch scenes?

I don’t want to use this method - https://www.babylonjs-playground.com/#JA1ND3#48 because I cannot load 100mb worth of files in one function and have to split them up. I am making a slideshow of 3d models and need to be able to cycle through a bunch of highly customized and large scenes.

So does anyone have a simple example of how to clear out the old scene which contains a .babylon or .glb or .gltf file in the canvas and render a completely new one using event listeners on a button?

Some more context for what I am doing … I have created a UI that is outside of Babyon and loads up a scene using ES6 module. Inside the .js file i am importing something like this code below:

export const loadScene = canvasElementID => {

  var canvas = document.getElementById(canvasElementID);
  var engine = new BABYLON.Engine(canvas, true);

  /******* Add the create scene function ******/
  var createScene = function() {
    var scene = new BABYLON.Scene(engine);

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

    camera.setPosition(new BABYLON.Vector3(0, 5, 60));
    camera.attachControl(canvas, true);

    var light1 = new BABYLON.HemisphericLight(
      "light1",
      new BABYLON.Vector3(80, 0, 420),
      scene
    );
   
    // import glb
    var exampleGLB = BABYLON.SceneLoader.Append(
      "./scenes/car/gltf/",
      "Car.glb",
      scene,
      function(scene) {}
    );

    return scene;
  };

};

I need to properly destroy/dispose/garbage collect that scene and load up another one when the user clicks a button. I have 50 scenes and am looking for a good way to do this so the user can jump around these scenes relatively quickly, ideally with some sort of caching enabled as they will be coming back to scenes they have already opened a lot.

Edit - Here’s a simple codepen example of what I am trying to achieve - https://codepen.io/john_smith_terms/pen/eobpzg

2 Likes

Hi,

You could use an assetContainer to load the files : Load from any file type - glTF, OBJ, STL, etc. - Babylon.js Documentation

Then dispose it when you don’t need it anymore :
https://doc.babylonjs.com/api/classes/babylon.assetcontainer#dispose

Now if you want to keep assets in cache don’t dispose it, rather use removeAllFromScene() AssetContainer - Babylon.js Documentation

Thanks for your reply. The first link you gave is the same as the one I provided in the top post and as far as I can see this does not solve my question.

Let me put this in a different way because I may not have explained it properly.

I have a a project which consists of 3 project files.

index.html
./scenes/firstScene.js ( code = https://www.babylonjs-playground.com/#QYFDDP#1)
./scenes/secondScene.js (code = https://www.babylonjs-playground.com/#8ZNVGR#0)

The index.html contains 2 buttons which will allow me to load up either scene when the button is pressed.

So what is the correct way to load the code in the links above but by storing that code in separate files and clearing out the scene when another one is loaded?

This should be a super simple answer I would imagine.

Something like this ?

//index.html
var scene;

on button click, => 
if(scene){
    scene.dispose();
    scene = null;
}
scene = createSceneBasedOnBtn();

any imported files and textures should be cached and load faster if you go back to a disposed scene

1 Like

Are you saying to put in 50-100 if statements in the engine.runRenderLoop() for each of my scenes?

Here is a codepen https://codepen.io/john_smith_terms/pen/eobpzg … perhaps this might help if anyone has some suggestions about how to best switch scenes.

what do you mean 50-100 if statements?

you’re already doing what i did in my example, except if you want the scenes to be released / garbage collected, add scene.dispose() before creating a new

function loadLeft() {
 if(scene) {
    scene.dispose();
 }
 scene = createScene();
}

etc

update;
I think this might help you more:
I added

var sceneIndex = 0;
var scenes_arr = [];
// now simply scenes_arr.push( createSceneFunction ) for each scene file you have
the buttons now loop through this array, so if first scene is being rendered and you go back/left, last scene will be rendered, and vice versa.

https://codepen.io/anon/pen/eobzJB

Don’t follow you. When I try to use this method i get the following error and the scenes do not always load - “Added non-passive event listener to a scroll-blocking ‘wheel’ event.”

I think the problem is related to the fact that I am using “ES6 module” to load the code from external files… I am starting to think that no one has tried to load scenes this way yet.

Does anyone have working examples of how to load scenes stored in external .js files into an index.html using ES6 module or a similar method?

The above methods give me various errors and do not work consistently. I do not want to have an index.html file with 50 scenes that is 5000 lines of code.

as i explained, all you need is to do in your xxxxScene.js files is:

scenes_arr.push( 
 function() {
   // create scene function
 }
)

I do not use es6 modules, so i can’t help you there.
Good luck.

Thanks I appreciate your help, I think I probably need a working example of loading scenes from external files to be able to understand how to do it.

Does that help?
https://www.babylonjs-playground.com/#058SEW#11

No. I can load external .glb .gltf, .babylon files no problem in their own scenes one at a time.

The problem I am having is that I have 50 babylon scenes with a bunch of custom code in each which also contain 3d models I have created in Maya, Zbrush and Blender and each one of those scenes contains a bunch of custom code for babylon particles and animation and all sorts. Each one of those files is Babylon code and 3d files (glb) consisting of 2mb -20mb file sizes. And I want to know what is the best way to keep all that code split up into their own little nicely compartmentalized files and only import them into my main index.html and initialize them when the user wants to see them. Like a sketchfab gallery in a single page application.

In short what is the best/recommended way to switch out “FirstScene” with “SecondScene” in the runRenderLoop() ?

I am currently using ES6 module imports like this

    <script type="module">
        import * as FirstScene from './scenes/FirstScene/FirstScene.js';
        import * as SecondScene from './scenes/SecondScene/SecondScene.js';
        import * as ThirdScene from './scenes/ThirdScene/ThirdScene.js';
        import * as FourthScene from './scenes/FourthScene/FourthScene.js';
    var scenes = [
      {"name": FirstScene},
      {"name": SecondScene},
      {"name": ThirdScene},
      {"name": FourthScene},
    ];

var createScene = scenes[0].name.loadScene();

var canvas = document.getElementById("renderCanvas"); // Get the canvas element
var engine = new BABYLON.Engine(canvas, true); 

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

But I was having some problems switching out the scenes dynamically and was looking for the recommended way to do this.

I think i’m nearly there now but still looking for working examples if there is a recommended way to organize and load scenes from external files and have them garbage collect properly.

1 Like

Ok make sense. Then I think you have everything you need.
You can jsut add a bit of code in your button like:

 myButton.addEventListener("click", () => {
createScene = scenes[1].name.loadScene();
});

So that way you do not need to change you render loop.

To go further I would encourage you to repro your issue somewhere online so we can run the actual code to test

1 Like

We did this using Dynamic Import Function:

nx.sceneSeq=[
  'many','file','names'
];//scene versioning mechanism
nx.loadSceneSeq = function(){ //scene-loader-.
    var scenePath = './scenes/'+nx.sceneSeq[nx.sceneSeqIdx]+'.js';
    import(scenePath)
    .then(function(sceneData) {
        sceneData.initScene();
        nx.sceneSet.push(sceneData); //save sceness for cleanup-.
        nx.sceneSeqIdx++;  //increment forward in sceneSequence-.
    });//.catch(function(e){console.log('error loading scene: '+e)});
}  
export var initScene = function(){ createScene(); ... }

Thanks Deltakosh … this is what I am currently doing and I am having some problems with the scenes not loading correctly. I will do some debugging and if I cannot figure it out will upload some code to reproduce the problem somewhere.

1 Like

@John_Smith I’m interested in how to best do this also, so it’d be great if you are able to report back how you solved it :slight_smile:

Hi, 1st time posting on this forum.

I am facing a problem similar to the problem being discussed here. I have 2 scenes, a “HomeScene” and a “GameplayScene”, the former being the 1st scene of the game. The “GameplayScene” uses a lot of assets (textures, models, sounds, fonts etc), so I want to preload all those assets and cache them in memory.

My initial idea was to load all those assets at the start of the game, before the “HomeScene” is displayed. I tried to use AssetsManager as well as AssetContainer, but both of them work only with the scene currently being loaded, and there is no clear-cut way to transfer all the loaded assets to another scene.

This is a very common task and I have done the same task in other game engines before. But in those other game engines, loaded assets are not tied to a specific “scene”. I am curious why this is the case in Babylon.js, and would like to hear an explanation.

Hi @randle_mcmurphy, can’t you use different AssetContainers to populate the one scene and/or different AssetsManagers for different scenes? They seem quite flexible in that regard, but maybe I’m not understanding your use case.

Im confused kinda, do you have all your scenes and assets preloaded? Or are you talking about cascading the scenes to the client and rending the first ready one then like toggling between different scenes? If that’s the case then just store them in an array as they come in and switch out which one is being used in your render loop by a selected Id? If I understand what your trying to do. If you need to switch between there is gonna have to be some sort of parsing unless you have all the assets already spun up. You could in that case have a secondary engine parsing the scenes that are loading but not being displayed then freezing them on complete. Then using that canvas data as a screen shot, so you don’t have to actually run the scenes constantly but still have a preview.