Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Procedural atmospheric scattering #16314

Open
wants to merge 100 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
100 commits
Select commit Hold shift + click to select a range
9d948ab
wip
ecoskey Aug 29, 2024
515dfde
WIP
ecoskey Aug 31, 2024
ceb4af1
Merge branch 'main' into proc_sky
ecoskey Sep 3, 2024
534f505
WIP
ecoskey Sep 5, 2024
3fa0980
use buffer binding
ecoskey Sep 5, 2024
d5c58f0
WIP + example
ecoskey Sep 9, 2024
28bd632
bind groups and more prep
ecoskey Sep 10, 2024
4c3de51
WIP
ecoskey Sep 10, 2024
e18baec
add ground albedo to bind groups
ecoskey Sep 10, 2024
823a338
add apply pass
ecoskey Sep 12, 2024
222b11d
bwah
ecoskey Sep 16, 2024
39c1075
WIP + finished aerial view lut
ecoskey Sep 19, 2024
a682732
small fixes
ecoskey Sep 20, 2024
fdc86c5
update bindings
ecoskey Sep 20, 2024
6f3a7c5
Merge branch 'main' into proc_sky
ecoskey Sep 3, 2024
0096c59
WIP
ecoskey Sep 5, 2024
bad3819
use buffer binding
ecoskey Sep 5, 2024
c1c73a1
WIP + example
ecoskey Sep 9, 2024
6ed73d4
bind groups and more prep
ecoskey Sep 10, 2024
1b215d8
WIP
ecoskey Sep 10, 2024
6050cb3
add ground albedo to bind groups
ecoskey Sep 10, 2024
3c4420f
add apply pass
ecoskey Sep 12, 2024
98285f3
bwah
ecoskey Sep 16, 2024
5cabba8
WIP + finished aerial view lut
ecoskey Sep 19, 2024
6e9251b
small fixes
ecoskey Sep 20, 2024
33ded2f
update bindings
ecoskey Sep 20, 2024
40a9b54
Merge branch 'proc_sky' of github.com:ecoskey/bevy into proc_sky
ecoskey Sep 20, 2024
7f05f5d
sky_view_lut progress
ecoskey Sep 24, 2024
9be3e7b
fix bindings and such
ecoskey Sep 24, 2024
7f1ed99
misc fixes
ecoskey Sep 24, 2024
818d556
partially working thing maybe
ecoskey Sep 27, 2024
af99fe3
gwah
ecoskey Sep 30, 2024
73c56c1
progress???
ecoskey Oct 1, 2024
dbfbcc9
cleanup and bindings
ecoskey Oct 29, 2024
7c1d767
wip
ecoskey Oct 30, 2024
966266c
fix a bunch of things
ecoskey Nov 1, 2024
cbf6d78
transforms and stuff
ecoskey Nov 3, 2024
1202bca
fix bindings layout
ecoskey Nov 7, 2024
b4366b9
fix extraction
ecoskey Nov 9, 2024
ac1ee5b
Merge branch 'main' into proc_sky
ecoskey Nov 9, 2024
d03c2bb
more small progress
ecoskey Nov 10, 2024
490cc5b
format toml
ecoskey Nov 10, 2024
ac4663d
Merge branch 'main' into proc_sky
ecoskey Nov 10, 2024
cfce3a5
fix readme examples
ecoskey Nov 10, 2024
69bca4e
approaching correctness
ecoskey Nov 11, 2024
06b5ba6
basic sun disk rendering
ecoskey Nov 11, 2024
cb3edf8
fix features list
ecoskey Nov 11, 2024
bbb1b45
Merge branch 'main' into proc_sky
ecoskey Nov 11, 2024
d27aa05
move to cubemap
ecoskey Nov 12, 2024
0d3471e
WIP atmo transformations
ecoskey Nov 21, 2024
40c5eaf
remove gunk
ecoskey Nov 21, 2024
e3ca9fe
fixes
ecoskey Nov 21, 2024
febb5b0
lots of progress somehow
ecoskey Nov 21, 2024
b30782a
Update multiscattering_lut.wgsl
ecoskey Nov 21, 2024
bed80b9
revert sky_view_lut behavior
ecoskey Nov 26, 2024
f27a0fd
fix transforms
ecoskey Nov 26, 2024
448cd2a
fix sky_view_lut radius
ecoskey Nov 27, 2024
7d51144
multiscattering and sampling
ecoskey Nov 27, 2024
6cb9c59
fix multiscattering
ecoskey Nov 27, 2024
41b801f
first cleanup/docs pass
ecoskey Nov 27, 2024
301c880
docs pass 2
ecoskey Nov 28, 2024
895de1a
remove old code
ecoskey Nov 28, 2024
e85809b
more docs
ecoskey Nov 29, 2024
901ab54
fix
ecoskey Dec 1, 2024
62ab0a5
comment
ecoskey Dec 1, 2024
8bdc1c4
Add MSAA support
JMS55 Dec 1, 2024
f1fd5dc
Fix
JMS55 Dec 1, 2024
d39d742
Fix import
JMS55 Dec 1, 2024
f553018
Merge pull request #2 from JMS55/depth-proc-sky
ecoskey Dec 2, 2024
31d88b0
specialize pipelines
ecoskey Dec 5, 2024
6b3e016
partial multiscattering fix
ecoskey Dec 5, 2024
4322495
small docs changes
ecoskey Dec 5, 2024
050e29f
why does this fix things
ecoskey Dec 6, 2024
ebf5363
minor docs
ecoskey Dec 6, 2024
4c470c0
density scaling
ecoskey Dec 6, 2024
5dda6aa
fix transmittance LUT
ecoskey Dec 6, 2024
d6f4fb2
fix horizon
ecoskey Dec 8, 2024
fbaccc9
blargh
Dec 15, 2024
64082da
fast math
Dec 17, 2024
f1c2fe1
fast math 2
Dec 18, 2024
7a11933
back to 2d sky-view
Dec 19, 2024
74ddce0
cleanup
Dec 21, 2024
b16b9cb
done????
Dec 21, 2024
9aa5b65
fix lat-long parametrization
Dec 22, 2024
e92d705
cleanup
Dec 22, 2024
649a2a4
cleanup
Dec 24, 2024
e704dcd
Merge branch 'main' into proc_sky
Dec 24, 2024
6bd299d
Merge branch 'main' into proc_sky
Dec 24, 2024
ff2c5ac
fix imports
Dec 24, 2024
43923dd
fix typos
Dec 24, 2024
dc39a89
fix ci
Dec 24, 2024
615dd5e
fix imports
Dec 24, 2024
7bd44dd
fmt
Dec 24, 2024
20745ec
taplo
Dec 24, 2024
d634e2d
cargo features
Dec 24, 2024
890a840
Update fast_math.wgsl
Dec 24, 2024
e05a8c8
fix meshlet mesh ref
Dec 24, 2024
9d8dadd
Merge branch 'main' into proc_sky
Dec 24, 2024
9fa8a4b
fix examples
Dec 24, 2024
3375c24
fix formatting
Dec 24, 2024
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
35 changes: 23 additions & 12 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -106,20 +106,18 @@ default = [
"android_shared_stdcxx",
"animation",
"bevy_asset",
"bevy_state",
"bevy_audio",
"bevy_color",
"bevy_core_pipeline",
"bevy_gilrs",
"bevy_gizmos",
"bevy_gltf",
"bevy_mesh_picking_backend",
"bevy_scene",
"bevy_winit",
"bevy_core_pipeline",
"bevy_pbr",
"bevy_picking",
"bevy_render",
"bevy_scene",
"bevy_sprite",
"bevy_sprite_picking_backend",
"bevy_state",
"bevy_text",
"bevy_ui",
"bevy_ui_picking_backend",
Expand All @@ -130,12 +128,16 @@ default = [
"hdr",
"multi_threaded",
"png",
"smaa_luts",
"sysinfo_plugin",
"tonemapping_luts",
"hdr",
"vorbis",
"webgl2",
"x11",
"bevy_gizmos",
"android_shared_stdcxx",
"tonemapping_luts",
"smaa_luts",
"default_font",
"webgl2",
"sysinfo_plugin",
]

# Provides an implementation for picking meshes
Expand Down Expand Up @@ -213,7 +215,6 @@ bevy_sprite = [
"bevy_render",
"bevy_core_pipeline",
"bevy_color",
"bevy_sprite_picking_backend",
]

# Provides text functionality
Expand All @@ -226,7 +227,6 @@ bevy_ui = [
"bevy_text",
"bevy_sprite",
"bevy_color",
"bevy_ui_picking_backend",
]

# Windowing layer
Expand Down Expand Up @@ -856,6 +856,17 @@ description = "A scene showcasing the atmospheric fog effect"
category = "3D Rendering"
wasm = true

[[example]]
name = "atmosphere"
path = "examples/3d/atmosphere.rs"
doc-scrape-examples = true

[package.metadata.example.atmosphere]
name = "Atmosphere"
description = "A scene showcasing pbr atmospheric scattering"
category = "3D Rendering"
wasm = true

[[example]]
name = "fog"
path = "examples/3d/fog.rs"
Expand Down
68 changes: 68 additions & 0 deletions crates/bevy_pbr/src/atmosphere/aerial_view_lut.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#import bevy_pbr::{
mesh_view_types::{Lights, DirectionalLight},
atmosphere::{
types::{Atmosphere, AtmosphereSettings},
bindings::{atmosphere, settings, view, lights, aerial_view_lut_out},
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, position_ndc_to_world, depth_ndc_to_view_z,
max_atmosphere_distance, uv_to_ray_direction
},
}
}


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

@compute
@workgroup_size(16, 16, 1) //TODO: this approach makes it so closer slices get fewer samples. But we also expect those to have less scattering. So win/win?
fn main(@builtin(global_invocation_id) idx: vec3<u32>) {
if any(idx.xy > settings.aerial_view_lut_size.xy) { return; }

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 t_max = max_atmosphere_distance(r, mu);

var prev_t = 0.0;
var total_inscattering = vec3(0.0);
var optical_depth = vec3(0.0);

// The aerial view LUT is in NDC space, so it uses bevy's reverse z convention. Since
// we write multiple slices from each thread, we need to iterate in order near->far, which
// is why the indices are reversed.
for (var slice_i: i32 = i32(settings.aerial_view_lut_size.z - 1); slice_i >= 0; slice_i--) {
var sum_transmittance = 0.0;
for (var step_i: i32 = i32(settings.aerial_view_lut_samples - 1); step_i >= 0; step_i--) {
let sample_depth = depth_at_sample(slice_i, step_i);
//view_dir.w is the cosine of the angle between the view vector and the camera forward vector, used to correct the step length.
let t_i = -depth_ndc_to_view_z(sample_depth) / ray_dir.w * settings.scene_units_to_km;
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);

let local_atmosphere = sample_atmosphere(local_r);
optical_depth += local_atmosphere.extinction * dt;

// use beer's law to get transmittance from optical density
let transmittance_to_sample = exp(-optical_depth);

// evaluate one segment of the integral
var local_inscattering = sample_local_inscattering(local_atmosphere, transmittance_to_sample, ray_dir.xyz, local_r, local_up);
total_inscattering += local_inscattering * dt;
sum_transmittance += transmittance_to_sample.r + transmittance_to_sample.g + transmittance_to_sample.b;
}
//We only have one channel to store transmittance, so we store the mean
let mean_transmittance = sum_transmittance / (f32(settings.aerial_view_lut_samples) * 3.0);
textureStore(aerial_view_lut_out, vec3(vec2<i32>(idx.xy), slice_i), vec4(total_inscattering, mean_transmittance));
}
}

// linearly interpolates from 0..1 on the domain of slice_i, using step_i as a substep index
fn depth_at_sample(slice_i: i32, step_i: i32) -> f32 {
return (f32(slice_i) + ((f32(step_i) + 0.5) / f32(settings.aerial_view_lut_samples))) / f32(settings.aerial_view_lut_size.z);
}
22 changes: 22 additions & 0 deletions crates/bevy_pbr/src/atmosphere/bindings.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#define_import_path bevy_pbr::atmosphere::bindings

#import bevy_render::view::View;

#import bevy_pbr::{
mesh_view_types::Lights,
atmosphere::types::{Atmosphere, AtmosphereSettings, AtmosphereTransforms}
}

@group(0) @binding(0) var<uniform> atmosphere: Atmosphere;
@group(0) @binding(1) var<uniform> settings: AtmosphereSettings;
@group(0) @binding(2) var<uniform> atmosphere_transforms: AtmosphereTransforms;
@group(0) @binding(3) var<uniform> view: View;
@group(0) @binding(4) var<uniform> lights: Lights;
@group(0) @binding(5) var transmittance_lut: texture_2d<f32>;
@group(0) @binding(6) var transmittance_lut_sampler: sampler;
@group(0) @binding(7) var multiscattering_lut: texture_2d<f32>;
@group(0) @binding(8) var multiscattering_lut_sampler: sampler;
@group(0) @binding(9) var sky_view_lut: texture_2d<f32>;
@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;
139 changes: 139 additions & 0 deletions crates/bevy_pbr/src/atmosphere/bruneton_functions.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// Copyright (c) 2017 Eric Bruneton
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// 3. Neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
// THE POSSIBILITY OF SUCH DAMAGE.
//
// Precomputed Atmospheric Scattering
// Copyright (c) 2008 INRIA
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// 3. Neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
// THE POSSIBILITY OF SUCH DAMAGE.

#define_import_path bevy_pbr::atmosphere::bruneton_functions

#import bevy_pbr::atmosphere::{
types::Atmosphere,
bindings::atmosphere,
}

// Mapping from view height (r) and zenith cos angle (mu) to UV coordinates in the transmittance LUT
// Assuming r between ground and top atmosphere boundary, and mu= cos(zenith_angle)
// Chosen to increase precision near the ground and to work around a discontinuity at the horizon
// See Bruneton and Neyret 2008, "Precomputed Atmospheric Scattering" section 4
fn transmittance_lut_r_mu_to_uv(r: f32, mu: f32) -> vec2<f32> {
// Distance along a horizontal ray from the ground to the top atmosphere boundary
let H = sqrt(atmosphere.top_radius * atmosphere.top_radius - atmosphere.bottom_radius * atmosphere.bottom_radius);

// Distance from a point at height r to the horizon
// ignore the case where r <= atmosphere.bottom_radius
let rho = sqrt(max(r * r - atmosphere.bottom_radius * atmosphere.bottom_radius, 0.0));

// Distance from a point at height r to the top atmosphere boundary at zenith angle mu
let d = distance_to_top_atmosphere_boundary(r, mu);

// Minimum and maximum distance to the top atmosphere boundary from a point at height r
let d_min = atmosphere.top_radius - r; // length of the ray straight up to the top atmosphere boundary
let d_max = rho + H; // length of the ray to the top atmosphere boundary and grazing the horizon

let u = (d - d_min) / (d_max - d_min);
let v = rho / H;
return vec2<f32>(u, v);
}

// Inverse of the mapping above, mapping from UV coordinates in the transmittance LUT to view height (r) and zenith cos angle (mu)
fn transmittance_lut_uv_to_r_mu(uv: vec2<f32>) -> vec2<f32> {
// Distance to top atmosphere boundary for a horizontal ray at ground level
let H = sqrt(atmosphere.top_radius * atmosphere.top_radius - atmosphere.bottom_radius * atmosphere.bottom_radius);

// Distance to the horizon, from which we can compute r:
let rho = H * uv.y;
let r = sqrt(rho * rho + atmosphere.bottom_radius * atmosphere.bottom_radius);

// Distance to the top atmosphere boundary for the ray (r,mu), and its minimum
// and maximum values over all mu- obtained for (r,1) and (r,mu_horizon) -
// from which we can recover mu:
let d_min = atmosphere.top_radius - r;
let d_max = rho + H;
let d = d_min + uv.x * (d_max - d_min);

var mu: f32;
if d == 0.0 {
mu = 1.0;
} else {
mu = (H * H - rho * rho - d * d) / (2.0 * r * d);
}

mu = clamp(mu, -1.0, 1.0);

return vec2<f32>(r, mu);
}

/// Simplified ray-sphere intersection
/// where:
/// Ray origin, o = [0,0,r] with r <= atmosphere.top_radius
/// mu is the cosine of spherical coordinate theta (-1.0 <= mu <= 1.0)
/// so ray direction in spherical coordinates is [1,acos(mu),0] which needs to be converted to cartesian
/// Direction of ray, u = [0,sqrt(1-mu*mu),mu]
/// Center of sphere, c = [0,0,0]
/// Radius of sphere, r = atmosphere.top_radius
/// This function solves the quadratic equation for line-sphere intersection simplified under these assumptions
fn distance_to_top_atmosphere_boundary(r: f32, mu: f32) -> f32 {
// ignore the case where r > atmosphere.top_radius
let positive_discriminant = max(r * r * (mu * mu - 1.0) + atmosphere.top_radius * atmosphere.top_radius, 0.0);
return max(-r * mu + sqrt(positive_discriminant), 0.0);
}

/// Simplified ray-sphere intersection
/// as above for intersections with the ground
fn distance_to_bottom_atmosphere_boundary(r: f32, mu: f32) -> f32 {
let positive_discriminant = max(r * r * (mu * mu - 1.0) + atmosphere.bottom_radius * atmosphere.bottom_radius, 0.0);
return max(-r * mu - sqrt(positive_discriminant), 0.0);
}

fn ray_intersects_ground(r: f32, mu: f32) -> bool {
return mu < 0.0 && r * r * (mu * mu - 1.0) + atmosphere.bottom_radius * atmosphere.bottom_radius >= 0.0;
}
Loading
Loading