Default scene instead of passing around everywhere

There’s a bit of a strange pattern I see with single scene experiences. I don’t know how common that is, but I have to believe at least for beginners it’s the “default” way of operating. Was wondering if there was an appetite to add a “default scene” concept. I found myself doing something like this:

export class VrApp {
    private static _scene: Scene;
    private engine: Engine;
    //preTasks = [havokModule];

    public static get scene(): Scene {
        return VrApp._scene;
    }
    constructor() {
        const canvas = (document.querySelector('#gameCanvas') as HTMLCanvasElement);
        this.engine = new Engine(canvas, true);
        this.engine.setHardwareScalingLevel(1 / window.devicePixelRatio);
        window.onresize = () => {
            this.engine.resize();
        }
        const scene = new Scene(this.engine);
        scene.ambientColor = new Color3(.1, .1, .1);
        VrApp._scene = scene;

and having everything get the scene by saying VrApp.scene.

It got me wondering though, much like default lights/etc might it make sense to have a Scene.defaultScene (or event put it on the individual scene instances). We could then make the scene parameter optional on all the stuff that “needs it” and “it would just work if there’s only one scene” and would still work if you passed it in. I reached this point because I was tired of having to pass something around that I “knew” I only had one of and I have to believe that’s a pretty common problem.

Sorta falls into “sensible default behavior” category in my mind…

Heeeyyyy, wait a minute…I’m noticing the scene on transformnode is optional, maybe I jumped to a conclusion about requiring a scene. will have to dig into this, maybe we’re already doing this sort of thing? Well I’ll be danged…at least in transformnode decendents (what I care about mostly) it seems this may already be handled-ish.

OK, never mind, didn’t dig deeply enough.

babylon does have a property like LastCreatedScene that you would say, which is passed in as a default value when some objects are built such as UtilityLayerRenderer.
But I don’t think it’s reliable because it will be overridden by the newly built scene, which can lead to results that aren’t what you want. If you need to specify defaultScene, you need to maintain it separately.

Yes, for a number of methods that take an optional Scene parameter, if you don’t provide it, Babylon will use the value from Engine.LastCreatedScene.

That was what I was wondering as I went down the rabbit hole. I ended up doing this instead which works very nicely for my purposes…Haven’t tested edge cases, but put in checks “just in case”.

import {Engine, Scene} from "@babylonjs/core";
import log from "loglevel";

const logger = log.getLogger('DefaultScene');
export class DefaultScene {
    private static _Scene: Scene;

    public static get Scene(): Scene {
        if (!DefaultScene._Scene) {
            logger.error('default scene not yet created');
            if (Engine.LastCreatedScene) {
                logger.warn('using last created scene, this may not be what you want, proceed with caution');
                DefaultScene._Scene = Engine.LastCreatedScene;
                return DefaultScene._Scene;
            } else {
                return null;
            }
        } else {
            return DefaultScene._Scene;
        }
    }

    public static set Scene(scene: Scene) {
        if (DefaultScene._Scene) {
            logger.error('default scene already created, disposing and recreating');
            if (DefaultScene._Scene.isDisposed) {
                logger.warn('default scene is already disposed');
            } else {
                DefaultScene._Scene.dispose();
                logger.info('default scene disposed');
            }

            DefaultScene._Scene = null;
        }
        DefaultScene._Scene = scene;
        logger.info('default scene created');
    }
}
1 Like