One scene, two canvases - intermittent camera controls and frame persistence, partially works

I’m experimenting with multi-views.

Goal is a “bird’s eye” view camera in an inset that overlays another larger view from a second camera which could be a FPS or some other type of camera. I’m close to getting it working but there is odd behavior. First the render does not update unless I resize the browser. Second camera controls are uhmm intermittent until a couple of seconds after resizing the browser. Third when the render does show the simple animation I made the frames persist, like its painting on the canvas. Seeing the PlayGround in action best explains. Another I’m a noob to the playground and cannot get it to run. So I also included HTML/CSS and the BJS source.

Update: I was able to get a JSFiddle demo going: https://jsfiddle.net/kdwoell/2wqj0fx6/1/

Blockquote

canvas { width: 100%; height: 100%; align-self: center; justify-self: center; }
    /* any HTML elments of class = ".renderCanvas" width and height set to 100% of browser window */
    .renderCanvas {
        width: 100%;
        height: 100%;
        position: absolute;
        left: 0px;
        top: 0px;
    }

    #renderCanvas0 {
        width: 100%;
        height: 100%;
        position: absolute;
        left: 0px;
        top: 0px;
        /* background: transparent; */
        background:rgba(200, 200, 200, 1);
        z-index: 0;
    }

    #renderCanvas1 {
        width: 25%;
        height: 25%;
        position: absolute;
        left: 0px;
        top: 0px;
        background:rgba(0, 200, 200, 0.5);
        outline-style: inset;
        z-index: 1;
    }
</style>
<title>Overlay Scene as Inset on Primary Scene - stacked canvases</title>
> Blockquote

Blockquote
window.addEventListener(‘DOMContentLoaded’, function () {

// Create a working document
var canvas = document.createElement("canvas");

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

// Set the default canvas to use for events
engine.inputElement = document.getElementById("renderCanvas0");

var createScene = function () {

    // This creates a basic Babylon Scene object (non-mesh)
    var scene = new BABYLON.Scene(engine);
    //scene.clearColor = new BABYLON.Color4(0, 0, 0, 0);
    //scene.autoClear = false;

    // This creates and positions a free camera (non-mesh)
    var camera = new BABYLON.ArcRotateCamera("Camera0", 0, 0.8, 5, new BABYLON.Vector3.Zero(), scene);
    camera.setTarget(BABYLON.Vector3.Zero());
    camera.wheelDeltaPercentage = 0.01;
    camera.minz = 0.0001;
    camera.lowerRadiusLimit = 1;
    camera.upperRadiusLimit = 100;

    // This attaches the camera to the canvas
    camera.attachControl(document.getElementById("renderCanvas0"), true);

    var camera1 = new BABYLON.ArcRotateCamera("Camera1", 0, 0, 100, new BABYLON.Vector3.Zero(), scene);   

    // assign canvases to cameras
    engine.registerView(document.getElementById("renderCanvas0"),camera);
    engine.registerView(document.getElementById("renderCanvas1"), camera1);

    // This creates a light, aiming 0,1,0 - to the sky (non-mesh)
    var light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene);

    // Default intensity is 1. Let's dim the light a small amount
    light.intensity = 0.7;

    // Create Box
    var box = BABYLON.MeshBuilder.CreateBox("Box", { size: 2 }, scene);
    box.position.y = 0.5;

    var mat = new BABYLON.PBRMetallicRoughnessMaterial("mat", scene);
    mat.metallic = 1;
    mat.roughness = 0.5;
    box.material = mat;

    // create a sphere
    var sphere = new BABYLON.MeshBuilder.CreateSphere("sphere", { segments: 8, diameter: 1 }, scene);
    var sphereMaterial = new BABYLON.StandardMaterial("sphereMaterial", scene);
    sphereMaterial.diffuseColor = new BABYLON.Color3(100, 0, 100);
    sphere.material = sphereMaterial;
    sphere.position.z = 3;

    camera1.lockedTarget = sphere;

    //quick way to creat an quasi ground plane an skydome
    //scene.createDefaultEnvironment();

    // initialize increments for animations
    var deltaXpos = 0;

    scene.registerBeforeRender(() => {

        sphere.position.x = sphere.position.x + deltaXpos;
        //console.log("sphere x pos: ", sphere.position.x);

        deltaXpos += 0.000001;
    })

    return scene;

}; // end create scene function

var scene = createScene();

engine.runRenderLoop(function () {
    if (scene.activeCamera) {
        scene.render();
    }
});

window.addEventListener('resize', function () {
    engine.resize();
});

});

Blockquote

1 Like

Hi @kdwoell, welcome to the BabylonJS forum.

I think… what you seek… is often called a “minimap”. Although your 2-canvas approach is interesting, it can also be a challenge and have difficulties.

I suggest you use this link… to search for all playgrounds that mention “minimap” in the code: https://doc.babylonjs.com/playground/?code=minimap

Let’s also search for all playgrounds with “minimap” in their title:
https://doc.babylonjs.com/playground/?bjsq=minimap

Let’s search our forum for the term “minimap”: Search results for 'minimap' - Babylon.js

And, reluctantly, we’ll search our older forum… for the same: Showing results for 'minimap'. - HTML5 Game Devs Forum

Lots of “minimap” talk, eh? nod. Another good search term… is “viewport”.

Look at this example: https://www.babylonjs-playground.com/#J597MF#10

See line 95? mm (minimap) viewport command. We even have docs that talk about viewports.

Here’s another example: https://www.babylonjs-playground.com/#1OQMIG#3
See line 24? Yet another “viewport” usage.

And layerMasks can get involved. Layers/masks are used on nodes (mesh, lights, cams) to show/hide nodes. For example, you might want only SOME things shown in the mini-map (like trails thru forests)… but not ALL things (like where enemy are hiding).

These methods (viewports) are used to AVOID using 2-canvas’s. You will likely want to stay with your 2-canvas system, because you are familiar with it. But… once you learn about BJS viewports and other methods of making mini-maps… you will have more power and less problems.

Another example: https://www.babylonjs-playground.com/#17DP89#42
See the viewport command in line 19? Yep. ONE canvas, but the BabylonJS engine is able to “talk-to” two or more viewports. I suggest taking the time to learn about viewports and see other people’s minimaps.

Important Note: scene.activeCameras (an array - notice plural property name) and scene.activeCamera (not an array - not plural)… are important properties for viewports. And the ORDER of the cameras that get pushed-into scene.activeCameras… is important. You will be experimenting with these two scene properties… if/when you start working with viewports.

If you REALLY like pain, check out @Gijs custom GUI-2d control (widget)… which SEEMS to allow a mini-map… inside of a GUI-2d button! VERY advanced stuff… it makes my brain hurt… but it’s marvelous.

I hope I’ve been helpful, but more-likely, I have given you a brain tumor. Sorry. Be patient with yourself. Good luck. Let’s ask other forum members… WHO has a great-working mini-map system that we can borrow/learn-from? Please share. Thanks!

4 Likes

Wingnut you are most helpful! Yes I should have been searching on “minimap”. Wealth of information to review.

I had spent a lot of time on the documentation links you posted. I could not quite connect the dots between the various code snippets therein.

That said the PG of the torus over a ground map with the minimap in the upper left corner is very close to my goal. I have a local version running via live server in VS code and reviewing the concepts.

Q: What is the purpose of the statement below? I’ve read the documentation but I think I’m misinterpreting.

Blockquote
scene.activeCameras.push(mm);
Blockquote

Q2: My goal is the minimap is not static but has a camera view. The user gets focus in the minimap and can zoom out/in as desired, while the main scene continues to animate. I’ve read about camera Input Mangagers. Will I need to implement an Input Manager i.e. attach/detach camera as the user switches focus between layer masks?

Cool, thx. I get talky, and don’t say much, eh? This is a large subject.

Good question. Too complicated for me. First, let’s visit the BabylonJS source code and see the MANY places that use scene.activeCameras:

https://github.com/BabylonJS/Babylon.js/search?p=1&q=activeCameras

Pretty complicated, eh? I agree. So let’s just play.

Here’s the playground you speak-of, except I adjusted it slightly.

https://www.babylonjs-playground.com/#J597MF#11

Modifications I made:

  • changed name of main arcRotate ‘camera’ to be ‘mainArcCam’
  • changed name of minimap free camera ‘mm’ to be ‘mmFreeCam’
  • moved the code to PUSH both cams into scene.activeCameras - to line 100 area.

Ok, in line 100, mainArcCam is pushed into scene.activeCameras
In line 102, mmFreeCam is pushed into scene.activeCameras

Line 102 is what you asked-about.

Try disabling line 102 and click RUN (arrow) again. Minimap is gone, yes? nod.

So, that is the PRIMARY reason why we need line 102. It is telling BabylonJS ‘engine’… something important. :slight_smile: Mostly, it is telling the ‘engine’ that there is MULTIPLE cameras active in this scene. If you need more-detailed explanation… we will need the help of smarter people than I. :smiley: I am not an expert. I’m a junior-level forum helper.

Let’s re-enable line 102 and have some more fun and learn more.

See lines 119 and 120? It says… mmFreeCam layerMask is 1, and mainArcCam layerMask is 2.

For fun, let’s change line 119… to be layer mask 2.

mmFreeCam.layerMask = 2;

Now RUN again. (make sure you have re-enabled line 102). The minimap is “rendering” the same mesh nodes (ground and torus) as mainArcCam, now. Both cameras are rendering the same layer… layer 2.

Now let’s change lines 119 & 120… to this:

mmFreeCam.layerMask = 1;
mainArcCam.layerMask = 1;

Now RUN again. Now, the mainArcCam is “rendering” the same mesh nodes (mapGround and a sphere named ‘s’) as mmFreeCam. Both cameras are rendering the same layer… layer 1.

In lines 122-126, we can see the FOUR mesh nodes… getting their layerMask numbers. In normal conditions, the torus and (heightMap-) ground… are layer 1. The red sphere and (plane-based)(mini-)mapGround are layer 2.

So now we know a bit more about layerMasks, too.

More fun? Ok, https://www.babylonjs-playground.com/#J597MF#12
In PG #12, I have added a ‘box’ in lines 145-147, and set it to layerMask 3.
See how it appears in BOTH layers 1 and 2?

You bet. 1 + 2 = 3. So any nodes with layerMask 3… show in BOTH views.

Change line 147 to layerMask 4 or even higher layer. Try 252.

Box is gone.

Now try line 147 set to layerMask 253.

Box is showing in minimap again. But why is it black instead of gray? It is because of line 124. Moving onward…

Now try line 147 set to layerMask 254.

Box is showing in main view/layer again, and it is gray.

Now try line 147 set to layerMask 255.

Box is showing in both views/layers, and it is gray. Yay!

Decimal-to-Binary review time…
255 in binary… is 1111 1111 (box appears in layers 1 & 2)
252 in binary… is 1111 1100 (box disappears in layers 1 & 2)
3 in binary… is 0000 0011 (box appears in layers 1 & 2)
4 in binary… is 0000 0100 (box disappears in layers 1 & 2)

Ain’t this fun? Ok, it’s not as fun as frisbee golf, but kind-of fun, right?

Yeah, I know, I didn’t really answer your question, but I, once-again, talked a lot, huh? :slight_smile:

Oh yeah, Q2. How to zoom on minimap view? (and maybe drag ground) (and maybe click-on actionManager-enabled mesh, which auto-centers that mesh in minimap)

Gruesome. Essentially… https://www.babylonjs-playground.com/#J597MF#14

  • Disable attaching main cam to scene… line 10
  • Disable ortho mode… line 74
  • Probably attach mmFreeCam to scene… line 75 (I didn’t attach)
  • Add mousewheel zoom to free camera… lines 150-181

And lastly, add some kind of “mouse dragging” to minimap view… with possible click-on-mesh via actionManagers, which centers the clicked mesh in minimap view.

Not easy, but can be done.

Would actionManagers… need a layerMask feature/power? Mesh is clickable in minimap view, but not in main view? OMG! erf.

Good question, @kdwoell! Good BJS feature idea!

Click on main view… mainArcCam attaches to canvas and mmFreeCam detaches from canvas.

Click on minimap… mainArcCam detaches and mmFreeCam attaches to canvas.

A lot of work… but still… viewports method better than 2-canvas method, I think.

We could use some advanced coders on this project. It’s a good idea, though. We really haven’t got a “click-to-focus - advanced drag-the-ground minimap system”. Perhaps we could assign some “big dogs” to help code such a thing… a nice tool.

Just the focus system… could be a challenge. Click mini-map… detaches main cam, attaches mini cam, and vice-versa. COOOOOL! I wonder if anyone has ever tried a “viewport focus” system.

And then, how to make a dragged free/universal cam (minimap cam)… NOT tilt like a standard freecam, but instead… drag the ground laterally… beneath/within the minimap viewport area. Phew.

My brain hurts. Stay tuned for more comments, @kdwoell. I think we are all “tuned into your dream”, now. At least I am… but I have no time to code this… and it’s likely worthy of some big-dog attention. Super minimap… only from BJS Systems (and from @kdwoell’s inventive brain) . :slight_smile:

1 Like

There is also a completely different way, a camera which indirectly projects onto a mesh as a texture. I asked about it here:

This mesh would of course move with the main camera(s) movement. It just needs a mesh with a UV, most likely a plane

It is also VR / XR friendly. If you put the mesh into BILLBOARD mode, there is a new one for XR, it would make it more visible. Also pretty efficient in that the texture stays in the GPU, to then be attached to the mesh on later renderings by the main camera(s), multiples for XR.

Not what was really asked for, but one might make into an occasional sign / map, to show where you are. In today where everyone is being lead around by the nose with GPS, might make for something more interesting to only be available at certain times. Would kind of be a cool having your actual avatar being in the actual sign “marking you are here”.

Other wild effects possible. Like a fun house mirror using a backwards, distorted UV. Probably need something with a UV editor, Blender, to make that, but still.

I am using it as more a maxmap than a minmap, but that is just a very close camera, projected onto a large mesh.

Yeah, thx JC… I think I saw a demo like that… or near.

https://www.babylonjs-playground.com/#1VVORT#3

Uses a renderTargetTexture (rtt) on a plane.

Here’s 4 rtt’s on a panel. https://www.babylonjs-playground.com/#1WROZH#67 phew.

And another 3 viewport demo, which is actually a 5 viewport demo, because the blue lines are in viewports, too. https://www.babylonjs-playground.com/#13TVWJ#2

Still not sure about viewports and focus-switching. That’s why I included the above 5-viewport demo… because… the border around a minimap MIGHT indicate if it is focused-upon, or not.

And dragging the minimap scene… wasn’t even asked about, but would likely be handy. And then there’s spin. Maybe ONLY spin minimap scene IF main scene camera spins (orbits)? sigh. SO much to think about.

The renderTargetTexture method… placed onto a parented-to-main-cam plane (non-viewport method) MIGHT be the best way to allow focus, zoom, and drag-on-minimap.

Ouch! My brain still hurts from last night’s posts. :slight_smile:

Wingnut, again thanks. A lot of material to consider.
Read up on the layerMask docs. The notation on declaring the mask in the docs is different than used in the PG example:

Blockquote
var secondCamera = new Babylon.Camera(…);
secondCamera.layerMask = 0x10000000;
scene.activeCameras.push(secondCamera);
Blockquote

Blockquote
mmFreeCam.layerMask = 1;
Blockquote

For my sanity, I put together a quick spreadsheet with the help of an online decimal2binary converter.
Q1:The first code block is binary 1?
The second code block is decimal 1, and the Babylon API converts to binary 1 internally?

image

Q2: I guess this does not work like the z-index property in CSS? Right? Its some type of AND or an OR binary operation?

1 Like

.layerMask = 0x10000000 = decimal 128 (left-most bit of an 8-bit byte)
.layerMask = 0x00000001 = decimal 1 (right-most bit of an 8-bit byte)

layerMask values can be set with binary numbers (such as 0x 00000010) or decimal numbers (such as 3). The 0x part is simply a “signal” to JS… to indicate that a binary number follows. The most important part… is the eight 1’s or 0’s that follow 0x.

This forum is targeted to help with BabylonJS webGL framework, and not for value-setting format-conversions.

The main issue in THIS thread… was to show you OTHER methods (non-two-canvas methods) for making mini-map overhead/radar views. Two-canvas mini-maps CAN cause problems like you listed in your first post.

The only reason we mentioned/saw layerMasks… is for choosing WHICH mesh can be seen in minimap view, and which mesh are hidden (if wanted).

LayerMask values can be set with decimal or binary values. Conversion between the two value-systems… is for webpages that teach such things.

I made a layerMask-teaching playground… once. https://www.babylonjs-playground.com/#11NJQT#25

That is an 8-layer demo. Line 5 sets camera to INITIALLY show all 8 layers (show all mesh - all 8 binary bits set to 1 - like 11111111).

Now notice lines 13, 18, 23, 28, 33, 38, 47 and 67. Eight different mesh, each one set with its OWN layer mask value.

The buttons… when clicked… adjust the CAMERA’s layermask value. As you push the buttons you can see mesh appear/disappear… being “masked” or “unmasked”. Each button-press… changes the CAMERA’S layerMask, not the layerMask values of the mesh. The buttons COULD change the values of the mesh layerMasks… but I chose to use the buttons to change the CAMERA layerMask values.

Ok, enough about layerMasks. Again, main thing: There are other ways (other than 2-canvas methods)… to make minimaps. You have seen many examples in action, now. You choose. Good luck.

(Boy, do we ever need “The Ultimate MiniMap-Making System”, eh? But writing docs about its many features… could make some folks go insane.) :smiley:

1 Like