Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/example-run.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ jobs:
example_name=`basename $example .ron`
echo -n $example_name > last_example_run
echo "running $example_name - "`date`
time TRACE_CHROME=trace-$example_name.json CI_TESTING_CONFIG=$example cargo run --example $example_name --features "bevy_ci_testing,trace,trace_chrome,bevy_ui_debug"
time TRACE_CHROME=trace-$example_name.json CI_TESTING_CONFIG=$example cargo run --example $example_name --features "bevy_ci_testing,trace,trace_chrome,bevy_ui_debug,area_light_luts"
sleep 10
if [ `find ./ -maxdepth 1 -name 'screenshot-*.png' -print -quit` ]; then
mkdir screenshots-$example_name
Expand Down Expand Up @@ -132,7 +132,7 @@ jobs:
example_name=`basename $example .ron`
echo -n $example_name > last_example_run
echo "running $example_name - "`date`
time TRACE_CHROME=trace-$example_name.json CI_TESTING_CONFIG=$example xvfb-run cargo run --example $example_name --features "bevy_ci_testing,trace,trace_chrome,bevy_ui_debug"
time TRACE_CHROME=trace-$example_name.json CI_TESTING_CONFIG=$example xvfb-run cargo run --example $example_name --features "bevy_ci_testing,trace,trace_chrome,bevy_ui_debug,area_light_luts"
sleep 10
if [ `find ./ -maxdepth 1 -name 'screenshot-*.png' -print -quit` ]; then
mkdir screenshots-$example_name
Expand Down Expand Up @@ -201,7 +201,7 @@ jobs:
example_name=`basename $example .ron`
echo -n $example_name > last_example_run
echo "running $example_name - "`date`
time WGPU_BACKEND=dx12 TRACE_CHROME=trace-$example_name.json CI_TESTING_CONFIG=$example cargo run --example $example_name --features "statically-linked-dxc,bevy_ci_testing,trace,trace_chrome,bevy_ui_debug"
time WGPU_BACKEND=dx12 TRACE_CHROME=trace-$example_name.json CI_TESTING_CONFIG=$example cargo run --example $example_name --features "statically-linked-dxc,bevy_ci_testing,trace,trace_chrome,bevy_ui_debug,area_light_luts"
sleep 10
if [ `find ./ -maxdepth 1 -name 'screenshot-*.png' -print -quit` ]; then
mkdir screenshots-$example_name
Expand Down
6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,9 @@ bluenoise_texture = ["bevy_internal/bluenoise_texture"]
# Include a preintegrated BRDF Look Up Table for more accurate specular shading.
dfg_lut = ["bevy_internal/dfg_lut"]

# Include Look Up Tables that are required for rect light.
Comment thread
beicause marked this conversation as resolved.
Outdated
area_light_luts = ["bevy_internal/area_light_luts"]

# NVIDIA Deep Learning Super Sampling
dlss = ["bevy_internal/dlss"]

Expand Down Expand Up @@ -1190,7 +1193,7 @@ wasm = true
name = "rect_light"
path = "examples/3d/rect_light.rs"
doc-scrape-examples = true
required-features = ["free_camera"]
required-features = ["free_camera", "area_light_luts"]

[package.metadata.example.rect_light]
name = "Rectangular Area Light"
Expand Down Expand Up @@ -5192,6 +5195,7 @@ hidden = true
name = "testbed_3d"
path = "examples/testbed/3d.rs"
doc-scrape-examples = true
required-features = ["area_light_luts"]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

non-blocking comment: I know that I recently added a rect_light to the lights scene, but I don’t know if this should necessarily be added as a required feature in Cargo.toml, similar to how the ui testbed doesnt require the debug ui feature flag. The ui testbed doesn’t insert the debug outline scene if the feature isn’t enabled. Perhaps something similar should be done for the 3d testbed? It’ll allow the 3d testbed to keep growing in feature complexity without needing to specify a growing list of required flags.

A related question is, do we expect the app to fail loudly if the app creator adds a RectLight, but did not enable the associated feature? If the answer is no, then I think I wouldn’t require the feature here. I also then wouldn’t do any feature gating of the RectLight in the testbed so that case could theoretically be tested.

I agree that it should be added in example-run.yml though, which you have done. I also would still require it for the rect_light example as well


[package.metadata.example.testbed_3d]
hidden = true
Expand Down
2 changes: 1 addition & 1 deletion _release-content/release-notes/area_lights.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ The implementation uses [Linearly Transformed Cosines](https://eheitzresearch.wo

Rectangular lights currently don't cast shadows or have support for anisotropic materials.

Check out [the new example](https://github.com/bevyengine/bevy/tree/latest/examples/3d/rect_light.rs) to see them in action.
You need to enable `area_light_luts` cargo feature to use it. Check out [the new example](https://github.com/bevyengine/bevy/tree/latest/examples/3d/rect_light.rs) to see them in action.
Comment thread
beicause marked this conversation as resolved.
Outdated
3 changes: 3 additions & 0 deletions crates/bevy_internal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ bluenoise_texture = ["bevy_pbr?/bluenoise_texture", "ktx2", "bevy_image/zstd"]
# Include a preintegrated BRDF Look Up Table for more accurate specular shading.
dfg_lut = ["bevy_pbr?/dfg_lut", "ktx2", "bevy_image/zstd"]

# Include Look Up Tables that are required for rect light.
Comment thread
beicause marked this conversation as resolved.
Outdated
area_light_luts = ["bevy_pbr?/area_light_luts", "ktx2", "bevy_image/zstd"]

# NVIDIA Deep Learning Super Sampling
dlss = ["bevy_anti_alias/dlss", "bevy_solari?/dlss"]

Expand Down
1 change: 1 addition & 0 deletions crates/bevy_pbr/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pbr_clustered_decals = []
pbr_light_textures = []
bluenoise_texture = ["bevy_image/ktx2", "bevy_image/zstd"]
dfg_lut = ["bevy_image/ktx2", "bevy_image/zstd"]
area_light_luts = ["bevy_image/ktx2", "bevy_image/zstd"]
shader_format_glsl = ["bevy_shader/shader_format_glsl"]
trace = ["bevy_render/trace"]
# Enables the meshlet renderer for dense high-poly scenes (experimental)
Expand Down
101 changes: 62 additions & 39 deletions crates/bevy_pbr/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,14 +107,14 @@ use bevy_asset::{AssetApp, AssetPath, Assets, Handle, RenderAssetUsages};
use bevy_core_pipeline::mip_generation::experimental::depth::early_downsample_depth;
use bevy_core_pipeline::schedule::{Core3d, Core3dSystems};
use bevy_ecs::prelude::*;
use bevy_image::{CompressedImageFormats, Image, ImageSampler, ImageType};
use bevy_image::{Image, ImageSampler};
use bevy_material::AlphaMode;
use bevy_render::{
camera::sort_cameras,
extract_resource::ExtractResourcePlugin,
render_resource::{
Extent3d, TextureDataOrder, TextureDescriptor, TextureDimension, TextureFormat,
TextureUsages,
TextureUsages, TextureViewDescriptor, TextureViewDimension,
},
sync_component::SyncComponentPlugin,
ExtractSchedule, GpuResourceAppExt, Render, RenderApp, RenderDebugFlags, RenderStartup,
Expand Down Expand Up @@ -167,16 +167,15 @@ pub struct Bluenoise {
pub texture: Handle<Image>,
}

/// LTC (Linearly Transformed Cosines) LUT textures for area light shading.
/// A texture array contains 2 LTC (Linearly Transformed Cosines) LUT textures for area light shading.
///
/// `ltc_1` encodes the 4 non-trivial elements of the inverse GGX LTC matrix.
/// `ltc_2` encodes amplitude and Fresnel-related weights.
Comment thread
beicause marked this conversation as resolved.
Outdated
///
/// [LUT source and fitting code](https://github.com/selfshadow/ltc_code/blob/master/fit/results)
#[derive(Resource, Clone)]
pub struct LtcLuts {
pub ltc_1: Handle<Image>,
pub ltc_2: Handle<Image>,
pub struct AreaLightLuts {
pub image: Handle<Image>,
}

// See https://github.com/bevyengine/bevy/pull/23737 for information on how the LUT was generated.
Expand Down Expand Up @@ -282,15 +281,16 @@ impl Plugin for PbrPlugin {
let mut images = app.world_mut().resource_mut::<Assets<Image>>();
#[cfg(feature = "bluenoise_texture")]
let handle = {
let image = Image::from_buffer(
let mut image = Image::from_buffer(
include_bytes!("bluenoise/stbn.ktx2"),
ImageType::Extension("ktx2"),
CompressedImageFormats::NONE,
bevy_image::ImageType::Extension("ktx2"),
bevy_image::CompressedImageFormats::NONE,
false,
ImageSampler::Default,
RenderAssetUsages::RENDER_WORLD,
)
.expect("Failed to decode embedded blue-noise texture");
image.texture_descriptor.label = Some("bluenoise");
images.add(image)
};

Expand All @@ -304,39 +304,32 @@ impl Plugin for PbrPlugin {
}
}

let has_ltc_luts = app
let has_area_light_luts = app
.get_sub_app(RenderApp)
.is_some_and(|render_app| render_app.world().is_resource_added::<LtcLuts>());
.is_some_and(|render_app| render_app.world().is_resource_added::<AreaLightLuts>());

if !has_ltc_luts {
if !has_area_light_luts {
let mut images = app.world_mut().resource_mut::<Assets<Image>>();
let ltc_luts = LtcLuts {
ltc_1: images.add(
Image::from_buffer(
include_bytes!("ltc/ltc1.ktx2"),
ImageType::Extension("ktx2"),
CompressedImageFormats::NONE,
false,
ImageSampler::linear(),
RenderAssetUsages::RENDER_WORLD,
)
.expect("Failed to decode embedded LTC LUT 1"),
),
ltc_2: images.add(
Image::from_buffer(
include_bytes!("ltc/ltc2.ktx2"),
ImageType::Extension("ktx2"),
CompressedImageFormats::NONE,
false,
ImageSampler::linear(),
RenderAssetUsages::RENDER_WORLD,
)
.expect("Failed to decode embedded LTC LUT 2"),
),
#[cfg(feature = "area_light_luts")]
let handle = {
let mut image = Image::from_buffer(
include_bytes!("ltc/ltc.ktx2"),
bevy_image::ImageType::Extension("ktx2"),
bevy_image::CompressedImageFormats::NONE,
false,
ImageSampler::linear(),
RenderAssetUsages::RENDER_WORLD,
)
.expect("Failed to decode embedded LTC LUTs");
image.texture_descriptor.label = Some("area_light_luts");
images.add(image)
};
#[cfg(not(feature = "area_light_luts"))]
let handle = images.add(area_light_luts_placeholder());

let area_light_luts = AreaLightLuts { image: handle };
if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
render_app.world_mut().insert_resource(ltc_luts);
render_app.world_mut().insert_resource(area_light_luts);
}
}

Expand All @@ -349,8 +342,8 @@ impl Plugin for PbrPlugin {
let texture = app.world_mut().resource_mut::<Assets<Image>>().add(
Image::from_buffer(
include_bytes!("environment_map/dfg.ktx2"),
ImageType::Extension("ktx2"),
CompressedImageFormats::NONE,
bevy_image::ImageType::Extension("ktx2"),
bevy_image::CompressedImageFormats::NONE,
false,
ImageSampler::linear(),
RenderAssetUsages::RENDER_WORLD,
Expand Down Expand Up @@ -468,7 +461,7 @@ pub fn stbn_placeholder() -> Image {
size: Extent3d::default(),
format,
dimension: TextureDimension::D2,
label: None,
label: Some("bluenoise_placeholder"),
mip_level_count: 1,
sample_count: 1,
usage: TextureUsages::TEXTURE_BINDING,
Expand All @@ -481,6 +474,36 @@ pub fn stbn_placeholder() -> Image {
}
}

pub fn area_light_luts_placeholder() -> Image {
let format = TextureFormat::Rgba16Float;
let data = vec![0; 16];
Image {
data: Some(data),
data_order: TextureDataOrder::default(),
texture_descriptor: TextureDescriptor {
size: Extent3d {
width: 1,
height: 1,
depth_or_array_layers: 2,
},
format,
dimension: TextureDimension::D2,
label: Some("area_light_luts_placeholder"),
mip_level_count: 1,
sample_count: 1,
usage: TextureUsages::TEXTURE_BINDING,
view_formats: &[],
},
sampler: ImageSampler::Default,
texture_view_descriptor: Some(TextureViewDescriptor {
dimension: Some(TextureViewDimension::D2Array),
..Default::default()
}),
asset_usage: RenderAssetUsages::RENDER_WORLD,
copy_on_resize: false,
}
}

impl SyncComponent<PbrPlugin> for DirectionalLight {
type Target = (
Self,
Expand Down
Binary file added crates/bevy_pbr/src/ltc/ltc.ktx2
Binary file not shown.
Binary file removed crates/bevy_pbr/src/ltc/ltc1.ktx2
Binary file not shown.
Binary file removed crates/bevy_pbr/src/ltc/ltc2.ktx2
Binary file not shown.
3 changes: 3 additions & 0 deletions crates/bevy_pbr/src/render/mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3344,6 +3344,9 @@ impl SpecializedMeshPipeline for MeshPipeline {
if cfg!(feature = "dfg_lut") {
shader_defs.push("DFG_LUT".into());
}
if cfg!(feature = "area_light_luts") {
shader_defs.push("AREA_LIGHT_LUTS".into());
}

let bind_group_layout = self.get_view_layout(key.into());
let mut bind_group_layout = vec![
Expand Down
57 changes: 30 additions & 27 deletions crates/bevy_pbr/src/render/mesh_view_bindings.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
DfgLut, LtcLuts, ScreenSpaceTransmission, ViewEnvironmentMapUniformOffset,
AreaLightLuts, DfgLut, ScreenSpaceTransmission, ViewEnvironmentMapUniformOffset,
ViewFogUniformOffset, ViewLightProbesUniformOffset, ViewLightsUniformOffset,
ViewScreenSpaceReflectionsUniformOffset,
};
Expand Down Expand Up @@ -97,6 +97,7 @@ bitflags::bitflags! {
const SCREEN_SPACE_TRANSMISSION = 1 << 13;
const CONTACT_SHADOWS = 1 << 14;
const DISTANCE_FOG = 1 << 15;
const AREA_LIGHT_LUTS = 1 << 16;
}
}

Expand Down Expand Up @@ -150,6 +151,10 @@ impl From<MeshPipelineKey> for MeshPipelineViewLayoutKey {
result |= MeshPipelineViewLayoutKey::STBN;
}

if cfg!(feature = "area_light_luts") {
result |= MeshPipelineViewLayoutKey::AREA_LIGHT_LUTS;
}

if value.contains(MeshPipelineKey::TONEMAP_IN_SHADER) {
result |= MeshPipelineViewLayoutKey::TONEMAP_IN_SHADER;
}
Expand Down Expand Up @@ -462,25 +467,23 @@ fn layout_entries(
),));
}
// LTC LUTs for area lights
entries = entries.extend_with_indices((
(
36,
texture_2d(TextureSampleType::Float { filterable: true }),
),
(
37,
texture_2d(TextureSampleType::Float { filterable: true }),
),
(38, sampler(SamplerBindingType::Filtering)),
));
if cfg!(feature = "area_light_luts") {
entries = entries.extend_with_indices((
(
36,
texture_2d_array(TextureSampleType::Float { filterable: true }),
),
(37, sampler(SamplerBindingType::Filtering)),
));
}
// DFG LUT
if cfg!(feature = "dfg_lut") {
entries = entries.extend_with_indices((
(
39,
38,
texture_2d(TextureSampleType::Float { filterable: true }),
),
(40, sampler(SamplerBindingType::Filtering)),
(39, sampler(SamplerBindingType::Filtering)),
));
}

Expand Down Expand Up @@ -678,15 +681,15 @@ pub fn prepare_mesh_view_bind_groups(
atmosphere_buffer,
atmosphere_sampler,
blue_noise,
ltc_luts,
area_light_luts,
dfg_lut,
): (
Res<DecalsBuffer>,
Res<RenderClusteredDecals>,
Option<Res<AtmosphereBuffer>>,
Option<Res<AtmosphereSampler>>,
Res<Bluenoise>,
Res<LtcLuts>,
Res<AreaLightLuts>,
Res<DfgLut>,
),
// TODO: Figure out how to reuse the memory. `BindGroupEntry` is non-send on wasm with atomics.
Expand Down Expand Up @@ -896,24 +899,24 @@ pub fn prepare_mesh_view_bind_groups(
};

// LTC LUTs for area lights
let (ltc1_view, ltc_sampler) = images
.get(&ltc_luts.ltc_1)
.map(|img| (&img.texture_view, &img.sampler))
.unwrap_or((&fallback_image.d2.texture_view, &fallback_image.d2.sampler));
let ltc2_view = images
.get(&ltc_luts.ltc_2)
.map(|img| &img.texture_view)
.unwrap_or(&fallback_image.d2.texture_view);
entries =
entries.extend_with_indices(((36, ltc1_view), (37, ltc2_view), (38, ltc_sampler)));
if cfg!(feature = "area_light_luts") {
let (ltc_view, ltc_sampler) = images
.get(&area_light_luts.image)
.map(|img| (&img.texture_view, &img.sampler))
.unwrap_or((
&fallback_image.d2_array.texture_view,
&fallback_image.d2_array.sampler,
));
entries = entries.extend_with_indices(((36, ltc_view), (37, ltc_sampler)));
}

// DFG LUT
if cfg!(feature = "dfg_lut") {
let (dfg_view, dfg_sampler) = images
.get(&dfg_lut.texture)
.map(|img| (&img.texture_view, &img.sampler))
.unwrap_or((&fallback_image.d2.texture_view, &fallback_image.d2.sampler));
entries = entries.extend_with_indices(((39, dfg_view), (40, dfg_sampler)));
entries = entries.extend_with_indices(((38, dfg_view), (39, dfg_sampler)));
}

let environment_map_bind_group_entries =
Expand Down
Loading