Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
97f84a1
Attempt at PBR integration WIP
mate-h Feb 7, 2025
11c20a5
Fix compilation errors and add bindings
mate-h Feb 9, 2025
bf0c82b
Align to 16 and pass in atmosphere transform
mate-h Feb 9, 2025
08b2a69
Directional light transmittance
mate-h Feb 10, 2025
b4a3e9c
Atmosphere flag in binding and mesh pipeline layout key
mate-h Feb 11, 2025
28b8b68
Lighting calculations relative to position in atmosphere
mate-h Feb 12, 2025
f00c775
Atmosphere shader testing
mate-h Feb 12, 2025
2fbb447
Clamp to bottom atmosphere radius
mate-h Feb 12, 2025
c7c392d
Only pass minimum required data for pbr lighting
mate-h Feb 12, 2025
0707fa5
Raymarching algo dynamic start and endpoint space view
mate-h Feb 13, 2025
230ee82
Use bevy native storagebuffer
mate-h Feb 16, 2025
2a17fec
Spherical atmosphere prototype
mate-h Feb 13, 2025
1ef2ff0
Up vector and mu based on view position in raymarch
mate-h Feb 13, 2025
4029575
Volumetric atmophere light shaft shadow experiment
mate-h Feb 21, 2025
afd72ee
Add blue noise jittering realtime performance
mate-h Feb 22, 2025
18cff2c
Add web support by gating dual source blending
mate-h Feb 24, 2025
afd1171
Volumetric fog compatibility
mate-h Mar 2, 2025
daf79d5
Fix build issues
mate-h Apr 19, 2025
06c1083
Implement basic environment lighting
mate-h Apr 20, 2025
1fa3894
Renamed skyview lut upsample to environment
mate-h Apr 20, 2025
cbd6c00
Rearrange bindings and fix reflection direction
mate-h Apr 20, 2025
83f53bb
Separate diffuse and specular
mate-h Apr 20, 2025
33ec1b8
Declutter code and fix warnings
mate-h Apr 21, 2025
d521dfc
Add dynamic environment map light probe pipelines
mate-h Apr 23, 2025
6ae1b27
Fix the SPD pipeline
mate-h Apr 24, 2025
fa71bbf
Implement filtering pipeline and propagate main world components
mate-h Apr 26, 2025
bd095ba
Cleanup example scene and tidy code
mate-h Apr 26, 2025
0fa8f7a
Bugfixes and blue noise sampling
mate-h Apr 27, 2025
7a01b77
Sampling improvements and bugfixes
mate-h Apr 28, 2025
129ac7c
Exposure compensation and ground luminance fix
mate-h Apr 29, 2025
33a179e
Fix CI
mate-h Apr 29, 2025
02a3390
Fix clippy errors
mate-h Apr 29, 2025
99b8d06
Exposed rendering type and sun disk size parameters
mate-h Apr 30, 2025
703c4a4
Raymarch function shadow argument and extract transform of lightprobe
mate-h May 2, 2025
a39bbe5
Revert controller changes to the examples
mate-h May 2, 2025
591fda2
Fix formatting
mate-h May 2, 2025
6dd02c5
Revert Cargo toml change
mate-h May 2, 2025
b0d8a53
Sun disk size in pbr
mate-h May 2, 2025
7c4b04a
Beauty pass and atmosphere view origin
mate-h May 2, 2025
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
16 changes: 16 additions & 0 deletions crates/bevy_image/src/image_texture_conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,22 @@ impl Image {
})
.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
texture_format => return Err(IntoDynamicImageError::UnsupportedFormat(texture_format)),
}
Expand Down
17 changes: 9 additions & 8 deletions crates/bevy_pbr/src/atmosphere/aerial_view_lut.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,16 @@
mesh_view_types::{Lights, DirectionalLight},
atmosphere::{
types::{Atmosphere, AtmosphereSettings},
bindings::{atmosphere, settings, view, lights, aerial_view_lut_out},
bindings::settings,
functions::{
sample_transmittance_lut, sample_atmosphere, rayleigh, henyey_greenstein,
sample_multiscattering_lut, AtmosphereSample, sample_local_inscattering,
get_local_r, get_local_up, view_radius, uv_to_ndc, max_atmosphere_distance,
uv_to_ray_direction, MIDPOINT_RATIO
uv_to_ray_direction, MIDPOINT_RATIO, get_view_position
},
}
}


@group(0) @binding(13) var aerial_view_lut_out: texture_storage_3d<rgba16float, write>;

@compute
Expand All @@ -22,8 +21,8 @@ fn main(@builtin(global_invocation_id) idx: vec3<u32>) {

let uv = (vec2<f32>(idx.xy) + 0.5) / vec2<f32>(settings.aerial_view_lut_size.xy);
let ray_dir = uv_to_ray_direction(uv);
let r = view_radius();
let mu = ray_dir.y;
let world_pos = get_view_position();
let r = length(world_pos);
let t_max = settings.aerial_view_lut_max_distance;

var prev_t = 0.0;
Expand All @@ -36,15 +35,17 @@ fn main(@builtin(global_invocation_id) idx: vec3<u32>) {
let dt = (t_i - prev_t);
prev_t = t_i;

let local_r = get_local_r(r, mu, t_i);
let local_up = get_local_up(r, t_i, ray_dir.xyz);
// Calculate position and up vector at the current sample point
let sample_pos = world_pos + ray_dir.xyz * t_i;
let local_r = length(sample_pos);
let local_up = normalize(sample_pos);

let local_atmosphere = sample_atmosphere(local_r);
let sample_optical_depth = local_atmosphere.extinction * dt;
let sample_transmittance = exp(-sample_optical_depth);

// evaluate one segment of the integral
var inscattering = sample_local_inscattering(local_atmosphere, ray_dir.xyz, local_r, local_up);
var inscattering = sample_local_inscattering(local_atmosphere, ray_dir.xyz, sample_pos, true);

// Analytical integration of the single scattering term in the radiance transfer equation
let s_int = (inscattering - inscattering * sample_transmittance) / local_atmosphere.extinction;
Expand Down
5 changes: 5 additions & 0 deletions crates/bevy_pbr/src/atmosphere/bindings.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,8 @@
@group(0) @binding(10) var sky_view_lut_sampler: sampler;
@group(0) @binding(11) var aerial_view_lut: texture_3d<f32>;
@group(0) @binding(12) var aerial_view_lut_sampler: sampler;
@group(0) @binding(14) var directional_shadow_texture: texture_depth_2d_array;
@group(0) @binding(15) var directional_shadow_sampler: sampler_comparison;
@group(0) @binding(16) var blue_noise_texture: texture_2d<f32>;
@group(0) @binding(17) var blue_noise_sampler: sampler;
@group(0) @binding(18) var<uniform> probe_transform_buffer: mat4x4<f32>;
Binary file added crates/bevy_pbr/src/atmosphere/bluenoise.ktx2
Binary file not shown.
74 changes: 74 additions & 0 deletions crates/bevy_pbr/src/atmosphere/environment.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#import bevy_render::maths::{PI}
#import bevy_pbr::atmosphere::{
types::{Atmosphere, AtmosphereSettings},
bindings::{atmosphere, settings, probe_transform_buffer},
functions::{max_atmosphere_distance, raymarch_atmosphere}
}

@group(0) @binding(13) var output: texture_storage_2d_array<rgba16float, write>;

// Convert from cubemap face and UV to direction vector
fn face_uv_to_direction(face: u32, uv: vec2<f32>) -> vec3<f32> {
// Convert UV from [0,1] to [-1,1]
let coords = 2.0 * uv - 1.0;

// Generate direction based on face
var dir: vec3<f32>;
switch face {
case 0u: { // +X
dir = vec3<f32>(1.0, -coords.y, coords.x);
}
case 1u: { // -X
dir = vec3<f32>(-1.0, -coords.y, -coords.x);
}
case 2u: { // +Y
dir = vec3<f32>(coords.x, 1.0, -coords.y);
}
case 3u: { // -Y
dir = vec3<f32>(coords.x, -1.0, coords.y);
}
case 4u: { // +Z
dir = vec3<f32>(coords.x, -coords.y, -1.0);
}
default: { // -Z (5)
dir = vec3<f32>(-coords.x, -coords.y, 1.0);
}
}

return normalize(dir);
}

@compute @workgroup_size(8, 8, 1)
fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
let dimensions = textureDimensions(output);
let slice_index = global_id.z;

if (global_id.x >= dimensions.x || global_id.y >= dimensions.y || slice_index >= 6u) {
return;
}

// Calculate normalized UV coordinates for this pixel
let uv = vec2<f32>(
(f32(global_id.x) + 0.5) / f32(dimensions.x),
(f32(global_id.y) + 0.5) / f32(dimensions.y)
);

var world_pos = probe_transform_buffer[3].xyz;

// offset by the origin point of the atmosphere scene
world_pos += atmosphere.origin;

let r = length(world_pos);

let ray_dir_ws = face_uv_to_direction(slice_index, uv);
let up = normalize(world_pos);
let mu = dot(ray_dir_ws, up);
let raymarch_steps = 16.0;
let t_max = max_atmosphere_distance(r, mu);
let sample_count = mix(1.0, raymarch_steps, clamp(t_max * 0.01, 0.0, 1.0));
let result = raymarch_atmosphere(world_pos, ray_dir_ws, t_max, sample_count, uv, false, true, false);
let inscattering = result.inscattering;
let color = vec4<f32>(inscattering, 1.0);

textureStore(output, vec2<i32>(global_id.xy), i32(slice_index), color);
}
Loading