Setting radius on ArcRotateCamera manually behaves strangely in regards to inertia

Hello Babylon folks,

I’m trying some strange camera gymnastics, will try my best to explain my scenario.

For a project I’m working on, I have a bunch of planes on top of each other, every plane being a lot larger than the one underneath. Imagine having a way to visualize solar system scales, then zoom out to galaxy scales, then cluster scales and so on.

Because using linear scale to zoom out would end up in massive numbers, I’m planning to do some camera magic, which basically means, when you zoom out, if camera radius is above a given radius, I set the radius back to 1, and then scale the plane down to “fake” the same size. Basically, we move the camera closer to a smaller object, which should translate in the users seeing the same thing (no weird flashes hopefully).

If we use default camera inertia, and updating the radius down, causes the inertialRadiusOffset to have a negative value based on how fast the user scrolls using the wheel.

In the playground, if not setting the inertialRadiusOffset at 0 (which is not ideal since it actually stops the camera scrolling when switching between radii), we notice a very big jump in radius, and it doesn’t keep the expected set radius.

Any ideas how I could work around this to make a smooth transition? And why would the jumping behavior be so large when leaving the inertialRadiusOffset as default?

You can find a playground here: Babylon.js Playground, zooming out above the radius threshold would make the objects “jump” instead of a smooth transition.

Hello !

I see two problems in your implementation :


if(camera.radius > threshold) {
    parent.scaling = new BABYLON.Vector3(1 / scale, 1 / scale, 1 / scale);
    camera.radius = minRadius;
    // etc...
}

You scale down by 100 (scale)
But you don’t scale down camera radius by 100
You do camera.radius = minRadius like if camera.radius where EQUAL to threshold while it’s just gone above (might be 1050 for example…) so there must be a jump since ratio (1/100) it not followed by camera radius

So you should replace by this :

if(camera.radius > threshold) {
    parent.scaling.scaleInPlace(1./scale);
    camera.radius /= scale;
    // etc
}

The default ArcRotateCamera behavior for radius is adding/subtracting some delta (which I agree is not ideal, that’s by the way the reason why radius can go negative, which is non sense)

If you want to conserve the same “zoom / unzoom speed”, while changing the radius, you should customize the wheel behavior so that it’s multiplicative, and not additive :

camera.radius *= 1.0+event.deltaY/3000.0;

One last thing :
Your solution of scaling up and down the scene, in order not to reach crazy camera radius is OK (that way you won’t have zFar and zNear issue with depth, etc, etc…)
But even simpler would be to get rid of all thresholds, get rid of camera radius, and just adjust the main scene scaling

[EDIT]
Here is an example, no threshold, zooming and unzooming from 0.001 to 10 000.0 :

2 Likes

Thank you for the fast reply and great suggestion! It seems this could solve the issues I currently have (even if I kinda liked the inertia behavior of the radius implemented by default, feels more natural to scroll, but I can investigate how to implement something similar in the event handler).

But even simpler would be to get rid of all thresholds, get rid of camera radius, and just adjust the main scene scaling

How would the main scene scaling be achieved? Not sure what this refers to exactly…

I just edited my answer while you were replying :slight_smile:

1 Like