Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
3 changes: 0 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -572,9 +572,6 @@ smaa_luts = ["bevy_internal/smaa_luts"]
# Include spatio-temporal blue noise KTX2 file used by generated environment maps, Solari and atmosphere
bluenoise_texture = ["bevy_internal/bluenoise_texture"]

# Include a preintegrated BRDF Look Up Table for more accurate specular shading.
dfg_lut = ["bevy_internal/dfg_lut"]

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

Expand Down
3 changes: 0 additions & 3 deletions crates/bevy_internal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,6 @@ smaa_luts = ["bevy_anti_alias?/smaa_luts", "ktx2", "bevy_image/zstd"]
# Include Bluenoise texture for environment map generation.
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"]

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

Expand Down
6 changes: 4 additions & 2 deletions crates/bevy_pbr/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ experimental_pbr_pcss = ["bevy_light/experimental_pbr_pcss"]
pbr_clustered_decals = []
pbr_light_textures = []
bluenoise_texture = ["bevy_image/ktx2", "bevy_image/zstd"]
dfg_lut = ["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 All @@ -47,7 +46,10 @@ bevy_ecs = { path = "../bevy_ecs", version = "0.19.0-dev" }
bevy_gltf = { path = "../bevy_gltf", version = "0.19.0-dev", optional = true }
bevy_light = { path = "../bevy_light", version = "0.19.0-dev" }
bevy_log = { path = "../bevy_log", version = "0.19.0-dev" }
bevy_image = { path = "../bevy_image", version = "0.19.0-dev" }
bevy_image = { path = "../bevy_image", version = "0.19.0-dev", features = [
"ktx2",
"zstd",
] }
bevy_mesh = { path = "../bevy_mesh", version = "0.19.0-dev", features = [
"morph",
"bevy_mikktspace",
Expand Down
Binary file removed crates/bevy_pbr/src/environment_map/dfg.ktx2
Binary file not shown.
81 changes: 23 additions & 58 deletions crates/bevy_pbr/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,23 +164,21 @@ pub struct Bluenoise {
pub texture: Handle<Image>,
}

/// LTC (Linearly Transformed Cosines) LUT textures for area light shading.
/// A texture array with 2 LTC LUT and 1 DFG LUT
///
/// Index 0 and 1: 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.
///
/// [LUT source and fitting code](https://github.com/selfshadow/ltc_code/blob/master/fit/results)
///
/// Index 2: The split-sum approximation LUT (`F_AB`) indexed by (`NdotV`, `perceptual_roughness`).
///
// See https://github.com/bevyengine/bevy/pull/23737 for information on how the DFG LUT was generated.
#[derive(Resource, Clone)]
pub struct LtcLuts {
pub ltc_1: Handle<Image>,
pub ltc_2: Handle<Image>,
}

// See https://github.com/bevyengine/bevy/pull/23737 for information on how the LUT was generated.
/// The split-sum approximation LUT (`F_AB`) indexed by (`NdotV`, `perceptual_roughness`).
#[derive(Resource, Clone)]
pub struct DfgLut {
pub texture: Handle<Image>,
pub struct LtcDfgLuts {
pub image: Handle<Image>,
}

impl Plugin for PbrPlugin {
Expand Down Expand Up @@ -279,7 +277,7 @@ 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,
Expand All @@ -288,6 +286,7 @@ impl Plugin for PbrPlugin {
RenderAssetUsages::RENDER_WORLD,
)
.expect("Failed to decode embedded blue-noise texture");
image.texture_descriptor.label = Some("bluenoise_texture");
images.add(image)
};

Expand All @@ -301,64 +300,30 @@ impl Plugin for PbrPlugin {
}
}

let has_ltc_luts = app
let has_ltc_dfg_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::<LtcDfgLuts>());

if !has_ltc_luts {
if !has_ltc_dfg_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"),
let ltc_dfg_luts = LtcDfgLuts {
image: images.add({
let mut img = Image::from_buffer(
include_bytes!("ltc_dfg/ltc_dfg.ktx2"),
ImageType::Extension("ktx2"),
CompressedImageFormats::NONE,
false,
ImageSampler::linear(),
RenderAssetUsages::RENDER_WORLD,
)
.expect("Failed to decode embedded LTC LUT 2"),
),
.expect("Failed to decode embedded LTC DFG LUT");
img.texture_descriptor.label = Some("ltc_dfg_luts");
img
}),
};

if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
render_app.world_mut().insert_resource(ltc_luts);
}
}

let has_dfg_lut = app
.get_sub_app(RenderApp)
.is_some_and(|render_app| render_app.world().is_resource_added::<DfgLut>());

if !has_dfg_lut {
#[cfg(feature = "dfg_lut")]
let texture = app.world_mut().resource_mut::<Assets<Image>>().add(
Image::from_buffer(
include_bytes!("environment_map/dfg.ktx2"),
ImageType::Extension("ktx2"),
CompressedImageFormats::NONE,
false,
ImageSampler::linear(),
RenderAssetUsages::RENDER_WORLD,
)
.expect("Failed to decode embedded DFG LUT"),
);
#[cfg(not(feature = "dfg_lut"))]
let texture = Handle::default();

if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
render_app.world_mut().insert_resource(DfgLut { texture });
render_app.world_mut().insert_resource(ltc_dfg_luts);
}
}

Expand Down
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.
Binary file added crates/bevy_pbr/src/ltc_dfg/ltc_dfg.ktx2
Binary file not shown.
3 changes: 0 additions & 3 deletions crates/bevy_pbr/src/render/mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3337,9 +3337,6 @@ impl SpecializedMeshPipeline for MeshPipeline {
if cfg!(feature = "bluenoise_texture") {
shader_defs.push("BLUE_NOISE_TEXTURE".into());
}
if cfg!(feature = "dfg_lut") {
shader_defs.push("DFG_LUT".into());
}

let bind_group_layout = self.get_view_layout(key.into());
let mut bind_group_layout = vec![
Expand Down
55 changes: 14 additions & 41 deletions crates/bevy_pbr/src/render/mesh_view_bindings.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{DfgLut, LtcLuts};
use crate::LtcDfgLuts;
use alloc::sync::Arc;
use bevy_core_pipeline::{
oit::{resolve::is_oit_supported, OitBuffers, OrderIndependentTransparencySettings},
Expand Down Expand Up @@ -436,28 +436,14 @@ pub fn layout_entries(
texture_2d_array(TextureSampleType::Float { filterable: false }),
),));
}
// LTC LUTs for area lights
// LTC LUTs for area lights and DFG LUT
entries = entries.extend_with_indices((
(
36,
texture_2d(TextureSampleType::Float { filterable: true }),
),
(
37,
texture_2d(TextureSampleType::Float { filterable: true }),
texture_2d_array(TextureSampleType::Float { filterable: true }),
),
(38, sampler(SamplerBindingType::Filtering)),
(37, sampler(SamplerBindingType::Filtering)),
));
// DFG LUT
if cfg!(feature = "dfg_lut") {
entries = entries.extend_with_indices((
(
39,
texture_2d(TextureSampleType::Float { filterable: true }),
),
(40, sampler(SamplerBindingType::Filtering)),
));
}
let mut binding_array_entries = DynamicBindGroupLayoutEntries::new(ShaderStages::FRAGMENT);
binding_array_entries = binding_array_entries.extend_with_indices((
(0, environment_map_entries[0]),
Expand Down Expand Up @@ -662,16 +648,14 @@ pub fn prepare_mesh_view_bind_groups(
atmosphere_buffer,
atmosphere_sampler,
blue_noise,
ltc_luts,
dfg_lut,
ltc_dfg_luts,
): (
Res<DecalsBuffer>,
Res<RenderClusteredDecals>,
Option<Res<AtmosphereBuffer>>,
Option<Res<AtmosphereSampler>>,
Res<Bluenoise>,
Res<LtcLuts>,
Res<DfgLut>,
Res<LtcDfgLuts>,
),
) {
if let (
Expand Down Expand Up @@ -843,26 +827,15 @@ pub fn prepare_mesh_view_bind_groups(
entries = entries.extend_with_indices(((35, stbn_view),));
}

// LTC LUTs for area lights
let (ltc1_view, ltc_sampler) = images
.get(&ltc_luts.ltc_1)
// LTC LUTs for area lights and DFG LUT.
let (ltc_dfg_view, ltc_dfg_sampler) = images
.get(&ltc_dfg_luts.image)
.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)));

// 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)));
}
.unwrap_or((
&fallback_image.d2_array.texture_view,
&fallback_image.d2_array.sampler,
));
entries = entries.extend_with_indices(((36, ltc_dfg_view), (37, ltc_dfg_sampler)));

let mut entries_binding_array = DynamicBindGroupEntries::new();

Expand Down
9 changes: 2 additions & 7 deletions crates/bevy_pbr/src/render/mesh_view_bindings.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,8 @@ const VISIBILITY_RANGE_UNIFORM_BUFFER_SIZE: u32 = 64u;
@group(0) @binding(35) var blue_noise_texture: texture_2d_array<f32>;
#endif // BLUE_NOISE_TEXTURE

@group(0) @binding(36) var ltc_lut1: texture_2d<f32>;
@group(0) @binding(37) var ltc_lut2: texture_2d<f32>;
@group(0) @binding(38) var ltc_lut_sampler: sampler;
#ifdef DFG_LUT
@group(0) @binding(39) var dfg_lut: texture_2d<f32>;
@group(0) @binding(40) var dfg_lut_sampler: sampler;
#endif // DFG_LUT
@group(0) @binding(36) var ltc_dfg_lut: texture_2d_array<f32>;
@group(0) @binding(37) var ltc_dfg_lut_sampler: sampler;

#ifdef MULTIPLE_LIGHT_PROBES_IN_ARRAY
@group(1) @binding(0) var diffuse_environment_maps: binding_array<texture_cube<f32>, 8u>;
Expand Down
21 changes: 5 additions & 16 deletions crates/bevy_pbr/src/render/pbr_lighting.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -527,18 +527,7 @@ fn Fd_Burley(

// Scale/bias approximation
fn F_AB(perceptual_roughness: f32, NdotV: f32) -> vec2<f32> {
#ifdef DFG_LUT
return textureSampleLevel(view_bindings::dfg_lut, view_bindings::dfg_lut_sampler, vec2<f32>(NdotV, perceptual_roughness), 0.0).rg;
#else
// Polynomial approximation, see https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile
let c0 = vec4<f32>(-1.0, -0.0275, -0.572, 0.022);
let c1 = vec4<f32>(1.0, 0.0425, 1.04, -0.04);
let r = perceptual_roughness * c0 + c1;
let a004 = min(r.x * r.x, exp2(-9.28 * NdotV)) * r.x + r.y;
// Keep F_ab positive to avoid divide-by-zero in downstream BRDF terms.
let f_ab_epsilon = 0.00005;
return max(vec2<f32>(-1.04, 1.04) * a004 + r.zw, vec2<f32>(f_ab_epsilon));
#endif
return textureSampleLevel(view_bindings::ltc_dfg_lut, view_bindings::ltc_dfg_lut_sampler, vec2<f32>(NdotV, perceptual_roughness), 2, 0.0).rg;
}

fn EnvBRDFApprox(F0: vec3<f32>, F_ab: vec2<f32>) -> vec3<f32> {
Expand Down Expand Up @@ -1046,8 +1035,8 @@ fn rect_light(
let LUT_SCALE = 63.0 / 64.0;
let LUT_BIAS = 0.5 / 64.0;
let uv = vec2<f32>(perceptual_roughness, sqrt(1.0 - NdotV)) * LUT_SCALE + LUT_BIAS;
let t1 = textureSampleLevel(view_bindings::ltc_lut1, view_bindings::ltc_lut_sampler, uv, 0.0);
let t2 = textureSampleLevel(view_bindings::ltc_lut2, view_bindings::ltc_lut_sampler, uv, 0.0);
let t1 = textureSampleLevel(view_bindings::ltc_dfg_lut, view_bindings::ltc_dfg_lut_sampler, uv, 0, 0.0);
let t2 = textureSampleLevel(view_bindings::ltc_dfg_lut, view_bindings::ltc_dfg_lut_sampler, uv, 1, 0.0);

// Reconstruct the GGX inverse-LTC matrix
let Minv = mat3x3<f32>(
Expand Down Expand Up @@ -1077,8 +1066,8 @@ fn rect_light(

// Sample LUTs for clearcoat layer
let cc_uv = vec2<f32>(clearcoat_perceptual_roughness, sqrt(1.0 - clearcoat_NdotV)) * LUT_SCALE + LUT_BIAS;
let tc1 = textureSampleLevel(view_bindings::ltc_lut1, view_bindings::ltc_lut_sampler, cc_uv, 0.0);
let tc2 = textureSampleLevel(view_bindings::ltc_lut2, view_bindings::ltc_lut_sampler, cc_uv, 0.0);
let tc1 = textureSampleLevel(view_bindings::ltc_dfg_lut, view_bindings::ltc_dfg_lut_sampler, cc_uv, 0, 0.0);
let tc2 = textureSampleLevel(view_bindings::ltc_dfg_lut, view_bindings::ltc_dfg_lut_sampler, cc_uv, 1, 0.0);
let Minv_cc = mat3x3<f32>(
vec3<f32>(tc1.x, 0.0, tc1.y),
vec3<f32>(0.0, 1.0, 0.0),
Expand Down
3 changes: 0 additions & 3 deletions crates/bevy_pbr/src/ssr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -574,9 +574,6 @@ impl SpecializedRenderPipeline for ScreenSpaceReflectionsPipeline {
if cfg!(feature = "bluenoise_texture") {
shader_defs.push("BLUE_NOISE_TEXTURE".into());
}
if cfg!(feature = "dfg_lut") {
shader_defs.push("DFG_LUT".into());
}

#[cfg(not(target_arch = "wasm32"))]
shader_defs.push("USE_DEPTH_SAMPLERS".into());
Expand Down
4 changes: 1 addition & 3 deletions crates/bevy_solari/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@ bevy_ecs = { path = "../bevy_ecs", version = "0.19.0-dev" }
bevy_shader = { path = "../bevy_shader", version = "0.19.0-dev" }
bevy_math = { path = "../bevy_math", version = "0.19.0-dev" }
bevy_mesh = { path = "../bevy_mesh", version = "0.19.0-dev" }
bevy_pbr = { path = "../bevy_pbr", version = "0.19.0-dev", features = [
"dfg_lut",
] }
bevy_pbr = { path = "../bevy_pbr", version = "0.19.0-dev" }
bevy_platform = { path = "../bevy_platform", version = "0.19.0-dev", default-features = false, features = [
"std",
] }
Expand Down
21 changes: 16 additions & 5 deletions crates/bevy_solari/src/scene/binder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ use bevy_ecs::{
};
use bevy_math::{ops::cos, Mat4, Vec3};
use bevy_pbr::{
DfgLut, ExtractedDirectionalLight, MeshMaterial3d, PreviousGlobalTransform, StandardMaterial,
ExtractedDirectionalLight, LtcDfgLuts, MeshMaterial3d, PreviousGlobalTransform,
StandardMaterial,
};
use bevy_platform::{collections::HashMap, hash::FixedHasher};
use bevy_render::{
Expand Down Expand Up @@ -48,7 +49,7 @@ pub fn prepare_raytracing_scene_bindings(
material_assets: Res<StandardMaterialAssets>,
texture_assets: Res<RenderAssets<GpuImage>>,
fallback_texture: Res<FallbackImage>,
dfg_lut: Res<DfgLut>,
ltc_dfg_luts: Res<LtcDfgLuts>,
render_device: Res<RenderDevice>,
pipeline_cache: Res<PipelineCache>,
render_queue: Res<RenderQueue>,
Expand Down Expand Up @@ -267,9 +268,19 @@ pub fn prepare_raytracing_scene_bindings(
command_encoder.build_acceleration_structures(&[], [&tlas]);
render_queue.submit([command_encoder.finish()]);

let (dfg_view, dfg_sampler) = texture_assets
.get(&dfg_lut.texture)
.map(|img| (&img.texture_view, &img.sampler))
let dfg_lut = texture_assets.get(&ltc_dfg_luts.image).map(|img| {
(
img.texture.create_view(&TextureViewDescriptor {
dimension: Some(TextureViewDimension::D2),
base_array_layer: 2,
..Default::default()
}),
&img.sampler,
)
});
let (dfg_view, dfg_sampler) = dfg_lut
.as_ref()
.map(|(dfg_view, sampler)| (dfg_view, *sampler))
.unwrap_or((
&fallback_texture.d2.texture_view,
&fallback_texture.d2.sampler,
Expand Down
1 change: 0 additions & 1 deletion docs/cargo_features.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ This is the complete `bevy` cargo feature list, without "profiles" or "collectio
|debug_glam_assert|Enable assertions in debug builds to check the validity of parameters passed to glam|
|default_font|Include a default font, containing only ASCII characters, at the cost of a 20kB binary size increase|
|detailed_trace|Enable detailed trace event logging. These trace events are expensive even when off, thus they require compile time opt-in|
|dfg_lut|Include a preintegrated BRDF Look Up Table for more accurate specular shading.|
|dlss|NVIDIA Deep Learning Super Sampling|
|dynamic_linking|Force dynamic linking, which improves iterative compile times|
|embedded_watcher|Enables watching in memory asset providers for Bevy Asset hot-reloading|
Expand Down