How to Fit Camera to Object

How to Fit Camera to Object

I am assuming you are using a perspective camera.

You can set the camera's position, field-of-view, or both.

The following calculation is exact for an object that is a cube, so think in terms of the object's bounding box, aligned to face the camera.

If the camera is centered and viewing the cube head-on, define

dist = distance from the camera to the _closest face_ of the cube

and

height = height of the cube.

If you set the camera field-of-view as follows

fov = 2 * Math.atan( height / ( 2 * dist ) ) * ( 180 / Math.PI ); // in degrees

then the cube height will match the visible height.

At this point, you can back the camera up a bit, or increase the field-of-view a bit.

If the field-of-view is fixed, then use the above equation to solve for the distance.


EDIT: If you want the cube width to match the visible width, let aspect be the aspect ratio of the canvas ( canvas width divided by canvas height ), and set the camera field-of-view like so

fov = 2 * Math.atan( ( width / aspect ) / ( 2 * dist ) ) * ( 180 / Math.PI ); // in degrees

three.js r.69

How to fit object to camera in threejs using OrthographicCamera?

As @gaitat said, with THREE.OrthographicCamera you need to adjust it's frustum dimensions to fit the size of an object you want to zoom in.

Straightforward thing to do would be to use geometry.boundingSphere and set camera top, left, bottom and up based on that. The easier thing to do would be to use camera.zoom to do the work, i.e.

// center camera on the object (ellipse in this case)
var boundingSphere = ellipse.geometry.boundingSphere

// aspect equals window.innerWidth / window.innerHeight
if( aspect > 1.0 )
{
// if view is wider than it is tall, zoom to fit height
camera.zoom = viewHeight / ( boundingSphere.radius * 2 )
}
else
{
// if view is taller than it is wide, zoom to fit width
camera.zoom = viewWidth / ( boundingSphere.radius * 2 )
}

// Don't forget this
camera.updateProjectionMatrix()

This will set the zoom level to be such that object (ellipse in this case) fits exactly your camera's frustum.

However, you will also have to center the camera on the object by either:

  • rotating the camera to point to the boundingSphere center
  • translating the camera so that the boundingSphere center ends up on the camera's frustum axis

Since translating the camera is easier thing to do of the two, and THREE.OrthographicCamera is mostly used to show 2D representation of your scene (i.e. for UI or some other things that take place on a plane parallel to the camera), here is the code to do just that:

camera.position.copy(boundingSphere.center)
// The number here is more or less arbitrary
// as long as all objects that need to be visible
// end up within the frustum
camera.position.z = 15

This assumes that your objects are in some plane parallel to XY plane and that the camera is positioned to look parallel to Z-axis (as it is by default).

Here is codepen that shows small grid and an ellipse in XY plane. On mouse down camera will zoom to the ellipse, and on mouse up it will come back to it's original state:

https://codepen.io/anon/pen/aJEzew

Making an object fit exactly inside the camera frustum in Three.Js

I have not checked your distance calculations, but you looking straight down the z-axis, while the object isn't vertically centered around 0. Putting your camera.y at mesh1_BB.max.y / 2 should fix that.

If you don't want to move your camera, at least point it towards the actual center of the object. In that case, using the (axis aligned) bounding box isn't 100% correct anymore.

Aframe/Three fit to screen - calculate zoom

Fitting an object to the screen by:

  • changing the camera FoV
  • zooming the camera
  • repositioning the camera / object

is quite similar once you understand where the formulas came from.

We'll use this neat image (from this SO thread) as it covers all three topics:

Sample Image

0. What do we want to achieve

We want the object (the longer side of either its width or height) to cover the filmHeight - so it fits the screen.

1. Recalculating the FoV

In this case we do know the focalLength (camera distance from the object) and filmHeight (object width or height). We can calculate fov / 2 thanks to our friend trigonometry:

Tan (fov / 2) = (filmHeight / 2) / focalLength

=>
fov = 2 * ATan ((filmHeight / 2)) / focalLength * 180 / PI

<script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
<script>
AFRAME.registerComponent("fit", {
init: function() {
const plane = document.querySelector("a-plane")
const distance = this.el.object3D.position.distanceTo(plane.object3D.position)
var height = plane.getAttribute("geometry").height
var newFov = 2 * Math.atan((height / 2) / distance) * (180 / Math.PI); // in degrees
this.el.sceneEl.camera.fov = newFov
}
})
</script>
<a-scene>
<a-plane position="0 1.6 -2" material="src: https://i.imgur.com/wjobVTN.jpg"></a-plane>
<a-camera position="0 1.6 0" fit></a-camera>
</a-scene>

Calculate camera zoom required for object to fit in screen height

I am doing the following which is based on the boundingSphere radius:

geometry.computeBoundingSphere();
radius = geometry.boundingSphere.radius;
distanceFactor = Math.abs( aspect * radius / Math.sin( fov/2 );

This is based on this stuff right here and I hope i interpreted it the right way:
http://www.flipcode.com/forums/thread/4172

This distanceFactor is the factor you need to move the camera along its viewing direction to fit it correctly. At the moment i am not sure if it is by height or width but maybe it helps you figure it out. :)

How to select an object and move camera into to another position?

You basically solve this problem in two steps:

First, you have to make 3D objects selectable which can be done via raycasting. There are many official examples that demonstrate 3D interaction based on raycasting, for example:

https://threejs.org/examples/webgl_interactive_cubes

If you know that a certain 3D object was clicked, you animate the camera from its current position to a defined target position. The possible target positions can be defined prior or you compute the in some way on the fly based on the object's bounding volume and the current camera position. The actual animation can be done in many ways. One approach is using a tweening engine like tween.js. Check out the following example to see how it is used together with three.js:

https://threejs.org/examples/css3d_periodictable



Related Topics



Leave a reply



Submit