Skip to content

Commit 0ff7c35

Browse files
beicausekfc35
andauthored
Gate LTC LUTs behind a feature and merge them to a texture array (#24065)
# Objective Alternative to #24004. #23288 adds ltc luts for rect light support which implicitly requires `bevy_image/ktx2` and `bevy_image/zstd` otherwise loading ltc luts will panic. We either accept to always enable area light supoort (#24004), or add a feature to opt out it (this PR). ## Solution Gate ltc luts behind a feature and merge them to a texture array. ## Testing `rect_light` example works. --------- Co-authored-by: Kevin Chen <chen.kevin.f@gmail.com>
1 parent 3f9bd6b commit 0ff7c35

18 files changed

Lines changed: 145 additions & 85 deletions

File tree

.github/workflows/example-run.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ jobs:
5252
example_name=`basename $example .ron`
5353
echo -n $example_name > last_example_run
5454
echo "running $example_name - "`date`
55-
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"
55+
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"
5656
sleep 10
5757
if [ `find ./ -maxdepth 1 -name 'screenshot-*.png' -print -quit` ]; then
5858
mkdir screenshots-$example_name
@@ -132,7 +132,7 @@ jobs:
132132
example_name=`basename $example .ron`
133133
echo -n $example_name > last_example_run
134134
echo "running $example_name - "`date`
135-
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"
135+
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"
136136
sleep 10
137137
if [ `find ./ -maxdepth 1 -name 'screenshot-*.png' -print -quit` ]; then
138138
mkdir screenshots-$example_name
@@ -202,7 +202,7 @@ jobs:
202202
example_name=`basename $example .ron`
203203
echo -n $example_name > last_example_run
204204
echo "running $example_name - "`date`
205-
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"
205+
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"
206206
sleep 10
207207
if [ `find ./ -maxdepth 1 -name 'screenshot-*.png' -print -quit` ]; then
208208
mkdir screenshots-$example_name

Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,9 @@ bluenoise_texture = ["bevy_internal/bluenoise_texture"]
579579
# Include a preintegrated BRDF Look Up Table for more accurate specular shading.
580580
dfg_lut = ["bevy_internal/dfg_lut"]
581581

582+
# Include Look Up Tables that are required for area lights.
583+
area_light_luts = ["bevy_internal/area_light_luts"]
584+
582585
# NVIDIA Deep Learning Super Sampling
583586
dlss = ["bevy_internal/dlss"]
584587

@@ -1195,7 +1198,7 @@ wasm = true
11951198
name = "rect_light"
11961199
path = "examples/3d/rect_light.rs"
11971200
doc-scrape-examples = true
1198-
required-features = ["free_camera"]
1201+
required-features = ["free_camera", "area_light_luts"]
11991202

12001203
[package.metadata.example.rect_light]
12011204
name = "Rectangular Area Light"
@@ -5209,6 +5212,7 @@ hidden = true
52095212
name = "testbed_3d"
52105213
path = "examples/testbed/3d.rs"
52115214
doc-scrape-examples = true
5215+
required-features = ["area_light_luts"]
52125216

52135217
[package.metadata.example.testbed_3d]
52145218
hidden = true

_release-content/release-notes/area_lights.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,6 @@ The implementation uses [Linearly Transformed Cosines](https://eheitzresearch.wo
1212

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

15+
You need to enable the `area_light_luts` cargo feature to use it.
16+
1517
Check out [the new example](https://github.com/bevyengine/bevy/tree/latest/examples/3d/rect_light.rs) to see them in action.

crates/bevy_internal/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ bluenoise_texture = ["bevy_pbr?/bluenoise_texture", "ktx2", "bevy_image/zstd"]
9090
# Include a preintegrated BRDF Look Up Table for more accurate specular shading.
9191
dfg_lut = ["bevy_pbr?/dfg_lut", "ktx2", "bevy_image/zstd"]
9292

93+
# Include Look Up Tables that are required for area lights.
94+
area_light_luts = ["bevy_pbr?/area_light_luts", "ktx2", "bevy_image/zstd"]
95+
9396
# NVIDIA Deep Learning Super Sampling
9497
dlss = ["bevy_anti_alias/dlss", "bevy_solari?/dlss"]
9598

crates/bevy_light/src/rect_light.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ use crate::light_consts;
1313
///
1414
/// Shadow maps are currently unsupported, objects illuminated by a
1515
/// ``RectLight`` will not cast shadows.
16+
///
17+
/// Note: Requires the `area_light_luts` cargo feature.
1618
#[derive(Component, Debug, Clone, Copy, Reflect)]
1719
#[reflect(Component, Default, Debug, Clone)]
1820
#[require(Transform, Visibility, VisibilityClass)]

crates/bevy_pbr/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ pbr_clustered_decals = []
2222
pbr_light_textures = []
2323
bluenoise_texture = ["bevy_image/ktx2", "bevy_image/zstd"]
2424
dfg_lut = ["bevy_image/ktx2", "bevy_image/zstd"]
25+
area_light_luts = ["bevy_image/ktx2", "bevy_image/zstd"]
2526
shader_format_glsl = ["bevy_shader/shader_format_glsl"]
2627
trace = ["bevy_render/trace"]
2728
# Enables the meshlet renderer for dense high-poly scenes (experimental)

crates/bevy_pbr/src/lib.rs

Lines changed: 64 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -107,14 +107,14 @@ use bevy_asset::{AssetApp, AssetPath, Assets, Handle, RenderAssetUsages};
107107
use bevy_core_pipeline::mip_generation::experimental::depth::early_downsample_depth;
108108
use bevy_core_pipeline::schedule::{Core3d, Core3dSystems};
109109
use bevy_ecs::prelude::*;
110-
use bevy_image::{CompressedImageFormats, Image, ImageSampler, ImageType};
110+
use bevy_image::{Image, ImageSampler};
111111
use bevy_material::AlphaMode;
112112
use bevy_render::{
113113
camera::sort_cameras,
114114
extract_resource::ExtractResourcePlugin,
115115
render_resource::{
116116
Extent3d, TextureDataOrder, TextureDescriptor, TextureDimension, TextureFormat,
117-
TextureUsages,
117+
TextureUsages, TextureViewDescriptor, TextureViewDimension,
118118
},
119119
sync_component::SyncComponentPlugin,
120120
ExtractSchedule, GpuResourceAppExt, Render, RenderApp, RenderDebugFlags, RenderStartup,
@@ -169,14 +169,14 @@ pub struct Bluenoise {
169169

170170
/// LTC (Linearly Transformed Cosines) LUT textures for area light shading.
171171
///
172-
/// `ltc_1` encodes the 4 non-trivial elements of the inverse GGX LTC matrix.
173-
/// `ltc_2` encodes amplitude and Fresnel-related weights.
172+
/// It is a texture array containing 2 LUT textures:
173+
/// The first entry encodes the 4 non-trivial elements of the inverse GGX LTC matrix.
174+
/// The second entry encodes amplitude and Fresnel-related weights.
174175
///
175176
/// [LUT source and fitting code](https://github.com/selfshadow/ltc_code/blob/master/fit/results)
176177
#[derive(Resource, Clone)]
177-
pub struct LtcLuts {
178-
pub ltc_1: Handle<Image>,
179-
pub ltc_2: Handle<Image>,
178+
pub struct AreaLightLuts {
179+
pub image: Handle<Image>,
180180
}
181181

182182
// See https://github.com/bevyengine/bevy/pull/23737 for information on how the LUT was generated.
@@ -282,15 +282,16 @@ impl Plugin for PbrPlugin {
282282
let mut images = app.world_mut().resource_mut::<Assets<Image>>();
283283
#[cfg(feature = "bluenoise_texture")]
284284
let handle = {
285-
let image = Image::from_buffer(
285+
let mut image = Image::from_buffer(
286286
include_bytes!("bluenoise/stbn.ktx2"),
287-
ImageType::Extension("ktx2"),
288-
CompressedImageFormats::NONE,
287+
bevy_image::ImageType::Extension("ktx2"),
288+
bevy_image::CompressedImageFormats::NONE,
289289
false,
290290
ImageSampler::Default,
291291
RenderAssetUsages::RENDER_WORLD,
292292
)
293293
.expect("Failed to decode embedded blue-noise texture");
294+
image.texture_descriptor.label = Some("bluenoise");
294295
images.add(image)
295296
};
296297

@@ -304,39 +305,32 @@ impl Plugin for PbrPlugin {
304305
}
305306
}
306307

307-
let has_ltc_luts = app
308+
let has_area_light_luts = app
308309
.get_sub_app(RenderApp)
309-
.is_some_and(|render_app| render_app.world().is_resource_added::<LtcLuts>());
310+
.is_some_and(|render_app| render_app.world().is_resource_added::<AreaLightLuts>());
310311

311-
if !has_ltc_luts {
312+
if !has_area_light_luts {
312313
let mut images = app.world_mut().resource_mut::<Assets<Image>>();
313-
let ltc_luts = LtcLuts {
314-
ltc_1: images.add(
315-
Image::from_buffer(
316-
include_bytes!("ltc/ltc1.ktx2"),
317-
ImageType::Extension("ktx2"),
318-
CompressedImageFormats::NONE,
319-
false,
320-
ImageSampler::linear(),
321-
RenderAssetUsages::RENDER_WORLD,
322-
)
323-
.expect("Failed to decode embedded LTC LUT 1"),
324-
),
325-
ltc_2: images.add(
326-
Image::from_buffer(
327-
include_bytes!("ltc/ltc2.ktx2"),
328-
ImageType::Extension("ktx2"),
329-
CompressedImageFormats::NONE,
330-
false,
331-
ImageSampler::linear(),
332-
RenderAssetUsages::RENDER_WORLD,
333-
)
334-
.expect("Failed to decode embedded LTC LUT 2"),
335-
),
314+
#[cfg(feature = "area_light_luts")]
315+
let handle = {
316+
let mut image = Image::from_buffer(
317+
include_bytes!("ltc/ltc.ktx2"),
318+
bevy_image::ImageType::Extension("ktx2"),
319+
bevy_image::CompressedImageFormats::NONE,
320+
false,
321+
ImageSampler::linear(),
322+
RenderAssetUsages::RENDER_WORLD,
323+
)
324+
.expect("Failed to decode embedded LTC LUTs");
325+
image.texture_descriptor.label = Some("area_light_luts");
326+
images.add(image)
336327
};
328+
#[cfg(not(feature = "area_light_luts"))]
329+
let handle = images.add(area_light_luts_placeholder());
337330

331+
let area_light_luts = AreaLightLuts { image: handle };
338332
if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
339-
render_app.world_mut().insert_resource(ltc_luts);
333+
render_app.world_mut().insert_resource(area_light_luts);
340334
}
341335
}
342336

@@ -349,8 +343,8 @@ impl Plugin for PbrPlugin {
349343
let texture = app.world_mut().resource_mut::<Assets<Image>>().add(
350344
Image::from_buffer(
351345
include_bytes!("environment_map/dfg.ktx2"),
352-
ImageType::Extension("ktx2"),
353-
CompressedImageFormats::NONE,
346+
bevy_image::ImageType::Extension("ktx2"),
347+
bevy_image::CompressedImageFormats::NONE,
354348
false,
355349
ImageSampler::linear(),
356350
RenderAssetUsages::RENDER_WORLD,
@@ -468,7 +462,7 @@ pub fn stbn_placeholder() -> Image {
468462
size: Extent3d::default(),
469463
format,
470464
dimension: TextureDimension::D2,
471-
label: None,
465+
label: Some("bluenoise_placeholder"),
472466
mip_level_count: 1,
473467
sample_count: 1,
474468
usage: TextureUsages::TEXTURE_BINDING,
@@ -481,6 +475,36 @@ pub fn stbn_placeholder() -> Image {
481475
}
482476
}
483477

478+
pub fn area_light_luts_placeholder() -> Image {
479+
let format = TextureFormat::Rgba16Float;
480+
let data = vec![0; 16];
481+
Image {
482+
data: Some(data),
483+
data_order: TextureDataOrder::default(),
484+
texture_descriptor: TextureDescriptor {
485+
size: Extent3d {
486+
width: 1,
487+
height: 1,
488+
depth_or_array_layers: 2,
489+
},
490+
format,
491+
dimension: TextureDimension::D2,
492+
label: Some("area_light_luts_placeholder"),
493+
mip_level_count: 1,
494+
sample_count: 1,
495+
usage: TextureUsages::TEXTURE_BINDING,
496+
view_formats: &[],
497+
},
498+
sampler: ImageSampler::Default,
499+
texture_view_descriptor: Some(TextureViewDescriptor {
500+
dimension: Some(TextureViewDimension::D2Array),
501+
..Default::default()
502+
}),
503+
asset_usage: RenderAssetUsages::RENDER_WORLD,
504+
copy_on_resize: false,
505+
}
506+
}
507+
484508
impl SyncComponent<PbrPlugin> for DirectionalLight {
485509
type Target = (
486510
Self,

crates/bevy_pbr/src/ltc/ltc.ktx2

45.1 KB
Binary file not shown.

crates/bevy_pbr/src/ltc/ltc1.ktx2

-28.1 KB
Binary file not shown.

crates/bevy_pbr/src/ltc/ltc2.ktx2

-16.9 KB
Binary file not shown.

0 commit comments

Comments
 (0)