Combine simple building blocks to create smooth cameras: first-person, chase, orbit, look-at, you name it!

Overview

🎥 dolly

Combine simple building blocks to create smooth cameras: first-person, chase, orbit, look-at, you name it!

Camera rigs made with dolly are engine-agnostic, and only provide camera positioning. Optical and rendering parameters such as field of view and clipping planes can be built on top, and are not within the scope of this crate.

While cameras are a complex topic in gamedev, this crate only provides the basics, aiming at small games and tools.

Examples

orbit.mp4
let mut camera = CameraRig::builder()
    .with(YawPitch::new().yaw_degrees(45.0).pitch_degrees(-30.0))
    .with(Smooth::new_look(1.5))
    .with(Arm::new(Vec3::Z * 4.0))
    .build();

// ...

let camera_driver = camera.driver_mut::();
if keyboard.was_just_pressed(VirtualKeyCode::Z) {
    camera_driver.rotate_yaw_pitch(-90.0, 0.0);
}
if keyboard.was_just_pressed(VirtualKeyCode::X) {
    camera_driver.rotate_yaw_pitch(90.0, 0.0);
}

camera.update(time_delta_seconds);

follow.mp4
let mut camera = CameraRig::builder()
    .with(Positional::new(car.position))
    .with(Smooth::new_move(1.25).predictive(1.0))
    .with(Arm::new(Vec3::new(0.0, 1.5, -3.5)))
    .with(Smooth::new_move(2.5))
    .with(
        LookAt::new(car.position + Vec3::Y)
            .smoothness(1.25)
            .predictive(1.0),
    )
    .build();

// ...

camera
    .driver_mut::()
    .set_position_rotation(car.position, car.rotation);
camera.driver_mut::().target = car.position + Vec3::Y;
camera.update(time_delta_seconds);

look-at.mp4
let mut camera = CameraRig::builder()
    .with(Positional::new(Vec3::Y * 3.0))
    .with(LookAt::new(car.position))
    .build();

// ...

camera.driver_mut::().target = car.position;
camera.update(time_delta_seconds);

free.mp4
() .rotate_yaw_pitch(-0.3 * mouse.delta.x, -0.3 * mouse.delta.y); camera .driver_mut::() .translate(move_vec * time_delta_seconds * 10.0); camera.update(time_delta_seconds); ">
let mut camera = CameraRig::builder()
    .with(Positional::new(Vec3::Y))
    .with(YawPitch::new())
    .with(Smooth::new_move_look(1.0, 1.0))
    .build();

// ...

let move_vec = camera.transform.rotation
    * Vec3::new(input["move_right"], input["move_up"], -input["move_fwd"])
        .clamp_length_max(1.0)
    * 10.0f32.powf(input["boost"]);

camera
    .driver_mut::()
    .rotate_yaw_pitch(-0.3 * mouse.delta.x, -0.3 * mouse.delta.y);
camera
    .driver_mut::()
    .translate(move_vec * time_delta_seconds * 10.0);
camera.update(time_delta_seconds);
Comments
  • Add GitHub Actions configuration

    Add GitHub Actions configuration

    This is a minimal setup that checks code formatting, clippy lints (also a check), documentation and specifically broken intradoc links and directives, and the current MSRV of 1.58.1.

    opened by MarijnS95 8
  • Allow nested drivers

    Allow nested drivers

    Allows you to create a nested driver using a derive (Debug derive is needed as well due to RigDriver in CameraRig uses std::fmt::Debug), there might be a smarter way to make this abstraction, though I do not know how. Any input is highly appreciated:

    use dolly::{
        driver::RigDriver,
        glam::Vec3,
        prelude::{Arm, CameraRig, LookAt, Position, Rotation, Smooth},
        rig::RigUpdateParams,
        DollyDriver,
    };
    
    #[derive(Debug, DollyDriver)]
    pub struct Follow {
        pub rig: CameraRig,
    }
    
    impl Follow {
        pub fn init(transform: dolly::transform::Transform) -> Self {
            Self {
                rig: CameraRig::builder()
                    .with(Position::new(transform.position))
                    .with(Rotation::new(transform.rotation))
                    .with(Smooth::new_position(1.25).predictive(true))
                    .with(Arm::new(Vec3::new(0.0, 1.5, -3.5)))
                    .with(Smooth::new_position(2.5))
                    .with(
                        LookAt::new(transform.position + Vec3::Y)
                            .tracking_smoothness(1.25)
                            .tracking_predictive(true),
                    )
                    .build(),
            }
        }
    
        pub fn update(&mut self, position: Vec3, rotation: dolly::glam::Quat, target: Vec3) {
            self.rig.driver_mut::<Position>().position = position;
            self.rig.driver_mut::<Rotation>().rotation = rotation;
            self.rig.driver_mut::<LookAt>().target = target;
        }
    }
    

    Allows for:

    In setup:

    CameraRig::builder()
    .with(Follow::init(
    	  dolly::transform::Transform {
    		  position: start_pos,
    		  rotation: dolly::glam::Quat::IDENTITY,
    	  }
    )).build()
    

    At runtime:

    rig.driver_mut::<Follow>().update(
    	player.position,
    	player.rotation,
    	player.position + Vec3::Y,
    );
    
    let transform = rig.update(time.delta_seconds());
    
    
    opened by BlackPhlox 7
  • cargo: Bump glam upper version bound to 0.21

    cargo: Bump glam upper version bound to 0.21

    Note that const_vec3! is now deprecated in favor of new const fns, should we switch to that and drop the minimum bound? This may also have implications on MSRV though. See also https://github.com/MarijnS95/dolly/compare/glam-0.21-const.

    opened by MarijnS95 6
  • Made CameraRig phantom field pub so it can support bevy_dolly

    Made CameraRig phantom field pub so it can support bevy_dolly

    From bevy 0.6 and forward, all components require the #[derive(Component)] which means that bevy_dolly's current impl. of dolly cannot compile. In order to use CameraRig as a component in bevy_ecs, the newtype pattern is required as shown:

    #[derive(Component, Deref, DerefMut)]
    pub struct BevyCameraRig(CameraRig<RightHanded>);
    

    However, this also means that the builder function has to return BevyCameraRig. And seeing as we have to reimplement the CameraRigBuilder to return BevyCameraRig (I see no other option). We have to create CameraRig, though this is currently not feasible outside the crate itself due to the phantom field in CameraRig being non-pub.

    So... An image showing the Bernie Sanders meme: I Am Once Again Asking For Your Financial Support. Bernie Sanders' head has been replaced with BlackPhlox's profile picture and the financial part of the text has been replaced with bevy, now saying: I Am Once Again Asking For Your Bevy Support.

    opened by BlackPhlox 6
  • Upgrade `glam` to `0.22`, bump minimum to `0.21`

    Upgrade `glam` to `0.22`, bump minimum to `0.21`

    glam finally removed the deprecated const_vec3! macro constructor in favour of proper const fns, supported for both arrays and loose per-component arguments. This however bumps the minimum requirement to 0.21 where these const fns were first introduced, and propagates its 1.58.1 MSRV.

    opened by MarijnS95 5
  • 🐑 Left-handed systems support.

    🐑 Left-handed systems support.

    New: Implement left-handed system support using generics + handedness trait. CameraRig defaults to RightHanded.

    Old: The comment below doesn't apply anymore, as the entire PR has pretty much changed :)

    I tried to keep the public API unchanged, but alas the Transform forward() function didn't make the cut 😛 as I didn't want to pass a nasty bool inside Transform as well.

    Users should be able to simply call build_lh(). Works on my machine™.

    opened by EmilioLaiso 4
  • Added bevy_ecs support to CameraRig

    Added bevy_ecs support to CameraRig

    In order for bevy to use the CameraRig as a component, Sync + Send (thread-safe) is currently required. This addition should not inhibit its usage in other engines.

    opened by BlackPhlox 1
  • Add driver() function to obtain an immutable reference to the driver

    Add driver() function to obtain an immutable reference to the driver

    Somethings it needed to get a value from driver without it modification. In unit tests, for example. It would be great to have a function that behaves like driver_mut, but returns a non-mutable reference.

    opened by Shatur 0
  • Using rotational smoothing causes snapping and camera roll

    Using rotational smoothing causes snapping and camera roll

    Very high rotational smoothing values in combination with high sensitivity causes the camera to snap (to the closest quat rotation) and roll which is mildly dizzying 😅

    opened by VZout 0
  • Support for bbox/bsphere framing?

    Support for bbox/bsphere framing?

    I saw in the readme that field of view is (intentionally) not part of this. But could it be?

    Framing an object (smoothly) based on its bbox/bsphere is a common task for such rigs in the wild.

    opened by virtualritz 4
Owner
Tomasz Stachowiak
Rust and GPU hacker at Embark Studios
Tomasz Stachowiak
First-person 3D pong ray-traced on CPU in real time.

ray ten Run in browser ray-ten.mp4 Reimagining of a 1986 ZX Spectrum game room ten made with ray tracing. Completely ignoring GPUs when rendering 3D g

Egor 2 Aug 20, 2022
A Bevy Engine plugin for making 2D paths, smooth animations with Bezier curves

bevy_pen_tool A Bevy Engine plugin for making 2D paths and smooth animations with Bezier curves TODO: Mesh-making functionality for building 2D shapes

Eli 36 Dec 22, 2022
Smooth pixel-perfect camera for Bevy

bevy_smooth_pixel_camera A bevy plugin that adds a simple smooth pixel camera. The smoothing is based on this video from aarthificial which explains h

Doonv 9 Nov 14, 2023
Managed game servers, matchmaking, and DDoS mitigation that lets you focus on building your game

Managed game servers, matchmaking, and DDoS mitigation that lets you focus on building your game. Home - Docs - Twitter - Discord ?? Features Everythi

Rivet 58 Jun 25, 2023
My first attempt at game programming. This is a simple target shooting game built in macroquad.

sergio My first attempt at game programming. This is a simple target shooting game built in macroquad. Rules Hit a target to increase score by 1 Score

Laz 1 Jan 11, 2022
Bevy Simple Portals is a Bevy game engine plugin aimed to create portals.

Portals for Bevy Bevy Simple Portals is a Bevy game engine plugin aimed to create portals. Those portals are (for now) purely visual and can be used t

Sélène Amanita 11 May 28, 2023
Dark Forest, the world's first decentralized real-time strategy game.

darkforest-rs Dark Forest, the world's first decentralized real-time strategy game.

null 44 Oct 9, 2022
My first Real-Time 3D Game Engine learning project written in Rust.

EyeEngine-Rust FOA, sry for my poor English. What is Eye Engine? Eye Engine is my first Real-Time 3D Game Engine learning project. There are two editi

F-seeeye 4 Jan 5, 2022
Rushes are new ephemeral projects at Hive Helsinki. Wordle is the first in this series with 48 hours time window

Rushes are new ephemeral projects at Hive Helsinki. Wordle is the first in this series with 48 hours time window

Jiri Novotny 1 Feb 24, 2022
A first-time implementation of Conway's Game of Life in Rust: Adventure and Commentary

A Commentary on Life This project documents the process and final result of my first-ever attempt at implementing Conway's Game of Life. I'll be using

Avery R. 2 Feb 25, 2022
A game made in one week for the Bevy engine's first game jam

¿Quien es el MechaBurro? An entry for the first Bevy game jam following the theme of "Unfair Advantage." It was made in one week using the wonderful B

mike 20 Dec 23, 2022
A plugin-first anime-ish video game

?? ?? Project Flara ?? ?? A plugin-first anime-ish video game Have you ever played an anime mobile video game, and then wondered. Huh, I wish I could

null 2 Dec 23, 2022
You have been an apprentice to a powerful sorcerer for as long as you can remember.

You have been an apprentice to a powerful sorcerer for as long as you can remember. However you dream of becoming a rancher, raising animals in your own pen.

null 3 Jun 22, 2022
Random utility stuff for bevy for my personal use. You're welcome to use it, too, if you like.

bevy_cleancut Random utility stuff for bevy for my personal use. You're welcome to use it, too, if you like. Stuff It's all in the prelude: use bevy_c

Nathan Stocks 3 Aug 15, 2024
A place to start when building webgl apps in Bevy. Use this to avoid writing the boilerplate.

Template Bevy project with WebGL enabled Prerequisites cargo install cargo-make Build and serve WASM version Set your local ip address in Makefile.to

Michael Dorst 0 Dec 24, 2021
A Rust framework for building Minecraft servers.

A Rust framework for building Minecraft: Java Edition servers. Like feather, Valence is an effort to build a Minecraft compatible server completely fr

Valence 1.4k Dec 30, 2022
A framework for building adventure games in Bevy.

Bevy_adventure A framework for building 3d adventure games in Bevy. preview.mp4 Features Interactive trait is the backbone of the framework, allowing

Hank Jordan 9 Jan 5, 2023
Rust library to create a Good Game Easily

ggez What is this? ggez is a Rust library to create a Good Game Easily. The current version is 0.6.0-rc0. This is a RELEASE CANDIDATE version, which m

null 3.6k Jan 7, 2023
An attempt to create an easily customizable MMORPG game engine. Sky not included.

skyless Proof of concept of an easily customizable MMORPG game engine. Getting started Copy environment variables cp .env.example .env Start the engi

null 8 Nov 23, 2022