ArcRotateCamera.zoomOn is not working as expected

ArcRotateCamera.zoomOn is not working as expected.

If I have a large viewport, I see that there is still a bit more to be zoomed there.
If I reduce the viewport, and call the function again, nothing updates and the object doesn’t fit.

I want to use this to automatically zoom the camera in the initial load to fit the viewport.

https://playground.babylonjs.com/#IYPUNY

adding @Cedric to check :wink:

I’m taking a look.

@wang.minion

zoomOn function places the cameras so the distance to the bounding box center of the mesh is large enough to not have the camera in the bounding box.
to make it short, it places the camera, so it’s far enough of the bounding box.

It doesn’t take into account the projected bounding box, the camera fov or the viewport size.

Thanks for letting me know about that.
In that case, if I want to zoom in/out automatically the camera to fit the current viewing bounding box, what could I do?
Do I have to manually calculate the ArcRotateCamera’s alpha, beta, radius?

Looking forward to your solutions.

alpha/beta can be updated just by setting the target (center of bounding box).
The real deal is to set the distance to the center that will give the projected bounding box to be entierly framed by the viewport.
as usual depending on the quality, this will need some work.
if you assume the bounding sphere is enough, then you can compute the distance so the projected disk is framed by the viewport.
for the viewport, you only need the ratio width/height I think. the closer to 1, the more you can zoom.
and use the fov value from the camera aswell.

@Cedric, quick question around the fov. So what I have found out is that fov is the dfov.
Please check the article I have sent below.
http://chrisjones.id.au/FOV/fovtext.htm

So what I did was that I set the fovMode of ArcRotateCamera as FIXED.

defaultCamera.fovMode = ArcRotateCamera.FOVMODE_HORIZONTAL_FIXED

And calculated the hfov and vfov from dfov and based on that, I calculated the radius.
Is this the right choice?
It seems working but still shows some paddings.

Please let me know if that makes sense.

export function zoomOnCamera (mesh: Mesh, camera: ArcRotateCamera) {
  camera.fovMode = ArcRotateCamera.FOVMODE_HORIZONTAL_FIXED

  const { max, min } = mesh.getHierarchyBoundingVectors(true, x => x.isVisible)
  const boundingInfo = new BoundingInfo(min, max)
  const bbox = boundingInfo.boundingBox
  const ratio = camera.getScene().getEngine().getAspectRatio(camera, true)

  const dfov = camera.fov

  const vfov = Math.atan(Math.tan(dfov / 2.0) * Math.cos(Math.atan(ratio))) * 2.0
  const vtheta = vfov / 2
  const vr = (bbox.maximum._y - bbox.minimum._y) / 2
  const vdistance = vr / Math.sin(vtheta)

  const hfov = Math.atan(Math.tan(dfov / 2.0) * Math.sin(Math.atan(ratio))) * 2.0
  const htheta = hfov / 2
  const hr = (bbox.maximum._x - bbox.minimum._x) / 2
  const hdistance = hr / Math.sin(htheta)

  camera.radius = Math.max(hdistance, vdistance)
}

I don’t think vr and hr are correct. it’s computed with world coordinates but your camera can be oriented so x is not on the camera right.

So

  • Regarding fov of ArcRotate Camera as a dfov is the right decision?
  • And you mean vr and hr calculations are not proper?

depending on the camera fovmode (vertical or horizontal) I would compute the other value instead of using a dfov. https://www.reddit.com/r/Planetside/comments/1xl1z5/brief_table_for_calculating_fieldofview_vertical/

vr and hr should use the camera orientation. Or, for a first test, compute a maximum radius and use it for both.

Great. Thanks for this.