Port bevy_core_pipeline to LinearRgba (#12116)

# Objective

- We should move towards a consistent use of the new `bevy_color` crate.
- As discussed in #12089, splitting this work up into small pieces makes
it easier to review.

## Solution

- Port all uses of `LegacyColor` in the `bevy_core_pipeline` to
`LinearRgba`
- `LinearRgba` is the correct type to use for internal rendering types
- Added `LinearRgba::BLACK` and `WHITE` (used during migration)
- Add `LinearRgba::grey` to more easily construct balanced grey colors
(used during migration)
- Add a conversion from `LinearRgba` to `wgpu::Color`. The converse was
not done at this time, as this is typically a user error.

I did not change the field type of the clear color on the cameras: as
this is user-facing, this should be done in concert with the other
configurable fields.

## Migration Guide

`ColorAttachment` now stores a `LinearRgba` color, rather than a Bevy
0.13 `Color`.
`set_blend_constant` now takes a `LinearRgba` argument, rather than a
Bevy 0.13 `Color`.

---------

Co-authored-by: Alice Cecile <alice.i.cecil@gmail.com>
This commit is contained in:
Alice Cecile 2024-02-26 07:25:11 -05:00 committed by GitHub
parent 43b859dfcf
commit 8ec65525ab
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 71 additions and 24 deletions

View file

@ -15,6 +15,7 @@ bevy_reflect = { path = "../bevy_reflect", version = "0.14.0-dev", features = [
] }
serde = "1.0"
thiserror = "1.0"
wgpu = { version = "0.19.1", default-features = false }
[lints]
workspace = true

View file

@ -23,6 +23,30 @@ pub struct LinearRgba {
impl StandardColor for LinearRgba {}
impl LinearRgba {
/// A fully black color with full alpha.
pub const BLACK: Self = Self {
red: 0.0,
green: 0.0,
blue: 0.0,
alpha: 1.0,
};
/// A fully white color with full alpha.
pub const WHITE: Self = Self {
red: 1.0,
green: 1.0,
blue: 1.0,
alpha: 1.0,
};
/// A fully transparent color.
pub const NONE: Self = Self {
red: 0.0,
green: 0.0,
blue: 0.0,
alpha: 0.0,
};
/// Construct a new [`LinearRgba`] color from components.
pub const fn new(red: f32, green: f32, blue: f32, alpha: f32) -> Self {
Self {
@ -49,6 +73,18 @@ impl LinearRgba {
}
}
/// Construct a new [`LinearRgba`] color with the same value for all channels and an alpha of 1.0.
///
/// A value of 0.0 is black, and a value of 1.0 is white.
pub const fn gray(value: f32) -> Self {
Self {
red: value,
green: value,
blue: value,
alpha: 1.0,
}
}
/// Return a copy of this color with the red channel set to the given value.
pub const fn with_red(self, red: f32) -> Self {
Self { red, ..self }
@ -81,12 +117,7 @@ impl LinearRgba {
impl Default for LinearRgba {
/// Construct a new [`LinearRgba`] color with the default values (white with full alpha).
fn default() -> Self {
Self {
red: 1.,
green: 1.,
blue: 1.,
alpha: 1.,
}
Self::WHITE
}
}
@ -205,6 +236,17 @@ impl From<Hsla> for LinearRgba {
}
}
impl From<LinearRgba> for wgpu::Color {
fn from(color: LinearRgba) -> Self {
wgpu::Color {
r: color.red as f64,
g: color.green as f64,
b: color.blue as f64,
a: color.alpha as f64,
}
}
}
#[cfg(test)]
mod tests {
use super::*;

View file

@ -24,6 +24,7 @@ tonemapping_luts = ["bevy_render/ktx2", "bevy_render/zstd"]
bevy_app = { path = "../bevy_app", version = "0.14.0-dev" }
bevy_asset = { path = "../bevy_asset", version = "0.14.0-dev" }
bevy_core = { path = "../bevy_core", version = "0.14.0-dev" }
bevy_color = { path = "../bevy_color", version = "0.14.0-dev" }
bevy_derive = { path = "../bevy_derive", version = "0.14.0-dev" }
bevy_ecs = { path = "../bevy_ecs", version = "0.14.0-dev" }
bevy_log = { path = "../bevy_log", version = "0.14.0-dev" }

View file

@ -2,6 +2,7 @@ mod downsampling_pipeline;
mod settings;
mod upsampling_pipeline;
use bevy_color::LinearRgba;
pub use settings::{BloomCompositeMode, BloomPrefilterSettings, BloomSettings};
use crate::{
@ -17,7 +18,6 @@ use bevy_render::{
extract_component::{
ComponentUniforms, DynamicUniformIndex, ExtractComponentPlugin, UniformComponentPlugin,
},
prelude::LegacyColor,
render_graph::{NodeRunError, RenderGraphApp, RenderGraphContext, ViewNode, ViewNodeRunner},
render_resource::*,
renderer::{RenderContext, RenderDevice},
@ -244,7 +244,7 @@ impl ViewNode for BloomNode {
mip as f32,
(bloom_texture.mip_count - 1) as f32,
);
upsampling_pass.set_blend_constant(LegacyColor::rgb_linear(blend, blend, blend));
upsampling_pass.set_blend_constant(LinearRgba::gray(blend));
upsampling_pass.draw(0..3, 0..1);
}
@ -271,7 +271,7 @@ impl ViewNode for BloomNode {
}
let blend =
compute_blend_factor(bloom_settings, 0.0, (bloom_texture.mip_count - 1) as f32);
upsampling_final_pass.set_blend_constant(LegacyColor::rgb_linear(blend, blend, blend));
upsampling_final_pass.set_blend_constant(LinearRgba::gray(blend));
upsampling_final_pass.draw(0..3, 0..1);
}

View file

@ -41,6 +41,7 @@ pub const CORE_3D_DEPTH_FORMAT: TextureFormat = TextureFormat::Depth32Float;
use std::ops::Range;
use bevy_asset::AssetId;
use bevy_color::LinearRgba;
pub use camera_3d::*;
pub use main_opaque_pass_3d_node::*;
pub use main_transparent_pass_3d_node::*;
@ -49,7 +50,6 @@ use bevy_app::{App, Plugin, PostUpdate};
use bevy_ecs::prelude::*;
use bevy_render::{
camera::{Camera, ExtractedCamera},
color::LegacyColor,
extract_component::ExtractComponentPlugin,
mesh::Mesh,
prelude::Msaa,
@ -836,18 +836,18 @@ pub fn prepare_prepass_textures(
commands.entity(entity).insert(ViewPrepassTextures {
depth: cached_depth_texture
.map(|t| ColorAttachment::new(t, None, Some(LegacyColor::BLACK))),
.map(|t| ColorAttachment::new(t, None, Some(LinearRgba::BLACK))),
normal: cached_normals_texture
.map(|t| ColorAttachment::new(t, None, Some(LegacyColor::BLACK))),
.map(|t| ColorAttachment::new(t, None, Some(LinearRgba::BLACK))),
// Red and Green channels are X and Y components of the motion vectors
// Blue channel doesn't matter, but set to 0.0 for possible faster clear
// https://gpuopen.com/performance/#clears
motion_vectors: cached_motion_vectors_texture
.map(|t| ColorAttachment::new(t, None, Some(LegacyColor::BLACK))),
.map(|t| ColorAttachment::new(t, None, Some(LinearRgba::BLACK))),
deferred: cached_deferred_texture
.map(|t| ColorAttachment::new(t, None, Some(LegacyColor::BLACK))),
.map(|t| ColorAttachment::new(t, None, Some(LinearRgba::BLACK))),
deferred_lighting_pass_id: cached_deferred_lighting_pass_id_texture
.map(|t| ColorAttachment::new(t, None, Some(LegacyColor::BLACK))),
.map(|t| ColorAttachment::new(t, None, Some(LinearRgba::BLACK))),
size,
});
}

View file

@ -4,10 +4,10 @@ use crate::{
core_3d::graph::{Core3d, Node3d},
};
use bevy_app::{App, Plugin};
use bevy_color::LinearRgba;
use bevy_ecs::prelude::*;
use bevy_render::{
camera::ExtractedCamera,
color::LegacyColor,
render_graph::{Node, NodeRunError, RenderGraphApp, RenderGraphContext},
renderer::RenderContext,
view::{Msaa, ViewTarget},
@ -92,7 +92,7 @@ impl Node for MsaaWritebackNode {
view: target.sampled_main_texture_view().unwrap(),
resolve_target: Some(post_process.destination),
ops: Operations {
load: LoadOp::Clear(LegacyColor::BLACK.into()),
load: LoadOp::Clear(LinearRgba::BLACK.into()),
store: StoreOp::Store,
},
})],

View file

@ -1,12 +1,12 @@
use crate::{
camera::Viewport,
prelude::LegacyColor,
render_resource::{
BindGroup, BindGroupId, Buffer, BufferId, BufferSlice, RenderPipeline, RenderPipelineId,
ShaderStages,
},
renderer::RenderDevice,
};
use bevy_color::LinearRgba;
use bevy_utils::{default, detailed_trace};
use std::ops::Range;
use wgpu::{IndexFormat, RenderPass};
@ -598,7 +598,7 @@ impl<'a> TrackedRenderPass<'a> {
/// Sets the blend color as used by some of the blending modes.
///
/// Subsequent blending tests will test against this value.
pub fn set_blend_constant(&mut self, color: LegacyColor) {
pub fn set_blend_constant(&mut self, color: LinearRgba) {
detailed_trace!("set blend constant: {:?}", color);
self.pass.set_blend_constant(wgpu::Color::from(color));
}

View file

@ -1,5 +1,6 @@
use super::CachedTexture;
use crate::{prelude::LegacyColor, render_resource::TextureView};
use crate::render_resource::TextureView;
use bevy_color::LinearRgba;
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
@ -13,7 +14,7 @@ use wgpu::{
pub struct ColorAttachment {
pub texture: CachedTexture,
pub resolve_target: Option<CachedTexture>,
clear_color: Option<LegacyColor>,
clear_color: Option<LinearRgba>,
is_first_call: Arc<AtomicBool>,
}
@ -21,7 +22,7 @@ impl ColorAttachment {
pub fn new(
texture: CachedTexture,
resolve_target: Option<CachedTexture>,
clear_color: Option<LegacyColor>,
clear_color: Option<LinearRgba>,
) -> Self {
Self {
texture,

View file

@ -551,9 +551,11 @@ pub fn prepare_view_targets(
(a, b, sampled, main_texture)
});
let converted_clear_color = clear_color.map(|color| color.into());
let main_textures = MainTargetTextures {
a: ColorAttachment::new(a.clone(), sampled.clone(), clear_color),
b: ColorAttachment::new(b.clone(), sampled.clone(), clear_color),
a: ColorAttachment::new(a.clone(), sampled.clone(), converted_clear_color),
b: ColorAttachment::new(b.clone(), sampled.clone(), converted_clear_color),
main_texture: main_texture.clone(),
};