How to acheive a dolly zoom effect

For my next animation, I want to throw aDolly Zoom in the works. My problem is, I do not know how to ‘zoom in’ a camera, I always just move it closer to the subject. Can blenders cameras zoom?

Here is a quick example that I knocked up. The cube and quarter sphere in the foreground are parented to the camera so that they stay the same distance from it while the camera moves forward towards the background. I added a quick and dirty DOF to help strengthen the effect.

This seems to work ok for this example, but if there were textures on the walls, or if there were various objects at different intervals down the hallway, this effect would be exposed as a cheap trick.

So, any suggestions?

Select Camera, Select IPO Curve < Camera >Select Lens Chanel, On Frame 1 Put Value 35, On Frame 20 Put Value=60, On Frame 40 Put Value 35 and its now zooooooooooming.

Thankyou, I did not know about the lens setting (smacks his forehead) Didn’t work quite as expected but a bit of tweaking should fix that.

Wow, just had a really quick play with a couple of the other curve options inside camera. I’ve been doing things the hard way.

To get the full effect of a contra-zoom (dolly zoom), it’s best to keep the main subject at the same magnification (scale in image frame) while everything else changes around it:

A Blender contra-zoom

Calculating the magnification needs a proper lens focal length in mm, which the Blender Lens setting is not (last I knew, at least), so the BLenses script might help you some. The movie above was made using BLenses to animate the focal length and camera-to-subject distance. It can also be seen at the bottom of page 2 of the BLenses site.

I’m not exactly certain what you mean by calculating the magnification, but I think it’s possible to achieve this effect without knowing a focal length. All you need is the field of view, which you can easily find (select the camera --> editing buttons --> lens, show in degrees).

The BLenses script is a very nice script, but can imho be a bit of overkill for setting up a dolly zoom (not trying to sound negative about your excellent script chipmasque, you really did some amazing work on it). Below you can find an alternative script, which only does dolly zooms.

To use it:
Animate either the lens value or the location of the camera (for best results use linear interpolation, not bezier)
Select the object you want to focus on (so the object which won’t change in size)
Run the script (alt+P)

And here’s a video with an example result.
http://bartius.crouch2.googlepages.com/dolly_zoom_ss01.png

import Blender
from Blender import *
import bpy
from math import pi, tan, atan

"""
Dolly zoom
Written by Bartius Crouch
How to use:
    Animate either the lens value or the location of the camera
    Select the object you want to focus on (so the object which won't change in size)
    Run this script (alt+P)
"""

# general variables
scn = bpy.data.scenes.active
cam_ob = scn.objects.camera
cam = cam_ob.data
ob = scn.objects.active

def main():
    animated = False
    ipos = []
    # check if the location of the camera is animated
    if cam_ob.ipo:
        if cam_ob.ipo.curves:
            active = []
            for i in cam_ob.ipo.curves:
                if i.name=="LocX" or i.name=="LocY" or i.name=="LocZ":
                    ipos.append(i)
            if len(ipos)&gt;0:
                animated = ["loc",ipos[0].interpolation,ipos[0].extend]
    
    # check if the lens value is animated
    if cam.ipo:
        if cam.ipo[Ipo.CA_LENS]:
            choice = 2
            if animated:
                choice = Draw.PupMenu("Change%t|Lens animation|Location animation")
                if choice == -1:
                    return
            if choice == 2:
                ipos.append(cam.ipo[Ipo.CA_LENS])
                animated = ["lens",ipos[0].interpolation,ipos[0].extend]
    
    # check if at least one parameter is animated
    if not animated:
        Draw.PupMenu("Error%t|Neither the location nor the lens-value of the camera is animated")
        return
    
    # collect keyframes
    frames = []
    for ipo in ipos:
        for bp in ipo.bezierPoints:
            if bp.pt[0] not in frames:
                frames.append(bp.pt[0])
    frames.sort()
    oldframe = Blender.Get('curframe')
    
    # calculate constant width
    fov = cam.angle
    dist = (Mathutils.Vector(ob.loc) - Mathutils.Vector(cam_ob.loc)).length
    width = dist*2*tan(pi*(fov/360))

    # location is already animated, so set up lens animation
    if animated[0] == "loc":
        if cam.ipo:
            cam_ipo = cam.ipo
            cam_ipo[Ipo.CA_LENS] = None
        else:
            cam.ipo = Ipo.New('Camera',"CaIpo")
            cam_ipo = cam.ipo
        curve = cam_ipo.addCurve('Lens')
        for f in frames:
            Blender.Set('curframe',int(f))
            dist = (Mathutils.Vector(ob.loc) - Mathutils.Vector(cam_ob.loc)).length
            fov = (360*atan(width/(2.0*dist)))/pi
            cam.angle = fov
            if fov&gt;172.85 or fov&lt;7.32:
                message = "Needed zoom is beyond the capability of Blender's camera%t|The ipo that was created doesn't create a correct dolly zoom"
            else:
                message = "Success%t|Created correct lens-ipo to set up dolly zoom"
            curve.append((float(f),cam.lens))
        curve.interpolation = animated[1]
        curve.extend = animated[2]
    
    # lens is already animated, so set up location animation
    if animated[0] == "lens":
        if cam_ob.ipo:
            cam_ob_ipo = cam_ob.ipo
            cam_ob_ipo[Ipo.OB_LOCX] = None
            cam_ob_ipo[Ipo.OB_LOCY] = None
            cam_ob_ipo[Ipo.OB_LOCZ] = None
        else:
            cam_ob.ipo = Ipo.New('Object',"ObIpo")
            cam_ob_ipo = cam_ob.ipo
        curveX = cam_ob_ipo.addCurve('LocX')
        curveY = cam_ob_ipo.addCurve('LocY')
        curveZ = cam_ob_ipo.addCurve('LocZ')
        ori = Mathutils.Vector(ob.loc)
        for f in frames:
            Blender.Set('curframe',int(f))
            dist = width/(2.0*tan(pi*(cam.angle/360.0)))
            cur_dist = Mathutils.Vector(cam_ob.loc)-ori
            cur_dist.length = dist
            loc = ori+cur_dist
            curveX.append((float(f),loc[0]))
            curveY.append((float(f),loc[1]))
            curveZ.append((float(f),loc[2]))
        curveX.interpolation = animated[1]
        curveX.extend = animated[2]
        curveY.interpolation = animated[1]
        curveY.extend = animated[2]
        curveZ.interpolation = animated[1]
        curveZ.extend = animated[2]
        message = "Success%t|Created location-ipo to set up dolly zoom"
    
    # reset to the old frame and communicate what happened
    Blender.Set('curframe',oldframe)
    if message:
        Draw.PupMenu(message)


# check if camera and focus object are present
if cam_ob == ob:
    Draw.PupMenu("Error%t|Select an object to focus on (camera can't focus on itself)")
elif cam_ob and ob:
    main()
elif cam_ob:
    Draw.PupMenu("Error%t|No active object, select an object to focus on")
else:
    Draw.PupMenu("Error%t|Couldn't find an active camera")

Yep, it can be done many ways, and you’re right, for just a contra-zoom, BLenses offers more than is necessary – the script can be used in many different ways, so it’s bound to be more complex than a single-function script. But it can help a lot if you want to calc some of the effects beforehand rather than tweaking 'til it looks right.

Magnification is basically the ratio of subject size to image size “on film.” In a camera, if the image is 10mm tall and the subject is 1 m tall then that’s a magnification of .01. In common terms that means the size of the subject in the image frame. To really push the contra-zoom effect it’s usually best to have the subject look as if it’s completely stationary and everything else is changing around it, like space stretching. But both a zoom and a dolly change the magnification, so with a contra-zoom, you’re using one against the other to maintain the magnification as a constant. The result is a change in field of view (as you mentioned) that also changes the perspective characteristics of the scene and that gives you the contra-zoom effect.

With an accurate focal length you can pre-calculate a lot of the animation settings (mainly camera position and focal length) and save some time in getting the effect at its best.

Or not :smiley:

Now I see what you mean by needing the magnification, thanks for the additional info.
And you’re right of course, BLenses can be used for many more things than just this effect.

Thanks Crouch for sharing the script. Very usefull.