Skip to content

Improve Camera naming and make bevy_ui respect cameras #16249

@aevyrie

Description

@aevyrie

Consider renaming Camera to something like RenderSurface. There isn't anything camera-like about our Camera component, and I think calling it a RenderSurface is more apt:

  • It has a size and position (viewport rect) that directly ties to the dimensions of the image you are rendering.
  • It has a target to render the 2d area to.
  • It can be ordered with other render surfaces that have the same target.

This is why bevy_picking relies on Camera - because the Camera component really describes the 2d area that Camera2d and Camera3d render to.

Following that first thought, there is a natural one-to-one cardinality between a UI tree and it's RenderSurface (Camera). You can't really show a UI tree on multiple render surfaces, because the size of the UI is dependent on the size of the render surface it is given to lay out into.

This is why, when this came up last time, I suggested that UI trees should be children of a RenderSurface (Camera). It would also, IMO solve some of the DX issues. You aren't spawning a freestanding UI camera, a freestanding UI tree, then linking them with a TargetCamera, it would make way more sense to me if the UI tree used our existing relationship for this: parenting.

If you want to have multiple UI trees on the same image, well, you would have a unique RenderSurface(Camera) at the root of each of these trees. This is nice because the order of these UI's sharing the same render target is explicit.

// Instead of
let ui_camera = commands.spawn(Camera);
commands.spawn((Node, TargetCamera(ui_camera)).with_children(|| /*...*/);
// What happens if two UI roots target the same camera? How are they ordered?
commands.spawn((Node, TargetCamera(ui_camera)).with_children(|| /*...*/);

// Renaming `Camera` to `RenderSurface` to illustrate this is what it really means:
// Two UIs and a 3d camera rendering to the default window, with order specified
// The render surface *is* the root UI node: it sets the viewport that can be drawn
comands.spawn((RenderSurface { order: 0, .. }, Node)).with_children(|| /*...*/);
comands.spawn((RenderSurface { order: 1, .. }, Node)).with_children(|| /*...*/);
comands.spawn((RenderSurface { order: 3 }, Camera3d))

You can also see how the UI/3d/2d can share the same abstractions for viewports, camera order, render targets.

For example, rendering the UIs to the second window, with a particular order, using a different sub viewport:

comands
    .spawn((RenderSurface { order: 0, viewport: Some(viewport_1), target: window_2 }, Node))
    .with_children(|parent| parent.spawn(Node));

comands
    .spawn((RenderSurface { order: 1, viewport: Some(viewport_2, target: window_2 }, Node))
    .with_children(|parent| parent.spawn(Node));

Some relevant comments:

  • @NthTensor: Oh, as an added benefit: people are constantly annoyed at how cumbersome it is to overlay 3d models on UI currently. This seems like it might be an interesting way to solve that little rough spot.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-PickingPointing at and selecting objects of all sortsA-RenderingDrawing game state to the screenA-UIGraphical user interfaces, styles, layouts, and widgetsC-UsabilityA targeted quality-of-life change that makes Bevy easier to useD-StraightforwardSimple bug fixes and API improvements, docs, test and examplesS-Needs-DesignThis issue requires design work to think about how it would best be accomplished

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions