Address feedback naming

This commit is contained in:
Máté Homolya 2025-05-07 22:56:53 -07:00
parent 4f28f38f14
commit 937c738591
No known key found for this signature in database
10 changed files with 108 additions and 123 deletions

View File

@ -197,22 +197,6 @@ impl Image {
}) })
.map(DynamicImage::ImageRgba8) .map(DynamicImage::ImageRgba8)
} }
TextureFormat::Rgba16Float => {
use half::f16;
let pixel_count = (width * height) as usize;
let mut rgba32f_data = Vec::<f32>::with_capacity(pixel_count * 4);
for rgba16f in data.chunks_exact(8) {
let r = f16::from_bits(u16::from_le_bytes([rgba16f[0], rgba16f[1]])).to_f32();
let g = f16::from_bits(u16::from_le_bytes([rgba16f[2], rgba16f[3]])).to_f32();
let b = f16::from_bits(u16::from_le_bytes([rgba16f[4], rgba16f[5]])).to_f32();
let a = f16::from_bits(u16::from_le_bytes([rgba16f[6], rgba16f[7]])).to_f32();
rgba32f_data.push(r);
rgba32f_data.push(g);
rgba32f_data.push(b);
rgba32f_data.push(a);
}
ImageBuffer::from_raw(width, height, rgba32f_data).map(DynamicImage::ImageRgba32F)
}
// Throw and error if conversion isn't supported // Throw and error if conversion isn't supported
texture_format => return Err(IntoDynamicImageError::UnsupportedFormat(texture_format)), texture_format => return Err(IntoDynamicImageError::UnsupportedFormat(texture_format)),
} }

View File

@ -45,7 +45,6 @@ use bevy_ecs::{
schedule::IntoScheduleConfigs, schedule::IntoScheduleConfigs,
system::{lifetimeless::Read, Query}, system::{lifetimeless::Read, Query},
}; };
use bevy_image::Image;
use bevy_math::{UVec2, UVec3, Vec3}; use bevy_math::{UVec2, UVec3, Vec3};
use bevy_reflect::{std_traits::ReflectDefault, Reflect}; use bevy_reflect::{std_traits::ReflectDefault, Reflect};
use bevy_render::{ use bevy_render::{

View File

@ -1,7 +1,7 @@
#import bevy_render::maths::{PI, PI_2}; #import bevy_render::maths::{PI, PI_2};
#import bevy_pbr::lighting::perceptualRoughnessToRoughness; #import bevy_pbr::lighting::perceptualRoughnessToRoughness;
struct PrefilterConstants { struct FilteringConstants {
mip_level: f32, mip_level: f32,
sample_count: u32, sample_count: u32,
roughness: f32, roughness: f32,
@ -11,7 +11,7 @@ struct PrefilterConstants {
@group(0) @binding(0) var input_texture: texture_2d_array<f32>; @group(0) @binding(0) var input_texture: texture_2d_array<f32>;
@group(0) @binding(1) var input_sampler: sampler; @group(0) @binding(1) var input_sampler: sampler;
@group(0) @binding(2) var output_texture: texture_storage_2d_array<rgba16float, write>; @group(0) @binding(2) var output_texture: texture_storage_2d_array<rgba16float, write>;
@group(0) @binding(3) var<uniform> constants: PrefilterConstants; @group(0) @binding(3) var<uniform> constants: FilteringConstants;
@group(0) @binding(4) var blue_noise_texture: texture_2d<f32>; @group(0) @binding(4) var blue_noise_texture: texture_2d<f32>;
// Tonemapping functions to reduce fireflies // Tonemapping functions to reduce fireflies
@ -196,11 +196,12 @@ fn hammersley_2d(i: u32, n: u32) -> vec2f {
} }
// Blue noise randomization // Blue noise randomization
fn blue_noise_offset(pixel_coords: vec2u) -> vec2f { fn sample_noise(pixel_coords: vec2u) -> vec4f {
// Get a stable random offset for this pixel // Get a stable random offset for this pixel
let noise_size = vec2u(u32(constants.blue_noise_size.x), u32(constants.blue_noise_size.y)); let noise_size = vec2u(u32(constants.blue_noise_size.x), u32(constants.blue_noise_size.y));
let noise_coords = pixel_coords % noise_size; let noise_coords = pixel_coords % noise_size;
return textureSampleLevel(blue_noise_texture, input_sampler, vec2f(noise_coords) / constants.blue_noise_size, 0.0).rg; let uv = vec2f(noise_coords) / constants.blue_noise_size;
return textureSampleLevel(blue_noise_texture, input_sampler, uv, 0.0);
} }
// GGX/Trowbridge-Reitz normal distribution function (D term) // GGX/Trowbridge-Reitz normal distribution function (D term)
@ -279,7 +280,7 @@ fn generate_radiance_map(@builtin(global_invocation_id) global_id: vec3u) {
let roughness = constants.roughness; let roughness = constants.roughness;
// Get blue noise offset for stratification // Get blue noise offset for stratification
let blue_noise = blue_noise_offset(coords); let vector_noise = sample_noise(coords);
var radiance = vec3f(0.0); var radiance = vec3f(0.0);
var total_weight = 0.0; var total_weight = 0.0;
@ -297,7 +298,7 @@ fn generate_radiance_map(@builtin(global_invocation_id) global_id: vec3u) {
for (var i = 0u; i < sample_count; i++) { for (var i = 0u; i < sample_count; i++) {
// Get sample coordinates from Hammersley sequence with blue noise offset // Get sample coordinates from Hammersley sequence with blue noise offset
var xi = hammersley_2d(i, sample_count); var xi = hammersley_2d(i, sample_count);
xi = fract(xi + blue_noise); // Apply Cranley-Patterson rotation xi = fract(xi + vector_noise.rg); // Apply Cranley-Patterson rotation
// Sample the GGX distribution to get a half vector // Sample the GGX distribution to get a half vector
let half_vector = importance_sample_ggx(xi, roughness, normal); let half_vector = importance_sample_ggx(xi, roughness, normal);
@ -370,14 +371,11 @@ fn generate_irradiance_map(@builtin(global_invocation_id) global_id: vec3u) {
// Create tangent space matrix // Create tangent space matrix
let tangent_frame = calculate_tangent_frame(normal); let tangent_frame = calculate_tangent_frame(normal);
// Get blue noise offset for stratification
let blue_noise = blue_noise_offset(coords);
var irradiance = vec3f(0.0); var irradiance = vec3f(0.0);
var total_weight = 0.0; var total_weight = 0.0;
let sample_count = min(constants.sample_count, 64u); let sample_count = min(constants.sample_count, 64u);
for (var i = 0u; i < sample_count; i++) { for (var i = 0u; i < sample_count; i++) {
// Using a predefined set of directions provides good hemisphere coverage for diffuse // Using a predefined set of directions provides good hemisphere coverage for diffuse
var dir = get_uniform_direction((i + u32(coords.x * 7u + coords.y * 11u + face * 5u)) % 64u); var dir = get_uniform_direction((i + u32(coords.x * 7u + coords.y * 11u + face * 5u)) % 64u);
@ -419,9 +417,6 @@ fn generate_irradiance_map(@builtin(global_invocation_id) global_id: vec3u) {
irradiance = irradiance / total_weight * PI; irradiance = irradiance / total_weight * PI;
} }
// Add some low-frequency ambient term to avoid completely dark areas
irradiance = max(irradiance, vec3f(0.01, 0.01, 0.01));
// Write result to output texture // Write result to output texture
textureStore(output_texture, coords, face, vec4f(irradiance, 1.0)); textureStore(output_texture, coords, face, vec4f(irradiance, 1.0));
} }

View File

@ -30,33 +30,36 @@ use bevy_render::{
Extract, Extract,
}; };
use crate::atmosphere;
use crate::light_probe::environment_map::EnvironmentMapLight; use crate::light_probe::environment_map::EnvironmentMapLight;
/// A handle to the SPD (Single Pass Downsampling) shader. /// Single Pass Downsampling (SPD) shader handle
pub const SPD_SHADER_HANDLE: Handle<Shader> = weak_handle!("5dcf400c-bcb3-49b9-8b7e-80f4117eaf82"); pub const SPD_SHADER_HANDLE: Handle<Shader> = weak_handle!("5dcf400c-bcb3-49b9-8b7e-80f4117eaf82");
/// A handle to the environment filter shader. /// Environment Filter shader handle
pub const ENVIRONMENT_FILTER_SHADER_HANDLE: Handle<Shader> = pub const ENVIRONMENT_FILTER_SHADER_HANDLE: Handle<Shader> =
weak_handle!("3110b545-78e0-48fc-b86e-8bc0ea50fc67"); weak_handle!("3110b545-78e0-48fc-b86e-8bc0ea50fc67");
/// Labels for the prefiltering nodes /// Sphere Cosine Weighted Irradiance shader handle
pub const STBN_SPHERE: Handle<Image> = weak_handle!("3110b545-78e0-48fc-b86e-8bc0ea50fc67");
pub const STBN_VEC2: Handle<Image> = weak_handle!("3110b545-78e0-48fc-b86e-8bc0ea50fc67");
/// Labels for the environment map generation nodes
#[derive(PartialEq, Eq, Debug, Copy, Clone, Hash, RenderLabel)] #[derive(PartialEq, Eq, Debug, Copy, Clone, Hash, RenderLabel)]
pub enum PrefilterNode { pub enum GeneratorNode {
GenerateMipmap, Mipmap,
RadianceMap, Radiance,
IrradianceMap, Irradiance,
} }
/// Stores the bind group layouts for the prefiltering process /// Stores the bind group layouts for the environment map generation pipelines
#[derive(Resource)] #[derive(Resource)]
pub struct PrefilterBindGroupLayouts { pub struct GeneratorBindGroupLayouts {
pub spd: BindGroupLayout, pub spd: BindGroupLayout,
pub radiance: BindGroupLayout, pub radiance: BindGroupLayout,
pub irradiance: BindGroupLayout, pub irradiance: BindGroupLayout,
} }
impl FromWorld for PrefilterBindGroupLayouts { impl FromWorld for GeneratorBindGroupLayouts {
fn from_world(world: &mut World) -> Self { fn from_world(world: &mut World) -> Self {
let render_device = world.resource::<RenderDevice>(); let render_device = world.resource::<RenderDevice>();
@ -178,7 +181,7 @@ impl FromWorld for PrefilterBindGroupLayouts {
StorageTextureAccess::WriteOnly, StorageTextureAccess::WriteOnly,
), ),
), // Output specular map ), // Output specular map
(3, uniform_buffer::<PrefilterConstants>(false)), // Uniforms (3, uniform_buffer::<FilteringConstants>(false)), // Uniforms
(4, texture_2d(TextureSampleType::Float { filterable: true })), // Blue noise texture (4, texture_2d(TextureSampleType::Float { filterable: true })), // Blue noise texture
), ),
), ),
@ -202,7 +205,7 @@ impl FromWorld for PrefilterBindGroupLayouts {
StorageTextureAccess::WriteOnly, StorageTextureAccess::WriteOnly,
), ),
), // Output irradiance map ), // Output irradiance map
(3, uniform_buffer::<PrefilterConstants>(false)), // Uniforms (3, uniform_buffer::<FilteringConstants>(false)), // Uniforms
(4, texture_2d(TextureSampleType::Float { filterable: true })), // Blue noise texture (4, texture_2d(TextureSampleType::Float { filterable: true })), // Blue noise texture
), ),
), ),
@ -216,18 +219,18 @@ impl FromWorld for PrefilterBindGroupLayouts {
} }
} }
/// Samplers for the prefiltering process /// Samplers for the environment map generation pipelines
#[derive(Resource)] #[derive(Resource)]
pub struct PrefilterSamplers { pub struct GeneratorSamplers {
pub linear: Sampler, pub linear: Sampler,
} }
impl FromWorld for PrefilterSamplers { impl FromWorld for GeneratorSamplers {
fn from_world(world: &mut World) -> Self { fn from_world(world: &mut World) -> Self {
let render_device = world.resource::<RenderDevice>(); let render_device = world.resource::<RenderDevice>();
let linear = render_device.create_sampler(&SamplerDescriptor { let linear = render_device.create_sampler(&SamplerDescriptor {
label: Some("prefilter_linear_sampler"), label: Some("generator_linear_sampler"),
address_mode_u: AddressMode::ClampToEdge, address_mode_u: AddressMode::ClampToEdge,
address_mode_v: AddressMode::ClampToEdge, address_mode_v: AddressMode::ClampToEdge,
address_mode_w: AddressMode::ClampToEdge, address_mode_w: AddressMode::ClampToEdge,
@ -241,19 +244,19 @@ impl FromWorld for PrefilterSamplers {
} }
} }
/// Pipelines for the prefiltering process /// Pipelines for the environment map generation pipelines
#[derive(Resource)] #[derive(Resource)]
pub struct PrefilterPipelines { pub struct GeneratorPipelines {
pub spd_first: CachedComputePipelineId, pub spd_first: CachedComputePipelineId,
pub spd_second: CachedComputePipelineId, pub spd_second: CachedComputePipelineId,
pub radiance: CachedComputePipelineId, pub radiance: CachedComputePipelineId,
pub irradiance: CachedComputePipelineId, pub irradiance: CachedComputePipelineId,
} }
impl FromWorld for PrefilterPipelines { impl FromWorld for GeneratorPipelines {
fn from_world(world: &mut World) -> Self { fn from_world(world: &mut World) -> Self {
let pipeline_cache = world.resource::<PipelineCache>(); let pipeline_cache = world.resource::<PipelineCache>();
let layouts = world.resource::<PrefilterBindGroupLayouts>(); let layouts = world.resource::<GeneratorBindGroupLayouts>();
let render_device = world.resource::<RenderDevice>(); let render_device = world.resource::<RenderDevice>();
let features = render_device.features(); let features = render_device.features();
@ -317,16 +320,16 @@ impl FromWorld for PrefilterPipelines {
} }
#[derive(Component, Clone, Reflect, ExtractComponent)] #[derive(Component, Clone, Reflect, ExtractComponent)]
pub struct FilteredEnvironmentMapLight { pub struct GeneratedEnvironmentMapLight {
pub environment_map: Handle<Image>, pub environment_map: Handle<Image>,
pub intensity: f32, pub intensity: f32,
pub rotation: Quat, pub rotation: Quat,
pub affects_lightmapped_mesh_diffuse: bool, pub affects_lightmapped_mesh_diffuse: bool,
} }
impl Default for FilteredEnvironmentMapLight { impl Default for GeneratedEnvironmentMapLight {
fn default() -> Self { fn default() -> Self {
FilteredEnvironmentMapLight { GeneratedEnvironmentMapLight {
environment_map: Handle::default(), environment_map: Handle::default(),
intensity: 0.0, intensity: 0.0,
rotation: Quat::IDENTITY, rotation: Quat::IDENTITY,
@ -335,18 +338,18 @@ impl Default for FilteredEnvironmentMapLight {
} }
} }
pub fn extract_prefilter_entities( pub fn extract_generator_entities(
prefilter_query: Extract< query: Extract<
Query<( Query<(
RenderEntity, RenderEntity,
&FilteredEnvironmentMapLight, &GeneratedEnvironmentMapLight,
&EnvironmentMapLight, &EnvironmentMapLight,
)>, )>,
>, >,
mut commands: Commands, mut commands: Commands,
render_images: Res<RenderAssets<GpuImage>>, render_images: Res<RenderAssets<GpuImage>>,
) { ) {
for (entity, filtered_env_map, env_map_light) in prefilter_query.iter() { for (entity, filtered_env_map, env_map_light) in query.iter() {
let env_map = render_images let env_map = render_images
.get(&filtered_env_map.environment_map) .get(&filtered_env_map.environment_map)
.expect("Environment map not found"); .expect("Environment map not found");
@ -389,12 +392,12 @@ pub struct RenderEnvironmentMap {
} }
#[derive(Component)] #[derive(Component)]
pub struct PrefilterTextures { pub struct IntermediateTextures {
pub environment_map: CachedTexture, pub environment_map: CachedTexture,
} }
/// Prepares textures needed for prefiltering /// Prepares textures needed for single pass downsampling
pub fn prepare_prefilter_textures( pub fn prepare_intermediate_textures(
light_probes: Query<Entity, With<RenderEnvironmentMap>>, light_probes: Query<Entity, With<RenderEnvironmentMap>>,
render_device: Res<RenderDevice>, render_device: Res<RenderDevice>,
mut texture_cache: ResMut<TextureCache>, mut texture_cache: ResMut<TextureCache>,
@ -405,7 +408,7 @@ pub fn prepare_prefilter_textures(
let environment_map = texture_cache.get( let environment_map = texture_cache.get(
&render_device, &render_device,
TextureDescriptor { TextureDescriptor {
label: Some("prefilter_environment_map"), label: Some("intermediate_environment_map"),
size: Extent3d { size: Extent3d {
width: 512, width: 512,
height: 512, height: 512,
@ -424,7 +427,7 @@ pub fn prepare_prefilter_textures(
commands commands
.entity(entity) .entity(entity)
.insert(PrefilterTextures { environment_map }); .insert(IntermediateTextures { environment_map });
} }
} }
@ -437,41 +440,45 @@ pub struct SpdConstants {
_padding: u32, _padding: u32,
} }
/// Constants for prefiltering /// Constants for filtering
#[derive(Clone, Copy, ShaderType)] #[derive(Clone, Copy, ShaderType)]
#[repr(C)] #[repr(C)]
pub struct PrefilterConstants { pub struct FilteringConstants {
mip_level: f32, mip_level: f32,
sample_count: u32, sample_count: u32,
roughness: f32, roughness: f32,
blue_noise_size: Vec2, blue_noise_size: Vec2,
} }
/// Stores bind groups for the prefiltering process /// Stores bind groups for the environment map generation pipelines
#[derive(Component)] #[derive(Component)]
pub struct PrefilterBindGroups { pub struct GeneratorBindGroups {
pub spd: BindGroup, pub spd: BindGroup,
pub radiance: Vec<BindGroup>, // One per mip level pub radiance: Vec<BindGroup>, // One per mip level
pub irradiance: BindGroup, pub irradiance: BindGroup,
} }
/// Prepares bind groups for prefiltering /// Prepares bind groups for environment map generation pipelines
pub fn prepare_prefilter_bind_groups( pub fn prepare_generator_bind_groups(
light_probes: Query< light_probes: Query<
(Entity, &PrefilterTextures, &RenderEnvironmentMap), (Entity, &IntermediateTextures, &RenderEnvironmentMap),
With<RenderEnvironmentMap>, With<RenderEnvironmentMap>,
>, >,
render_device: Res<RenderDevice>, render_device: Res<RenderDevice>,
queue: Res<RenderQueue>, queue: Res<RenderQueue>,
layouts: Res<PrefilterBindGroupLayouts>, layouts: Res<GeneratorBindGroupLayouts>,
samplers: Res<PrefilterSamplers>, samplers: Res<GeneratorSamplers>,
render_images: Res<RenderAssets<GpuImage>>, render_images: Res<RenderAssets<GpuImage>>,
mut commands: Commands, mut commands: Commands,
) { ) {
// Get blue noise texture // Get blue noise texture
let blue_noise_texture = render_images let sphere_cosine_weights = render_images
.get(&atmosphere::shaders::BLUENOISE_TEXTURE) .get(&STBN_SPHERE)
.expect("Blue noise texture not loaded"); .expect("Sphere cosine weights texture not loaded");
let vector2_uniform = render_images
.get(&STBN_VEC2)
.expect("Vector2 uniform texture not loaded");
for (entity, textures, env_map_light) in &light_probes { for (entity, textures, env_map_light) in &light_probes {
// Create SPD bind group // Create SPD bind group
@ -571,13 +578,13 @@ pub fn prepare_prefilter_bind_groups(
128 128
}; };
let radiance_constants = PrefilterConstants { let radiance_constants = FilteringConstants {
mip_level: mip as f32, mip_level: mip as f32,
sample_count, sample_count,
roughness, roughness,
blue_noise_size: Vec2::new( blue_noise_size: Vec2::new(
blue_noise_texture.size.width as f32, vector2_uniform.size.width as f32,
blue_noise_texture.size.height as f32, vector2_uniform.size.height as f32,
), ),
}; };
@ -597,7 +604,7 @@ pub fn prepare_prefilter_bind_groups(
(1, &samplers.linear), (1, &samplers.linear),
(2, &mip_storage_view), (2, &mip_storage_view),
(3, &radiance_constants_buffer), (3, &radiance_constants_buffer),
(4, &blue_noise_texture.texture_view), (4, &vector2_uniform.texture_view),
)), )),
); );
@ -605,13 +612,13 @@ pub fn prepare_prefilter_bind_groups(
} }
// Create irradiance bind group // Create irradiance bind group
let irradiance_constants = PrefilterConstants { let irradiance_constants = FilteringConstants {
mip_level: 0.0, mip_level: 0.0,
sample_count: 64, sample_count: 64,
roughness: 1.0, roughness: 1.0,
blue_noise_size: Vec2::new( blue_noise_size: Vec2::new(
blue_noise_texture.size.width as f32, sphere_cosine_weights.size.width as f32,
blue_noise_texture.size.height as f32, sphere_cosine_weights.size.height as f32,
), ),
}; };
@ -636,11 +643,11 @@ pub fn prepare_prefilter_bind_groups(
(1, &samplers.linear), (1, &samplers.linear),
(2, &irradiance_map), (2, &irradiance_map),
(3, &irradiance_constants_buffer), (3, &irradiance_constants_buffer),
(4, &blue_noise_texture.texture_view), (4, &sphere_cosine_weights.texture_view),
)), )),
); );
commands.entity(entity).insert(PrefilterBindGroups { commands.entity(entity).insert(GeneratorBindGroups {
spd: spd_bind_group, spd: spd_bind_group,
radiance: radiance_bind_groups, radiance: radiance_bind_groups,
irradiance: irradiance_bind_group, irradiance: irradiance_bind_group,
@ -667,7 +674,7 @@ fn create_storage_view(texture: &Texture, mip: u32, _render_device: &RenderDevic
pub struct SpdNode { pub struct SpdNode {
query: QueryState<( query: QueryState<(
Entity, Entity,
Read<PrefilterBindGroups>, Read<GeneratorBindGroups>,
Read<RenderEnvironmentMap>, Read<RenderEnvironmentMap>,
)>, )>,
} }
@ -692,7 +699,7 @@ impl Node for SpdNode {
world: &World, world: &World,
) -> Result<(), NodeRunError> { ) -> Result<(), NodeRunError> {
let pipeline_cache = world.resource::<PipelineCache>(); let pipeline_cache = world.resource::<PipelineCache>();
let pipelines = world.resource::<PrefilterPipelines>(); let pipelines = world.resource::<GeneratorPipelines>();
// First pass (mips 0-5) // First pass (mips 0-5)
let Some(spd_first_pipeline) = pipeline_cache.get_compute_pipeline(pipelines.spd_first) let Some(spd_first_pipeline) = pipeline_cache.get_compute_pipeline(pipelines.spd_first)
@ -708,7 +715,7 @@ impl Node for SpdNode {
for (entity, bind_groups, env_map_light) in self.query.iter_manual(world) { for (entity, bind_groups, env_map_light) in self.query.iter_manual(world) {
// Copy original environment map to mip 0 of the intermediate environment map // Copy original environment map to mip 0 of the intermediate environment map
let textures = world.get::<PrefilterTextures>(entity).unwrap(); let textures = world.get::<IntermediateTextures>(entity).unwrap();
render_context.command_encoder().copy_texture_to_texture( render_context.command_encoder().copy_texture_to_texture(
env_map_light.environment_map.texture.as_image_copy(), env_map_light.environment_map.texture.as_image_copy(),
@ -764,7 +771,7 @@ impl Node for SpdNode {
/// Radiance map node for generating specular environment maps /// Radiance map node for generating specular environment maps
pub struct RadianceMapNode { pub struct RadianceMapNode {
query: QueryState<(Entity, Read<PrefilterBindGroups>)>, query: QueryState<(Entity, Read<GeneratorBindGroups>)>,
} }
impl FromWorld for RadianceMapNode { impl FromWorld for RadianceMapNode {
@ -787,7 +794,7 @@ impl Node for RadianceMapNode {
world: &World, world: &World,
) -> Result<(), NodeRunError> { ) -> Result<(), NodeRunError> {
let pipeline_cache = world.resource::<PipelineCache>(); let pipeline_cache = world.resource::<PipelineCache>();
let pipelines = world.resource::<PrefilterPipelines>(); let pipelines = world.resource::<GeneratorPipelines>();
let Some(radiance_pipeline) = pipeline_cache.get_compute_pipeline(pipelines.radiance) let Some(radiance_pipeline) = pipeline_cache.get_compute_pipeline(pipelines.radiance)
else { else {
@ -824,7 +831,7 @@ impl Node for RadianceMapNode {
/// Irradiance Convolution Node /// Irradiance Convolution Node
pub struct IrradianceMapNode { pub struct IrradianceMapNode {
query: QueryState<(Entity, Read<PrefilterBindGroups>)>, query: QueryState<(Entity, Read<GeneratorBindGroups>)>,
} }
impl FromWorld for IrradianceMapNode { impl FromWorld for IrradianceMapNode {
@ -847,7 +854,7 @@ impl Node for IrradianceMapNode {
world: &World, world: &World,
) -> Result<(), NodeRunError> { ) -> Result<(), NodeRunError> {
let pipeline_cache = world.resource::<PipelineCache>(); let pipeline_cache = world.resource::<PipelineCache>();
let pipelines = world.resource::<PrefilterPipelines>(); let pipelines = world.resource::<GeneratorPipelines>();
let Some(irradiance_pipeline) = pipeline_cache.get_compute_pipeline(pipelines.irradiance) let Some(irradiance_pipeline) = pipeline_cache.get_compute_pipeline(pipelines.irradiance)
else { else {
@ -874,11 +881,11 @@ impl Node for IrradianceMapNode {
} }
} }
/// System that creates an `EnvironmentMapLight` component from the prefiltered textures /// System that generates an `EnvironmentMapLight` component based on the `GeneratedEnvironmentMapLight` component
pub fn create_environment_map_from_prefilter( pub fn generate_environment_map_light(
mut commands: Commands, mut commands: Commands,
mut images: ResMut<Assets<Image>>, mut images: ResMut<Assets<Image>>,
query: Query<(Entity, &FilteredEnvironmentMapLight), Without<EnvironmentMapLight>>, query: Query<(Entity, &GeneratedEnvironmentMapLight), Without<EnvironmentMapLight>>,
) { ) {
for (entity, filtered_env_map) in &query { for (entity, filtered_env_map) in &query {
// Create a placeholder for the irradiance map // Create a placeholder for the irradiance map

View File

@ -126,7 +126,7 @@
//! //!
//! [Blender]: http://blender.org/ //! [Blender]: http://blender.org/
//! //!
//! [baking tool]: https://docs.blender.org/manual/en/latest/render/eevee/render_settings/indirect_lighting.html //! [baking tool]: https://docs.blender.org/manual/en/latest/render/eevee/light_probes/volume.html
//! //!
//! [`bevy-baked-gi`]: https://github.com/pcwalton/bevy-baked-gi //! [`bevy-baked-gi`]: https://github.com/pcwalton/bevy-baked-gi
//! //!

View File

@ -31,10 +31,10 @@ use bevy_render::{
Extract, ExtractSchedule, Render, RenderApp, RenderSystems, Extract, ExtractSchedule, Render, RenderApp, RenderSystems,
}; };
use bevy_transform::{components::Transform, prelude::GlobalTransform}; use bevy_transform::{components::Transform, prelude::GlobalTransform};
use prefilter::{ use generate::{
create_environment_map_from_prefilter, extract_prefilter_entities, extract_generator_entities, generate_environment_map_light, prepare_generator_bind_groups,
prepare_prefilter_bind_groups, prepare_prefilter_textures, FilteredEnvironmentMapLight, prepare_intermediate_textures, GeneratedEnvironmentMapLight, GeneratorPipelines, SpdNode,
PrefilterPipelines, SpdNode, STBN_SPHERE, STBN_VEC2,
}; };
use tracing::error; use tracing::error;
@ -45,8 +45,8 @@ use crate::light_probe::environment_map::{EnvironmentMapIds, EnvironmentMapLight
use self::irradiance_volume::IrradianceVolume; use self::irradiance_volume::IrradianceVolume;
pub mod environment_map; pub mod environment_map;
pub mod generate;
pub mod irradiance_volume; pub mod irradiance_volume;
pub mod prefilter;
/// The maximum number of each type of light probe that each view will consider. /// The maximum number of each type of light probe that each view will consider.
/// ///
@ -350,8 +350,8 @@ impl Plugin for LightProbePlugin {
app.register_type::<LightProbe>() app.register_type::<LightProbe>()
.register_type::<EnvironmentMapLight>() .register_type::<EnvironmentMapLight>()
.register_type::<IrradianceVolume>() .register_type::<IrradianceVolume>()
.add_plugins(ExtractComponentPlugin::<FilteredEnvironmentMapLight>::default()) .add_plugins(ExtractComponentPlugin::<GeneratedEnvironmentMapLight>::default())
.add_systems(Update, create_environment_map_from_prefilter); .add_systems(Update, generate_environment_map_light);
} }
fn finish(&self, app: &mut App) { fn finish(&self, app: &mut App) {
@ -363,19 +363,19 @@ impl Plugin for LightProbePlugin {
.add_plugins(ExtractInstancesPlugin::<EnvironmentMapIds>::new()) .add_plugins(ExtractInstancesPlugin::<EnvironmentMapIds>::new())
.init_resource::<LightProbesBuffer>() .init_resource::<LightProbesBuffer>()
.init_resource::<EnvironmentMapUniformBuffer>() .init_resource::<EnvironmentMapUniformBuffer>()
.init_resource::<PrefilterBindGroupLayouts>() .init_resource::<GeneratorBindGroupLayouts>()
.init_resource::<PrefilterSamplers>() .init_resource::<GeneratorSamplers>()
.init_resource::<PrefilterPipelines>() .init_resource::<GeneratorPipelines>()
.add_render_graph_node::<SpdNode>(Core3d, PrefilterNode::GenerateMipmap) .add_render_graph_node::<SpdNode>(Core3d, GeneratorNode::Mipmap)
.add_render_graph_node::<RadianceMapNode>(Core3d, PrefilterNode::RadianceMap) .add_render_graph_node::<RadianceMapNode>(Core3d, GeneratorNode::Radiance)
.add_render_graph_node::<IrradianceMapNode>(Core3d, PrefilterNode::IrradianceMap) .add_render_graph_node::<IrradianceMapNode>(Core3d, GeneratorNode::Irradiance)
.add_render_graph_edges( .add_render_graph_edges(
Core3d, Core3d,
( (
Node3d::EndPrepasses, Node3d::EndPrepasses,
PrefilterNode::GenerateMipmap, GeneratorNode::Mipmap,
PrefilterNode::RadianceMap, GeneratorNode::Radiance,
PrefilterNode::IrradianceMap, GeneratorNode::Irradiance,
Node3d::StartMainPass, Node3d::StartMainPass,
), ),
) )
@ -384,7 +384,7 @@ impl Plugin for LightProbePlugin {
.add_systems(ExtractSchedule, gather_light_probes::<IrradianceVolume>) .add_systems(ExtractSchedule, gather_light_probes::<IrradianceVolume>)
.add_systems( .add_systems(
ExtractSchedule, ExtractSchedule,
extract_prefilter_entities.after(create_environment_map_from_prefilter), extract_generator_entities.after(generate_environment_map_light),
) )
.add_systems( .add_systems(
Render, Render,

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

View File

@ -39,8 +39,8 @@ enum ReflectionMode {
// Both a world environment map and a reflection probe are present. The // Both a world environment map and a reflection probe are present. The
// reflection probe is shown in the sphere. // reflection probe is shown in the sphere.
ReflectionProbe = 2, ReflectionProbe = 2,
// A prefiltered environment map is shown. // A generated environment map is shown.
PrefilteredEnvironmentMap = 3, GeneratedEnvironmentMap = 3,
} }
// The various reflection maps. // The various reflection maps.
@ -133,7 +133,7 @@ fn spawn_sphere(
commands.spawn(( commands.spawn((
Mesh3d(sphere_mesh.clone()), Mesh3d(sphere_mesh.clone()),
MeshMaterial3d(materials.add(StandardMaterial { MeshMaterial3d(materials.add(StandardMaterial {
base_color: Srgba::hex("#ffd891").unwrap().into(), base_color: Srgba::hex("#ffffff").unwrap().into(),
metallic: 1.0, metallic: 1.0,
perceptual_roughness: app_status.sphere_roughness, perceptual_roughness: app_status.sphere_roughness,
..StandardMaterial::default() ..StandardMaterial::default()
@ -157,10 +157,10 @@ fn spawn_reflection_probe(commands: &mut Commands, cubemaps: &Cubemaps) {
)); ));
} }
fn spawn_prefiltered_environment_map(commands: &mut Commands, cubemaps: &Cubemaps) { fn spawn_generated_environment_map(commands: &mut Commands, cubemaps: &Cubemaps) {
commands.spawn(( commands.spawn((
LightProbe, LightProbe,
FilteredEnvironmentMapLight { GeneratedEnvironmentMapLight {
environment_map: cubemaps.unfiltered_environment_map.clone(), environment_map: cubemaps.unfiltered_environment_map.clone(),
intensity: 5000.0, intensity: 5000.0,
..default() ..default()
@ -232,8 +232,8 @@ fn change_reflection_type(
match app_status.reflection_mode { match app_status.reflection_mode {
ReflectionMode::None | ReflectionMode::EnvironmentMap => {} ReflectionMode::None | ReflectionMode::EnvironmentMap => {}
ReflectionMode::ReflectionProbe => spawn_reflection_probe(&mut commands, &cubemaps), ReflectionMode::ReflectionProbe => spawn_reflection_probe(&mut commands, &cubemaps),
ReflectionMode::PrefilteredEnvironmentMap => { ReflectionMode::GeneratedEnvironmentMap => {
spawn_prefiltered_environment_map(&mut commands, &cubemaps); spawn_generated_environment_map(&mut commands, &cubemaps);
} }
} }
@ -245,9 +245,9 @@ fn change_reflection_type(
} }
ReflectionMode::EnvironmentMap ReflectionMode::EnvironmentMap
| ReflectionMode::ReflectionProbe | ReflectionMode::ReflectionProbe
| ReflectionMode::PrefilteredEnvironmentMap => { | ReflectionMode::GeneratedEnvironmentMap => {
let image = match app_status.reflection_mode { let image = match app_status.reflection_mode {
ReflectionMode::PrefilteredEnvironmentMap => { ReflectionMode::GeneratedEnvironmentMap => {
cubemaps.unfiltered_environment_map.clone() cubemaps.unfiltered_environment_map.clone()
} }
_ => cubemaps.skybox.clone(), _ => cubemaps.skybox.clone(),
@ -287,7 +287,7 @@ impl TryFrom<u32> for ReflectionMode {
0 => Ok(ReflectionMode::None), 0 => Ok(ReflectionMode::None),
1 => Ok(ReflectionMode::EnvironmentMap), 1 => Ok(ReflectionMode::EnvironmentMap),
2 => Ok(ReflectionMode::ReflectionProbe), 2 => Ok(ReflectionMode::ReflectionProbe),
3 => Ok(ReflectionMode::PrefilteredEnvironmentMap), 3 => Ok(ReflectionMode::GeneratedEnvironmentMap),
_ => Err(()), _ => Err(()),
} }
} }
@ -299,7 +299,7 @@ impl Display for ReflectionMode {
ReflectionMode::None => "No reflections", ReflectionMode::None => "No reflections",
ReflectionMode::EnvironmentMap => "Environment map", ReflectionMode::EnvironmentMap => "Environment map",
ReflectionMode::ReflectionProbe => "Reflection probe", ReflectionMode::ReflectionProbe => "Reflection probe",
ReflectionMode::PrefilteredEnvironmentMap => "Prefiltered environment map", ReflectionMode::GeneratedEnvironmentMap => "Generated environment map",
}; };
formatter.write_str(text) formatter.write_str(text)
} }