No problem! In hindsight, the math was simpler than I thought it would be. Hopefully, I didn’t make any more oversights on the latest version .
And there’s no need to rush the implementation on my behalf. I built a simple wrapper of ArcRotateCamera implementing this logic for my own use. Though, it will be nice to use all the playground examples with a silky smooth camera soon!
Thank you for all your help and I’m looking forward to having this solved for everyone.
Hey! For back-compat reasons we need to ensure the public this.speed is still used when calculating inertial limit. So we are proposing the following Camera inertia fixed | Babylon.js Playground
And the PR is updated as well. If you can test / ensure it works on your device, I can publish PR Thank you!
That said, your playground’s math does track with my former posts. However, I did have to decrease the constant from 0.001 to 0.0001, or else it cuts off too early. Since you’re using Epsilon in the PR, I’m not sure what the cleanest fix is. Do you just want to divide it by 10?
In my last playground, I declared different constants for each ‘purpose’ ahead of time. The idea was that the best cutoff for rotational inertia is probably different from the best one for positional inertia (since they are different units: radians and meters).
My somewhat arbitrary cutoff for rotational inertia in that playground was 1 / 250 of a radian per second. Or in other words, if inertia causes the camera to move slower than 0.004 radians per second, it should stop the inertia.
The rotational constant is defined like this:
const InertiaRotationNeededPerMillisecond = (2 * Math.PI) / 250 / 1000;
// 1 / 250 radians per second in milliseconds
The positional constant is defined like this (though I didn’t dial it in so it’s just a copy-paste with the unit replaced):
const InertiaPanNeededPerMillisecond = 1 / 250 / 1000;
// 1 / 250 'meters' per second in milliseconds
Putting them into separate constants lets us use a more precise cutoff for each. While I didn’t tune them, you can at least see that a different unit is used for each (1 radian and 1 meter) But, perhaps this is overkill when shrinking the shared epsilon suffices.
You can see that the result differs here, even when the units are related 5000 meters = 5 kilometers. The easiest way to fix this is by converting to the same unit:
This process can be applied to the camera’s rotation too, by converting it from a radian to a percentage:
Math.abs(this.cameraRotation.x) / (2 * Math.PI)
Now it represents the number of rotations similar to how Math.abs(this.cameraDirection.x) represents the number of meters. I think this would make comparisons with rotation and position more standardized.
All of this math has been put together in this playground:
Edit: I still think two distinct cutoffs work better, but if only one is allowed then converting the distance unit and rotation unit into a percentage makes choosing the cutoff easier (“It shall be 1% of the rotation unit and 1% of the distance unit” vs “It shall be 0.01 rotation units and 0.01 distance units”). Maybe someone more clever than me can weigh in.
As long as the inertia in radians / delta time is checked against 0.000001 or below I’ll be happy (as in my testing that is small enough to avoid problems).
Hey @reedsyllas thank you again for the super detailed investigation / suggestions! It is very much appreciated and we will take this into account as we build the new camera input system mentioned above.
We discussed internally and because we are planning on revamping our camera input system, we’d like to avoid making any changes that may alter existing behavior. So rather than changing our calculation internally we are exposing _panningEpsilon and _rotationEpsilon that you may override per-frame as needed (in the beforeRender observable).
This looks like a good compromise! It’s probably the most versatile solution too (until the awesome revamp). PR looks good. Once it is merged, I’ll work on creating a playground that dynamically sets the epsilons with respect to delta time for anyone else wanting to use it in the short-term.
Regarding the investigation: thank you for the quick responses and good work! There’s been a lot of back and forth and I appreciate you (& the team) reading through my babbling. Thank you.