Engine.resize() on html element size change

Hi there,

I’m working on a project where we have our canvas on the page, we’ve implemented some interaction with a few html elements.
Based on the interaction from the user with the 3D scene, various elements show/hide, and also our canvas should resize

An illustrative example (not with the 3D canvas but just a placeholder img):


As you can see it’s important to keep the center of the scene centered in the div.
That’s why it’s not an option to just slide a sidepanel over 50% of the canvas.

For this the engine.resize() doesn’t seem to work, as it’s usually used to resize when your window changes:

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

I can’t seem to find a good example or solution how to do this when you have a div that’s changing width.

In the end I tried this:
But it’s not fluent at all and not really an option.

  const cnvs = document.getElementById('cnvs') as HTMLElement
  const ro = new ResizeObserver((entries) => {
    engine.resize()
  })

  engine.runRenderLoop(() => {
    scene.render()
    ro.observe(cnvs)
  })

Any help would be very much appreciated!

Thanks
Pieter

2 Likes

May be not the correct approach. In the end, the scene renders from a camera.
I would likely use camera.targetScreenOffset with the offset of the open panel to keep with the centered view of the scene minus panel size. On panel close, zero it.

1 Like

engine.resize() should be called when the canvas size has changed. I believe you are already doing that. And it does seem to work, at last from what I’m seeing. The scene is still centered. I assume you want the entire model to be displayed?

About the resize observer, there is no need to call observe on each frame, only once. This is probably hurting performance (though I’m not sure if it is a no-op if you choose to observe the same element every time). It’s a great solution, and should work the way you described. What is the issue with this approach?

Thanks to the both of you for your feedback.
The camera.targetScreenOffset is a valid solution however if possible I would like the canvas to handle the centering of the camera by using the canvas size. If there is really no other solution this could be still the way to go.

However this is what I’d like to accomplish:

The canvas would resize with a transition to a percentage 50-70% of the full width. And this would be done with a css transition property so everything transitions smoothly.

Therefore the engine.resize() would have to be constantly updated during these transitions, right? This was the reason why I was calling the resize observer within the renderloop.

When doing so I get the following:

Thanks
Pieter

Hey there @Pieter_van_Stee just checking in if you need any more help with this :grin:

Hi and thanks for getting back to me on this issue.

I would like to know how this could be done.
For now I managed to solve this by just keeping the 100% width, and sliding it to the left for 50% while the right sidepanel transitions from 0% width to 50% width.

It looks the same and works in this instance.
However like I said I’d like to know how it could be done to transition the canvas width from 100% > 50% for example with a transition over 1000ms let’s say without changing the browser window width.

Thanks!

Would something like this: Animate canvas size change | Babylon.js Playground (babylonjs.com) work for your case? :thinking:

I’m confirming that resize doesn’t work as expected. i have small canvas on the page and want to create logic when i click on it, it becomes bigger(like almost full page) i’m using resize but it does nothing. the scene is just becomes bigger without changing its resolution. the strange thing here is when i click on it again it changes(!) resolution. I wanted to create question about it later when i will try to do something with this and just saw this question

Could be a workaround, however it looks a bit less smooth than pure css.
So for now I would omit having to use this feature, but If I had to, I 'll try your suggestion.

Thanks!
Pieter

What do you mean by “changing the resolution”? It’s a bit hard to understand the expected behavior from just this description.

I gave it a try with CSS transitions and your approach to call resize on render loop: Babylon Template (carolhmj.github.io) :thinking:

Great, this would be a smooth result :+1: thanks!
Are you, and how are you triggering a re-render on each changed css width?

Thanks for this example!
Pieter

I checked again and looks like i found my problem.
My issue is that width/height of canvas is not the same as width and height of css style which has canvas.
I used style to change size of canvas. In this case block becomes bigger but width and height of canvas is not changed. when babylon resize is occured it use width and size of canvas and because they are small i get such picture (that’s what i meant it’s not changing resolution)


when such picture is expected

Looks like my solution is to change width and height of canvas not css style of it.
Thanks

1 Like

I had to go with engine.resize in the render loop function, or else the engine wouldn’t resize properly Babylon Template

1 Like

Ok, thanks.
Is this bad for the performance?
Would it be better to wrap this in an if statement to turn the engine.resize on/off?

Thanks

It will have some effect on performance, I tested with a few different scenes and while the transition occurred a few frames were dropped. But it wasn’t an unreasonable amount, and the only case where I saw very long frames was in a scene that was already quite heavy by itself. So I think if your scene isn’t very very heavy it will be fine. The if statement won’t be necessary as the setSize function already checks if the size has changed before running: Babylon.js/thinEngine.ts at f610f68b036265c9e0b50ddb27428c1370ec468a · BabylonJS/Babylon.js · GitHub

Hey, @Pieter_van_Stee.
I’ve read the thread and I was wondering that maybe you can get it done another way.
Instead of calling the engine.resize() maybe you can just slide the right section over the canvas and move the camera accordingly?
Eg. if the right section is 50% width of the window then you should move the camera 25% to the left.
That way you don’t need to deal with re-rendering at all.

Cheers,
Jakub

Indeed you’re right.
At the moment I have set it up like this and works perfectly in this case.
However I wanted to know for when I come across a case where I can’t cover the canvas and have to resize it. But for now I’ll keep it like this cause not having to keep resizing the scene will improve performance I guess.

Thanks for the tip!

2 Likes

Thanks, interesting to know!

1 Like

Just wanted to add we do have support for zoom-changes in your browser:

Babylon.js Playground (babylonjs.com)

When you create the engine you can set the 4th variable to be true - auto-adjust the hardware scaling ratio according to your zoom level.

4 Likes