Skip to content
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

use marker components for cameras instead of name strings #3635

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

@jakobhellermann
Copy link
Contributor

@jakobhellermann jakobhellermann commented Jan 10, 2022

Problem

  • whenever you want more than one of the builtin cameras (for example multiple windows, split screen, portals), you need to add a render graph node that executes the correct sub graph, extract the camera into the render world and add the correct RenderPhase<T> components
  • querying for the 3d camera is annoying because you need to compare the camera's name to e.g. CameraPlugin::CAMERA_3d

Solution

  • Introduce the marker types Camera3d, Camera2d and CameraUi
    -> Query<&mut Transform, With<Camera3d>> works
  • PerspectiveCameraBundle::new_3d() and PerspectiveCameraBundle::<Camera3d>::default() contain the Camera3d marker
  • OrthographicCameraBundle::new_3d() has Camera3d, OrthographicCameraBundle::new_2d() has Camera2d
  • remove ActiveCameras, ExtractedCameraNames
  • run 2d, 3d and ui passes for every camera of their respective marker
    -> no custom setup for multiple windows example needed

Open questions

  • do we need a replacement for ActiveCameras? What about a component ActiveCamera { is_active: bool } similar to Visibility?
@alice-i-cecile
Copy link
Member

@alice-i-cecile alice-i-cecile commented Jan 10, 2022

Closes #1854. Previously attempted in #1888.

.get_or_spawn(entity)
.insert(RenderPhase::<Transparent2d>::default());
}
for entity in query_camera_2d.iter() {
Copy link
Member

@alice-i-cecile alice-i-cecile Jan 10, 2022

Choose a reason for hiding this comment

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

Ooh interesting: will this enable multiple cameras more easily?

Copy link
Contributor Author

@jakobhellermann jakobhellermann Jan 10, 2022

Choose a reason for hiding this comment

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

Yes, the multiple_windows example needs no additional setup for tue second camera anymore.

@alice-i-cecile alice-i-cecile requested a review from HackerFoo Jan 10, 2022
@alice-i-cecile
Copy link
Member

@alice-i-cecile alice-i-cecile commented Jan 10, 2022

We should think about how to coordinate this with #3412. @HackerFoo, do you have a preference?


/// Component bundle for camera entities with perspective projection
///
/// Use this for 3D rendering.
#[derive(Bundle)]
pub struct PerspectiveCameraBundle {
pub struct PerspectiveCameraBundle<M: Component> {
Copy link
Member

@alice-i-cecile alice-i-cecile Jan 10, 2022

Choose a reason for hiding this comment

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

I love this style of API; I've used it before in my games and it's great.

pub fn new_3d() -> Self {
Default::default()
PerspectiveCameraBundle::new()
Copy link
Member

@alice-i-cecile alice-i-cecile Jan 10, 2022

Choose a reason for hiding this comment

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

This feels a bit weird to me? Why not just use PerspectiveCameraBundle<Camera3d>::default() instead? And then specialize the default impls based on which generic is passed in.

@HackerFoo
Copy link
Contributor

@HackerFoo HackerFoo commented Jan 10, 2022

We should think about how to coordinate this with #3412. @HackerFoo, do you have a preference?

I'd like #3412 and #3568 to be considered, because they make it useful to run the draw_3d_graph subgraph on multiple cameras. It would be useful to attach some identifier to the types, to somehow control the layering order, and make other minor modifications to passes. I might have more feedback after reading through this PR.

I also have an idea for specifying the pass order in Camera, to allow e.g. skyboxes (behind everything else) and UI layers (in front.)

@jakobhellermann
Copy link
Contributor Author

@jakobhellermann jakobhellermann commented Jan 10, 2022

We should think about how to coordinate this with #3412. HackerFoo, do you have a preference?

Rebasing one on top of the other once it is merged shouldnt be too hard, the changes are in similar code paths but are mostly unrelated.

@alice-i-cecile
Copy link
Member

@alice-i-cecile alice-i-cecile commented Jan 10, 2022

This is looking much cleaner. I'm really happy to see this finally get cleaned up. Just a few nits :)

@superdump
Copy link
Contributor

@superdump superdump commented Jan 10, 2022

do we need a replacement for ActiveCameras? What about a component ActiveCamera { is_active: bool } similar to Visibility?

And here’s another instance of the same question. I’ve seen this 4 times in the past two days. :) @mockersf suggested adding enable/disable for lights while I was doing some other things but it’s not trivial imo because of the question of whether to have something like a ZST for the less likely case (i.e. an empty InactiveCamera component) which introduces archetype fragmentation but is directly queryable, or always adding an ActiveCamera { is_active: bool } component and forcing visiting all entities just to find one or the other subset, and always using the storage for the component. @cart suggested adding Visibility to the light bundles but Visibility feels like the wrong property for lights. I felt like something more generically usable everywhere like Enabled { is_enabled: bool } or Active { is_active: bool } or some better name, for all cases. Visibility, lights being enabled, cameras being active, whatever. And then when we make an editor there is one component that handles them all in a sensible and consistent way. But, I didn’t proceed because there’s still the question of the component with a bool member or the marker component for the less likely case. It feels like marker components should be used only where iteration performance is a top priority because I fear the combinatoric explosion and subsequent fragmentation if we use too many marker components… :/ I don’t know

@alice-i-cecile
Copy link
Member

@alice-i-cecile alice-i-cecile commented Jan 10, 2022

I felt like something more generically usable everywhere like Enabled { is_enabled: bool } or Active { is_active: bool } or some better name, for all cases

I'm in favor of this: being able to standardize the ecosystem around this pattern is super useful.

But, I didn’t proceed because there’s still the question of the component with a bool member or the marker component for the less likely case. It feels like marker components should be used only where iteration performance is a top priority because I fear the combinatoric explosion and subsequent fragmentation if we use too many marker components… :/

So, IMO archetype fragmentation is less important performance-wise than the requirement to constantly check values. I'd prefer a marker component: if we use sparse-set storage it'll be faster to add and remove too. I would be fine with either Enabled/Active or Disabled/Inactive as the marker, depending on which pattern you think is clearer / more useful for your rendering use cases.

Overall I think a Inactive marker component is going to be the clearest for debugging purposes, and the most natural to reuse in other contexts. I'd probably toss it in bevy_ecs; it'll be reused all over the place.

@HackerFoo
Copy link
Contributor

@HackerFoo HackerFoo commented Jan 10, 2022

How about RenderLayers::none() to disable a camera? That should already work, but maybe isn't optimized. I like RenderLayers because you can define complex relations between cameras and renderable entities.

Similar mechanisms are used for physics (e.g. in Rapier.)

@HackerFoo
Copy link
Contributor

@HackerFoo HackerFoo commented Jan 10, 2022

It would be useful to attach some identifier to the types

I suppose this could be done with some other component if needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

5 participants