Camera Control

Every scene3d scene gives you a free-roaming camera by default — click and drag to orbit, scroll to zoom. But sometimes you want to place the camera exactly where it should be: a bird’s-eye view, a close-up of one object, or a camera that tracks a moving character.

scene.camera gives you full control over where the camera sits, what it looks at, and whether it should follow a moving mesh.

Open In Jupyter K-12

Placing the Camera — set_position and look_at

By default the camera starts behind and above the scene, pointed at the origin. set_position(x, y, z) teleports it to any world coordinate you choose. look_at() then swivels it to face a mesh or a point in space.

scene.camera.set_position(0, 14, 0)   # directly above the scene
scene.camera.look_at(0, 0, 0)         # looking straight down at the origin

scene.camera.set_position(8, 4, -8)   # high and to the side
scene.camera.look_at(box)             # pointing at a specific mesh

The cell below uses a bird’s-eye view. Run it, then try orbiting with the mouse — you can still move the camera freely after any set_position call.

import scene3d

scene = scene3d.Scene()
scene.set_sky('#1a1a2e')
scene.set_ground(length=14, width=14)

for x, color in [(-3, '#e94560'), (0, '#f5a623'), (3, '#44cc88')]:
  s = scene3d.Shapes.Sphere(diameter=1.2, segments=16)
  s.set_color(color)
  s.set_position(x, 0.6, 0)
  scene.add(s)

# Bird's-eye view — camera directly above, looking straight down
scene.camera.set_position(0, 14, 0).look_at(0, 0, 0)

Camera Coordinates

The camera lives in the same 3D world as every shape. Its position uses the same axes:

       y (up)
       |
       |   z (toward camera, away from scene)
       |  /
       | /
       +---------- x (right)
Position What you see
(0, 14, 0) Straight down from above
(0, 5, -15) Default-like — behind and slightly above
(15, 2, 0) Side view from the right
(0, 1, -3) Ground level, close up

Methods can be chained because each one returns scene.camera:

scene.camera.set_position(8, 6, -8).look_at(box)

{ “question_type”: “multiple_choice”, “question”: “scene.camera.set_position(0, 14, 0).look_at(0, 0, 0) places the camera:”, “options”: [ { “key”: “a”, “text”: “In front of the scene at eye level” }, { “key”: “b”, “text”: “Directly above the scene, looking down” }, { “key”: “c”, “text”: “Behind the scene, looking forward” }, { “key”: “d”, “text”: “To the right of the scene” } ], “answer”: “b”, “submitted_answer”: “” }

set_distance — Zooming In and Out

set_distance() controls how far the camera sits from its target — a fast way to zoom without repositioning the camera entirely.

scene.camera.set_distance(5)    # close-up
scene.camera.set_distance(30)   # wide establishing shot

Use the sliders to explore different heights and distances and see how they change the feel of the scene.

import scene3d

CAMERA_HEIGHT   =  6 #@param {type:"slider", min:2, max:16, step:1}
CAMERA_DISTANCE = 12 #@param {type:"slider", min:4, max:30, step:2}

scene = scene3d.Scene()
scene.set_sky('#0f3460')
scene.set_ground(length=14, width=14)

box = scene3d.Shapes.Box(width=1.5, height=1.5, depth=1.5)
box.set_color('#e94560')
box.set_position(-2, 0.75, 0)
scene.add(box)

sphere = scene3d.Shapes.Sphere(diameter=1.4, segments=16)
sphere.set_color('#4488ff')
sphere.set_position(2, 0.7, 0)
scene.add(sphere)

scene.camera.set_position(0, CAMERA_HEIGHT, -CAMERA_DISTANCE).look_at(0, 0, 0)

{ “question_type”: “true_false”, “question”: “scene.camera.set_distance(5) moves the camera closer to its current target.”, “answer”: “True”, “submitted_answer”: “” }

follow — Tracking a Moving Object

scene.camera.follow(mesh) makes the camera automatically track a mesh every frame. As the mesh moves, the camera moves with it to keep it in view.

scene.camera.follow(ball)              # track the ball
scene.camera.follow(ball, distance=12) # track at a specific distance
scene.camera.follow(None)              # stop following

The scene below has a bouncing ball that travels left and right. The camera follows it the whole way. Click Stop (■) when you’re done.

import scene3d
import math

scene = scene3d.Scene()
scene.set_sky('#0f3460')
scene.set_ground(length=30, width=14)

ball = scene3d.Shapes.Sphere(diameter=1, segments=16)
ball.set_color('#e94560')
ball.set_position(0, 0.5, 0)
scene.add(ball)

# Static markers for the ball to pass
for x in [-8, -4, 0, 4, 8]:
  b = scene3d.Shapes.Box(width=0.8, height=0.8, depth=0.8)
  b.set_color('#4488ff')
  b.set_position(x, 0.4, 3)
  scene.add(b)

# Camera tracks the ball from behind
scene.camera.follow(ball, distance=10)

t = 0.0

@scene.on_frame
def animate(dt):
  global t
  t += dt
  x = math.sin(t * 0.8) * 10
  y = 0.5 + abs(math.sin(t * 3)) * 2
  ball.set_position(x, y, 0)

scene.run()

{ “question_type”: “multiple_choice”, “question”: “What does scene.camera.follow(None) do?”, “options”: [ { “key”: “a”, “text”: “Pauses the animation” }, { “key”: “b”, “text”: “Makes the camera look at the origin” }, { “key”: “c”, “text”: “Stops the camera from tracking the mesh it was following” }, { “key”: “d”, “text”: “Removes the camera from the scene” } ], “answer”: “c”, “submitted_answer”: “” }

Method Chaining and reset()

Every camera method returns scene.camera, so you can chain calls on one line:

# Three separate calls:
scene.camera.set_position(8, 6, -8)
scene.camera.set_distance(14)
scene.camera.look_at(box)

# Equivalent chain:
scene.camera.set_position(8, 6, -8).set_distance(14).look_at(box)

scene.camera.reset() returns the camera to the default start position and angle — useful when you want a clean slate or need to undo experimental positioning.

The demo below uses a chain to set a dramatic low-angle view of a single object.

import scene3d

scene = scene3d.Scene()
scene.set_sky('#1a1a2e')
scene.set_ground(length=14, width=14)

box = scene3d.Shapes.Box(width=2, height=2, depth=2)
box.set_material(scene3d.Material.Marble.Gray)
box.set_position(0, 1, 0)
scene.add(box)

# Low angle, close in, pointing at the box — all in one chain
scene.camera.set_position(6, 1.5, -6).set_distance(10).look_at(box)

# Uncomment the line below and re-run to jump back to the default view:
# scene.camera.reset()

{ “question_type”: “multiple_choice”, “question”: “What does scene.camera.reset() do?”, “options”: [ { “key”: “a”, “text”: “Deletes all camera settings permanently” }, { “key”: “b”, “text”: “Returns the camera to the default start position and angle” }, { “key”: “c”, “text”: “Freezes the camera so the mouse no longer works” }, { “key”: “d”, “text”: “Resets the entire scene, including all shapes” } ], “answer”: “b”, “submitted_answer”: “” }

Try It Yourself

Use the sliders to adjust the camera height and distance, and toggle Follow Ball to switch between a fixed viewpoint and a tracking camera. Watch how dramatically the same scene feels different from different angles.

import scene3d
import math

CAMERA_HEIGHT   =  8 #@param {type:"slider", min:2, max:20, step:1}
CAMERA_DISTANCE = 14 #@param {type:"slider", min:5, max:30, step:1}
FOLLOW_BALL     = True #@param {type:"boolean"}

scene = scene3d.Scene()
scene.set_sky('#0f3460')
scene.set_ground(length=30, width=14)

ball = scene3d.Shapes.Sphere(diameter=1, segments=16)
ball.set_color('#e94560')
ball.set_position(0, 0.5, 0)
scene.add(ball)

for x, color in [(-8, '#44cc88'), (-4, '#f5a623'), (4, '#f5a623'), (8, '#44cc88')]:
  b = scene3d.Shapes.Box(width=1, height=1, depth=1)
  b.set_color(color)
  b.set_position(x, 0.5, 3)
  scene.add(b)

if FOLLOW_BALL:
  scene.camera.follow(ball, distance=CAMERA_DISTANCE)
else:
  scene.camera.set_position(0, CAMERA_HEIGHT, -CAMERA_DISTANCE).look_at(0, 0, 0)

t = 0.0

@scene.on_frame
def animate(dt):
  global t
  t += dt
  x = math.sin(t * 0.8) * 10
  y = 0.5 + abs(math.sin(t * 3)) * 2
  ball.set_position(x, y, 0)

scene.run()

Think about a 3D scene or game you’d like to build — a race, a platformer, a tour of a building.

How would the camera position change the feel of the experience? Would a fixed overhead view, a close follow-cam, or a wide establishing shot work best? Describe how you’d use set_position, look_at, and follow to create that effect.