How do i do dolly/Hitchcock/Vertigo zoom using perspective camera?

as the camera zooms in the fov should goes in the opposite direction.

using lerpVectors i can zoom with orbitcontrols ,
and
with orbitcontrols.getDistance() i can get the distance between camera and target

how do i calculate the correct fov change ?

There’s a formula on the wiki page you linked:

distance = \frac{width}{2 \tan (\frac{1}{2} * FOV)}

There are also many results if you search for “calculate fov for hitchcock zoom”. For example, this page gives a code sample for Unity which you can adapt for three.js.

2 Likes

oh the unity example came in handy :+1: :+1: :+1:

here’s a pen https://codepen.io/optimus007-the-looper/pen/porYyER

how can i auto set the width, based on current camera position ?

1 Like

current snippet

gui.add(camera,'fov',1,180,1).onChange((v)=>{
    camera.updateProjectionMatrix()
    const width=1
    const fov=v
    const distance = width / (2 * Math.tan(THREE.MathUtils.degToRad(fov * 0.5)));

	const lerpDist = distance / controls.getDistance()
	
	camera.position.lerpVectors(controls.target, camera.position, lerpDist)

  })

You could try this - put in the distance of your object (in world space) to the camera as the z-depth to get the width of the scene at that distance. Then use that width in the calculation.

visibleWidthAtZDepth(controller.getDistance(), camera)

gives huge values , inverse of this also did not work.

updated the pen with width slider to see its effects

https://codepen.io/optimus007-the-looper/pen/porYyER (same pen as above)

You should get the distance between the camera and the mesh, not the camera and the target.
Actually I would recommend removing the controls from the scene while you are working on this, and if you do include them, disable them while doing the zoom. Using OrbitControls while doing camera animation is tricky.

You can get the camera distance to the mesh like this:

const a = new Vector3();

mesh.getWorldPosition(a);

const distance = camera.position.distanceTo(a);

Although in this case, you can also just leave the mesh at (0,0,0), then do:

camera.position.set(0, 0, 1);

Then the z-depth will be 1.

2 Likes

right now the target and mesh is at 0,0,0 so that simplifies stuff ,

i kept orbitcontrols cause its easier to handle framing & i’ll put target at the center of mesh bounding box before starting vzoom

so width is the unknown factor , i’ll try to setup a bounding box size * distance from target * constant factor as default width …once its in the correct ballpark a gui slider can used to add or remove a bit of width.