PyBevy is in an early and experimental stage. The API is incomplete, subject to breaking changes without notice, and you should expect bugs. Many features are still under development.
Camera Plugins
Add fly and orbit cameras to your 3D scenes with zero setup.
Introduction
Navigating 3D scenes is tedious to implement from scratch. pybevy ships two
camera plugins that handle all the input logic for you:
- FlyCameraPlugin: Free-flying first-person camera (WASD + mouse look).
- OrbitCameraPlugin: Orbit around a target point (click-drag + scroll zoom).
Just add the plugin and attach the component to your camera entity.
from pybevy.prelude import *
from pybevy.plugins import FlyCameraPlugin, FlyCamera, OrbitCameraPlugin, OrbitCameraFly Camera
The fly camera moves freely through the scene. Hold right mouse button to look around, and use WASD (or arrow keys) to move. Q/E moves down/up, and Shift sprints.
You can customize speed and sensitivity via the FlyCamera component fields.
def setup_fly_camera(commands: Commands, meshes: ResMut[Assets[Mesh]], materials: ResMut[Assets[StandardMaterial]]):
# Spawn the camera with the FlyCamera component
commands.spawn(
Camera3d(),
Transform.from_xyz(0.0, 5.0, 15.0).looking_at(Vec3.ZERO, Vec3.Y),
FlyCamera(move_speed=15.0, sprint_multiplier=3.0),
)
# A simple scene to fly around
commands.spawn(
Mesh3d(meshes.add(Plane3d(Vec3.Y, Vec2(50.0, 50.0)))),
MeshMaterial3d(materials.add(Color.srgb(0.3, 0.5, 0.3))),
)
for i in range(5):
commands.spawn(
Mesh3d(meshes.add(Cuboid.from_length(2.0))),
MeshMaterial3d(materials.add(Color.srgb(0.2 + i * 0.15, 0.3, 0.8))),
Transform.from_xyz(i * 4.0 - 8.0, 1.0, 0.0),
)
commands.spawn(
DirectionalLight(illuminance=5000.0),
Transform.IDENTITY.looking_at(Vec3(-1.0, -1.0, -1.0), Vec3.Y),
)Orbit Camera
The orbit camera rotates around a target point. Left-click drag rotates, Shift + left-click drag pans, and scroll wheel zooms.
def setup_orbit_camera(commands: Commands, meshes: ResMut[Assets[Mesh]], materials: ResMut[Assets[StandardMaterial]]):
# Spawn camera with OrbitCamera component
commands.spawn(
Camera3d(),
Transform.from_xyz(0.0, 10.0, 20.0).looking_at(Vec3.ZERO, Vec3.Y),
OrbitCamera(
distance=25.0,
yaw=0.0,
pitch=0.4,
target=Vec3.ZERO,
zoom_sensitivity=0.15,
),
)
# Scene to orbit around
commands.spawn(
Mesh3d(meshes.add(Plane3d(Vec3.Y, Vec2(50.0, 50.0)))),
MeshMaterial3d(materials.add(Color.srgb(0.3, 0.5, 0.3))),
)
commands.spawn(
Mesh3d(meshes.add(Cuboid.from_length(3.0))),
MeshMaterial3d(materials.add(Color.srgb(0.8, 0.3, 0.2))),
Transform.from_xyz(0.0, 1.5, 0.0),
)
commands.spawn(
DirectionalLight(illuminance=5000.0),
Transform.IDENTITY.looking_at(Vec3(-1.0, -1.0, -1.0), Vec3.Y),
)Running the App
Choose one of the two setups below. Both plugins can coexist, but you'll typically want one camera controller per camera entity.
This example uses the orbit camera. Switch setup_orbit_camera to
setup_fly_camera and OrbitCameraPlugin to FlyCameraPlugin to try the other.
@entrypoint
def main(app: App) -> App:
return (
app
.add_plugins(DefaultPlugins)
.add_plugins(OrbitCameraPlugin())
.add_systems(Startup, setup_orbit_camera)
)
if __name__ == "__main__":
main().run()