Here’s a tute showing how to do both dolly zoom and the binocular effect:
# Panda3D dolly zoom and binoculars example [aurilliance 3/3/09]
# This code just shows how to create a 'dolly zoom' effect
# such as the one seen in the opening scene of half-life 2.
# This effect is achieved by simultanously decreasing the
# field of view (FOV) and moving the camera forwards slightly.
#
# It also shows how to use Lerp intervals to create a nice,
# smooth binoculars / weapon scope effect that zooms in on
# what the player is looking at.
import direct.directbase.DirectStart
from pandac.PandaModules import *
from direct.interval.IntervalGlobal import *
from direct.showbase.DirectObject import DirectObject
from direct.gui.OnscreenText import OnscreenText
from direct.task.Task import Task
import sys
# Function to print text to the screen
def genLabelText(text, i):
return OnscreenText(text = text, pos = (-1.3, .95-.05*i), fg=(1,1,1,1), align = TextNode.ALeft, scale = .05, mayChange=1)
class World(DirectObject):
def __init__(self):
# Game state variables and window setup
self.zoomed = 0
self.controls_disabled = 1
self.cam_height = 1.0
p = WindowProperties()
p.setCursorHidden(True)
p.setSize(800, 600)
base.win.requestProperties(p)
# Set the FOV to a wide value and the camera
# slightly forwards (to show the dolly zoom)
base.camLens.setFov(120)
base.camera.setPos(Point3(0,20,self.cam_height))
# Add some text to the screen
genLabelText("Panda3D Dolly Zoom and Binoculars example", 0)
genLabelText("WASD + mouse to look and move, F to use binoculars", 1)
genLabelText("Controls are enabled when the dolly zoom finishes", 2)
# Set up control
self.keyMap = {"left":0, "right":0, "up":0, "down":0, "zoom":0}
self.accept("escape", sys.exit)
self.accept("a", self.setKey, ["left",1])
self.accept("d", self.setKey, ["right",1])
self.accept("w", self.setKey, ["up",1])
self.accept("s", self.setKey, ["down",1])
self.accept("f", self.setKey, ["zoom",1])
self.accept("a-up", self.setKey, ["left",0])
self.accept("d-up", self.setKey, ["right",0])
self.accept("w-up", self.setKey, ["up",0])
self.accept("s-up", self.setKey, ["down",0])
self.accept("f-up", self.setKey, ["zoom",0])
base.disableMouse()
# Load a few models to show off the effect
self.box = loader.loadModel("box")
self.box.reparentTo(render)
self.box.setPos(-2,23,0)
self.smiley = loader.loadModel("smiley")
self.smiley.reparentTo(render)
self.smiley.setPos(2,23,1)
self.teapot = loader.loadModel("teapot")
self.teapot.reparentTo(render)
self.teapot.setPos(0,30,0)
# Add a point light to light things up a bit
plight = PointLight('plight')
plight.setColor(VBase4(1,1,1,1))
plnp = render.attachNewNode(plight)
plnp.setPos(0,0,10)
render.setLight(plnp)
render.setShaderAuto()
# Create and play the dolly zoom effect
# It is set to zoom from FOV 120 to 45, moving the camera 5
# units in 10 seconds. All these parameters can be adjusted
# to create different effects / to suit your taste
dollyZoomer = LerpFunc(self.fovSet, 10, 120, 45, 'easeOut')
camMover = LerpPosInterval(base.camera, 10, Point3(0,15,self.cam_height), Point3(0,20,self.cam_height), blendType='easeOut')
dollySequence = Sequence(Wait(3), Parallel(dollyZoomer, camMover), Func(self.setControls, 0))
dollySequence.start()
# Add the frame task to task list
taskMgr.add(self.frame, "moveFunc")
def setKey(self, key, value):
self.keyMap[key] = value
# Sets whether the keys and mouse are disabled or not
def setControls(self, value):
self.controls_disabled = value
# This function is used (generally by a lerp function) to adjust the FOV
def fovSet(self, t):
base.camLens.setFov(t)
# The frame task
def frame(self, task):
cam_height = 1.0
cam_sensitivity = 0.1
speed = 0.35
strafe_speed = 0.2
# Mouse Control
md = base.win.getPointer(0)
x = md.getX()
y = md.getY()
rotx, roty = 0, 0
if base.win.movePointer(0, 400, 300):
rotx -= (x - 400)*cam_sensitivity
roty -= (y - 300)*cam_sensitivity
if (roty < -80): roty = -80
if (roty > 80): roty = 80
# Exit here if the controls are still disabled,
# we let the above code execute to prevent the player
# moving the mouse before the dolly zoom finishes
if self.controls_disabled:
return Task.cont
base.camera.setHpr(base.camera.getH()+rotx, base.camera.getP()+roty, 0)
forward_dir = base.camera.getNetTransform().getMat().getRow3(1)
strafe_dir = base.camera.getNetTransform().getMat().getRow3(0)
forward_dir.normalize(); strafe_dir.normalize()
forward_dir *= speed; strafe_dir *= strafe_speed
# Key Movement
if self.keyMap["up"]:
base.camera.setPos(base.camera.getPos()+forward_dir)
if self.keyMap["down"]:
base.camera.setPos(base.camera.getPos()-forward_dir)
if self.keyMap["left"]:
base.camera.setPos(base.camera.getPos()-strafe_dir)
if self.keyMap["right"]:
base.camera.setPos(base.camera.getPos()+strafe_dir)
# This handles the binoculars
# It quickly lerps from FOV 45 (assumed to be the initial setting)
# to 13 - the smaller the final value, the more it is 'zoomed in'
if self.keyMap["zoom"]:
if not self.zoomed:
self.zoomed=1
fovZoomer = LerpFunc(self.fovSet, 0.1, 45, 13, 'easeOut', [], "zoomer")
fovZoomer.start()
else:
if self.zoomed:
self.zoomed=0
fovZoomer = LerpFunc(self.fovSet, 0.1, 13, 45, 'easeIn', [], "zoomer")
fovZoomer.start()
return Task.cont
w = World()
run()