Address feedback naming
This commit is contained in:
parent
4f28f38f14
commit
937c738591
@ -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)),
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
@ -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::{
|
||||||
|
|||||||
@ -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,9 +371,6 @@ 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;
|
||||||
|
|
||||||
@ -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));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
@ -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
|
||||||
//!
|
//!
|
||||||
|
|||||||
@ -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 |
@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user