Add "depth_load_op" configuration to 3d Cameras (#4904)

# Objective

Users should be able to configure depth load operations on cameras. Currently every camera clears depth when it is rendered. But sometimes later passes need to rely on depth from previous passes.

## Solution

This adds the `Camera3d::depth_load_op` field with a new `Camera3dDepthLoadOp` value. This is a custom type because Camera3d uses "reverse-z depth" and this helps us record and document that in a discoverable way. It also gives us more control over reflection + other trait impls, whereas `LoadOp` is owned by the `wgpu` crate.

```rust
commands.spawn_bundle(Camera3dBundle {
    camera_3d: Camera3d {
        depth_load_op: Camera3dDepthLoadOp::Load,
        ..default()
    },
    ..default()
});
```

### two_passes example with the "second pass" camera configured to the default (clear depth to 0.0)

![image](https://user-images.githubusercontent.com/2694663/171743172-46d4fdd5-5090-46ea-abe4-1fbc519f6ee8.png)


### two_passes example with the "second pass" camera configured to "load" the depth
![image](https://user-images.githubusercontent.com/2694663/171743323-74dd9a1d-9c25-4883-98dd-38ca0bed8c17.png)

---

## Changelog

### Added

* `Camera3d` now has a `depth_load_op` field, which can configure the Camera's main 3d pass depth loading behavior.
This commit is contained in:
Carter Anderson 2022-06-07 22:22:10 +00:00
parent cbf032419d
commit f28b921209
6 changed files with 40 additions and 4 deletions

View file

@ -1,18 +1,50 @@
use crate::clear_color::ClearColorConfig;
use bevy_ecs::{prelude::*, query::QueryItem};
use bevy_reflect::Reflect;
use bevy_reflect::{Reflect, ReflectDeserialize};
use bevy_render::{
camera::{Camera, CameraRenderGraph, Projection},
extract_component::ExtractComponent,
primitives::Frustum,
render_resource::LoadOp,
view::VisibleEntities,
};
use bevy_transform::prelude::{GlobalTransform, Transform};
use serde::{Deserialize, Serialize};
#[derive(Component, Default, Reflect, Clone)]
/// Configuration for the "main 3d render graph".
#[derive(Component, Reflect, Clone, Default)]
#[reflect(Component)]
pub struct Camera3d {
/// The clear color operation to perform for the main 3d pass.
pub clear_color: ClearColorConfig,
/// The depth clear operation to perform for the main 3d pass.
pub depth_load_op: Camera3dDepthLoadOp,
}
/// The depth clear operation to perform for the main 3d pass.
#[derive(Reflect, Serialize, Deserialize, Clone, Debug)]
#[reflect_value(Serialize, Deserialize)]
pub enum Camera3dDepthLoadOp {
/// Clear with a specified value.
/// Note that 0.0 is the far plane due to bevy's use of reverse-z projections.
Clear(f32),
/// Load from memory.
Load,
}
impl Default for Camera3dDepthLoadOp {
fn default() -> Self {
Camera3dDepthLoadOp::Clear(0.0)
}
}
impl From<Camera3dDepthLoadOp> for LoadOp<f32> {
fn from(config: Camera3dDepthLoadOp) -> Self {
match config {
Camera3dDepthLoadOp::Clear(x) => LoadOp::Clear(x),
Camera3dDepthLoadOp::Load => LoadOp::Load,
}
}
}
impl ExtractComponent for Camera3d {

View file

@ -87,8 +87,8 @@ impl Node for MainPass3dNode {
view: &depth.view,
// NOTE: The opaque main pass loads the depth buffer and possibly overwrites it
depth_ops: Some(Operations {
// NOTE: 0.0 is the far plane due to bevy's use of reverse-z projections
load: LoadOp::Clear(0.0),
// NOTE: 0.0 is the far plane due to bevy's use of reverse-z projections.
load: camera_3d.depth_load_op.clone().into(),
store: true,
}),
stencil_ops: None,

View file

@ -95,6 +95,7 @@ fn setup(
.spawn_bundle(Camera3dBundle {
camera_3d: Camera3d {
clear_color: ClearColorConfig::Custom(Color::WHITE),
..default()
},
camera: Camera {
// render before the "main pass" camera

View file

@ -66,6 +66,7 @@ fn setup(
camera_3d: Camera3d {
// dont clear on the second camera because the first camera already cleared the window
clear_color: ClearColorConfig::None,
..default()
},
..default()
})

View file

@ -49,6 +49,7 @@ fn setup(
transform: Transform::from_xyz(10.0, 10., -5.0).looking_at(Vec3::ZERO, Vec3::Y),
camera_3d: Camera3d {
clear_color: ClearColorConfig::None,
..default()
},
camera: Camera {
// renders after / on top of the main camera

View file

@ -102,6 +102,7 @@ fn setup(
commands.spawn_bundle(Camera3dBundle {
camera_3d: Camera3d {
clear_color: ClearColorConfig::Custom(Color::WHITE),
..default()
},
camera: Camera {
target: RenderTarget::Image(image_handle.clone()),