Skip to content

Add bevy_camera_controllers crate and move freecam implementation into it #20215

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

alice-i-cecile
Copy link
Member

@alice-i-cecile alice-i-cecile commented Jul 21, 2025

Objective

Moving the camera around is really important to validate that our scenes are rendered correctly.

Bevy engine devs currently do this via a fairly cursed "library example" which includes a basic freecam controller (which is technically distinct from a flycam apparently). This has three problems:

  1. Oh god why are we taking pseudo-dependencies on other examples.
  2. Something like this would be useful for debugging for users.
  3. Something like this would be useful for the editor and other tooling.

Solution

Create a new bevy_camera_controllers crate, and move the existing freecam implementation into it, nearly verbatim.

This cleans up some ugly tech debt in how we do this, makes it easier to add a camera controller to other examples, and also gives us a scaffold for future camera controllers.

This PR has been marked X-Blessed, as I went over this plan with @cart in a meeting on 2025-06-23, and we both agreed that this was the right first step.

Testing

I've tested the examples that rely on this camera controller: they work just like before.

Notes for reviewers

  • I don't intend to land this in Bevy 0.17: the existing example code is not high enough quality for me to be happy shipping this
    • we're also soft feature-frozen; I was just in the mood to do this today
  • this PR has some minimal cleanup: just enough naming and docs work to make this code not an active liability. Any more will risk derailing this PR and making it harder to review
  • I've opted to expose top-level feature flags for the various camera controllers. This is a bit noisy, but it was the only sensible way I could see to both have "no camera controllers by default" and "still easy to use these controllers in examples"
  • this will not be the only camera controller in this crate, or the Bevy Editor
    • this is not the place to discuss "what should the default camera controller for the Bevy Editor be"
    • if you think this crate, or this particular move is the wrong strategy for some other reason though, please do speak up :)
  • my personal (unblessed) hope is that we continue to add camera controllers to this crate as needed for various first-party tooling. I will probably largely push-back on adding camera controllers that we do not actively use to this crate, since I don't think they make great libraries in general (much better to copy-paste)

TODO

  • add release note. I'm waiting until after Bevy 0.17 ships to do this
  • update the examples/README.md file. I was lazy and didn't want to constantly resolve merge conflicts on that while this PR sits
  • change to singular crate name

Future work

  • split apart the giant camera controller component
  • make keybinding better, either with or without a real input manager solution
  • split apart the system to make it more modular
  • make the system handle fixed timesteps better
  • use the camera controller in more examples for debugging
  • add more camera controllers!

Module docs

Hook up new crate to bevy_internal
Stub for fly_cam camera controller

Steal existing free-cam controller
@alice-i-cecile alice-i-cecile added this to the 0.18 milestone Jul 21, 2025
@alice-i-cecile alice-i-cecile added C-Feature A new feature, making something new possible C-Code-Quality A section of code that is hard to understand or change S-Blocked This cannot move forward until something else changes M-Needs-Release-Note Work that should be called out in the blog due to impact X-Blessed Has a large architectural impact or tradeoffs, but the design has been endorsed by decision makers A-Camera User-facing camera APIs and controllers. labels Jul 21, 2025

This comment was marked as duplicate.

@alice-i-cecile alice-i-cecile changed the title Bevy camera controllers Add bevy_camera_controllers crate and move freecam implementation into it Jul 21, 2025
@atlv24
Copy link
Contributor

atlv24 commented Jul 21, 2025

i worry a bit about the added friction of having to run some examples with --features "free_cam" now

@@ -298,6 +298,10 @@ bevy_gizmos = ["bevy_internal/bevy_gizmos", "bevy_color"]
# Provides a collection of developer tools
bevy_dev_tools = ["bevy_internal/bevy_dev_tools"]

# Provides a collection of prebuilt camera controllers
bevy_camera_controllers = ["bevy_internal/bevy_camera_controllers"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are we sure we want plural crate name?

bevy_camera_controllers::free_cam
bevy_camera_controllers::fly_cam

vs

bevy_camera_controller::free_cam
bevy_camera_controller::fly_cam

@@ -4,13 +4,12 @@
//! - Insert an initialized `SceneHandle` resource into your App's `AssetServer`.

use bevy::{
gltf::Gltf, input::common_conditions::input_just_pressed, prelude::*, scene::InstanceId,
camera_controllers::free_cam::FreeCamController, gltf::Gltf,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be cool to re-export this from top level crate and probably shorten it to just FreeCam maybe

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we overuse re-exports! Shortening it would be good though.

This comment was marked as duplicate.

@Aceeri
Copy link
Member

Aceeri commented Jul 21, 2025

i worry a bit about the added friction of having to run some examples with --features "free_cam" now

I think it's ok, there is some minor friction but the required-features should prompt people well enough and may add to discoverability of how to add FreeCam for your own project.

alice-i-cecile and others added 2 commits July 21, 2025 13:10
Co-authored-by: atlv <email@atlasdostal.com>
@alice-i-cecile
Copy link
Member Author

Yeah, the prompt is very helpful. I don't like having to add it, but the alternative is to add it to the default features. Since 99% of games won't want to ship with this in production, the only way to reclaim that binary size / compile speed will be to turn off Bevy's default features and slowly build it back up.

Copy link
Contributor

The generated examples/README.md is out of sync with the example metadata in Cargo.toml or the example readme template. Please run cargo run -p build-templated-pages -- update examples to update it, and commit the file change.

@BigWingBeat
Copy link
Contributor

I have some feedback and improvements in mind for this code, but as per the "notes for reviewers", I think it would mostly be out of scope for this initial PR. Should I wait until this PR is merged to follow-up on it, or is there an appropriate way to share the feedback immediately?

@alice-i-cecile
Copy link
Member Author

Leave your feedback here for now, and then we can come back to this thread for notes when merged :)

@BigWingBeat
Copy link
Contributor

BigWingBeat commented Jul 21, 2025

On line 183 (Github won't let me comment on that line directly because it's outside of the diff), the scroll delta is divided by 16 if the unit is pixels, and not if the unit is lines. This seems odd to me, both because it's undocumented, and because no other use of mouse scrolling I could find in Bevy cares about the scroll units.

The PR that added this was #11921, and reading the comments there reveals that the choice of 16 as the divisor was both arbitrary and untested.

Someone should actually test pixel scrolling, and either confirm that 16 is fine, or update it to something better (and also document it either way). Alternatively, the special-casing based on the units could just be removed entirely.

@BigWingBeat
Copy link
Contributor

BigWingBeat commented Jul 21, 2025

Line 186 (also outside the diff) is where the movement speed is updated based on the mouse scrolling, however the way it is done is flawed.

Ideally, the effect of n scroll events, each with a delta of 1, should be the same as the effect of 1 scroll event with a delta of n. This is not the case with the current implementation.

The correct way to do it, that does have this property we want, looks something like this:

-controller.walk_speed += scroll * controller.scroll_factor * controller.walk_speed;
+controller.walk_speed *= (controller.scroll_factor + 1.0).powf(scroll);

This should also be documented when implemented, and maybe someone who understands the math better than me can explain why/how it works, beyond just that It Does.

@BigWingBeat
Copy link
Contributor

BigWingBeat commented Jul 21, 2025

Line 235 (not in diff etc.), the way friction is applied should take the delta time into account. Given that it's implementing an exponential decay, it should be refactored to use StableInterpolate::smooth_nudge.

@BigWingBeat
Copy link
Contributor

Lastly, and most subjectively, I think the default sensitivity is way too high. I should not be doing 360s with ~1cm of physical mouse movement (and I say this as someone who tends to turn mouse sensitivity up in most games I play).

@torsteingrindvik
Copy link
Contributor

For traceability I'll link the issue on upstreaming bevy_editor_cam: #19741

If I'm reading the context correctly the outcome of upstreaming that would be as a controller in bevy_camera_controllers.

Nit: The OP says "I don't intend to land this in Bevy 0.18", I assume this should say 0.17?

@Aceeri
Copy link
Member

Aceeri commented Jul 22, 2025

Lastly, and most subjectively, I think the default sensitivity is way too high. I should not be doing 360s with ~1cm of physical mouse movement (and I say this as someone who tends to turn mouse sensitivity up in most games I play).

FWIW this should be reflective of the default 1.0 sensitivity from Valorant, if it doesn't match for you in that then there was probably something wrong with my math.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Camera User-facing camera APIs and controllers. C-Code-Quality A section of code that is hard to understand or change C-Feature A new feature, making something new possible M-Needs-Release-Note Work that should be called out in the blog due to impact S-Blocked This cannot move forward until something else changes X-Blessed Has a large architectural impact or tradeoffs, but the design has been endorsed by decision makers
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants