Cameras and Views
Pyglet provides camera scopes in pyglet.window.camera for 2D and 3D rendering.
For common 2D workflows, use Camera2D. By default, the
window is created with a 2D camera.
Default camera behavior
Every window has a default camera at pyglet.window.Window.default_camera.
The projection, view,
and viewport properties proxy directly to it.
The default camera is initialized with the window context creation and applies itself automatically.
Creating a camera
Create cameras from a window, and optionally configure scroll/zoom behavior:
window = pyglet.window.Window()
world_camera = pyglet.window.camera.Camera2D(
window,
scroll_speed=5,
min_zoom=1,
max_zoom=4,
)
gui_camera = pyglet.window.camera.Camera2D(window)
world_camera.zoom += 0.25
world_camera.move(1, 0)
world_camera.position = (50, 0)
Creating views
A camera can have multiple views. Views let you scope additional transforms and scissor areas inside one camera.
Use camera.create_view() for additional view scopes. This is useful for parallax
layers, minimaps, and nested local transforms:
window = pyglet.window.Window()
ui_camera = pyglet.window.camera.Camera2D(window)
inherited_view = ui_camera.create_view(inherit=True) # Inherits parent transform chain.
independent_view = ui_camera.create_view(inherit=False) # Parented to camera root view.
Views share the camera’s viewport/projection behavior and can be used anywhere a camera scope is expected.
Views can also be created from other views. For example:
ui_camera = pyglet.window.camera.Camera2D(window)
scroll_box_a = ui_camera.create_view()
scroll_box_b = scroll_box_a.create_view()
If scroll_box_a moves or zooms, scroll_box_b inherits those changes.
Using camera scopes with batches
Cameras can be used to target a specific batch instead of groups:
@window.event
def on_draw():
window.clear()
with world_batch.draw_with_options() as options:
options.camera = world_camera
with gui_batch.draw_with_options() as options:
options.camera = gui_camera
Using camera scopes in groups
Attach camera scopes to groups with Group.set_camera:
world_group = pyglet.graphics.Group(order=0)
world_group.set_camera(world_camera)
ui_group = pyglet.graphics.Group(order=1)
ui_group.set_camera(window.default_camera)
pyglet.sprite.Sprite(world_image, batch=batch, group=world_group)
pyglet.text.Label("HUD", batch=batch, group=ui_group)
Note
Group.set_camera applies camera state at draw entry by calling begin().
It does not call end() during group unsetting.
Viewport
Each camera has a viewport in framebuffer coordinates:
world_camera.viewport = (0, 0, window.width // 2, window.height)
By default, viewport follows the full framebuffer and updates on resize/scale events. Setting a tuple makes viewport explicit, and will no longer update automatically. In those cases you will have to update your viewport coordinates explicitly.
Scissor
Scissor clipping can be set on both cameras and views.
Use set_scissor_area(...) for fixed window-space clipping:
world_camera.set_scissor_area(0, 0, window.width // 2, window.height)
Use set_scissor_area_relative(...) when clipping should move with the
camera/view transform:
moving_panel = ui_camera.create_view(inherit=True)
moving_panel.set_scissor_area_relative(40, 40, 280, 160)
moving_panel.offset_x += 16 # Scissor follows the moved view
When a camera/view is applied through Group.set_camera, pyglet automatically applies
matching scissor state for that group.
For nested views, the effective scissor is the intersection of all scissor areas in the view chain.