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 42 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
48 changes: 25 additions & 23 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -100,41 +100,34 @@ unused_qualifications = "warn"

[features]
default = [
"android-game-activity",
"android-game-activity",
"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_remote",
"bevy_gltf",
"bevy_render",
"bevy_scene",
"bevy_sprite",
"bevy_sprite_picking_backend",
"bevy_state",
"bevy_text",
"bevy_ui",
"bevy_ui_picking_backend",
"bevy_winit",
"custom_cursor",
"default_font",
"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 @@ -200,7 +193,6 @@ bevy_sprite = [
"bevy_render",
"bevy_core_pipeline",
"bevy_color",
"bevy_sprite_picking_backend",
]

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

# winit window and input backend
Expand Down Expand Up @@ -837,6 +828,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 Expand Up @@ -1217,7 +1219,7 @@ setup = [
"curl",
"-o",
"assets/models/bunny.meshlet_mesh",
"https://raw.githubusercontent.com/JMS55/bevy_meshlet_asset/defbd9b32072624d40d57de7d345c66a9edf5d0b/bunny.meshlet_mesh",
ecoskey marked this conversation as resolved.
Show resolved Hide resolved
"https://raw.githubusercontent.com/JMS55/bevy_meshlet_asset/b6c712cfc87c65de419f856845401aba336a7bcd/bunny.meshlet_mesh",
],
]

Expand Down
105 changes: 105 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,105 @@
#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
},
bruneton_functions::{distance_to_top_atmosphere_boundary, distance_to_bottom_atmosphere_boundary,ray_intersects_ground}
}
}


@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; }
var optical_depth: vec3<f32> = vec3(0.0);

let uv = (vec2<f32>(idx.xy) + 0.5) / vec2<f32>(settings.aerial_view_lut_size.xy);
let view_dir = uv_to_ray_direction(uv); //TODO: negate for lighting calcs?
let r = view.world_position.y / 1000.0 + atmosphere.bottom_radius;
let mu = view_dir.y;

var prev_view_z = 0.0;
var total_inscattering = vec3(0.0);
for (var slice_i: i32 = i32(settings.aerial_view_lut_size.z - 1); slice_i >= 0; slice_i--) { //reversed loop to iterate depth near->far
var sum_transmittance = 0.0;
for (var step_i: i32 = i32(settings.aerial_view_lut_samples - 1); step_i >= 0; step_i--) { //same here
let ndc_z = (f32(slice_i) + ((f32(step_i) + 0.5) / f32(settings.aerial_view_lut_samples))) / f32(settings.aerial_view_lut_size.z);
//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 view_z = depth_ndc_to_view_z(ndc_z) / view_dir.w / 1000.0;

//subtraction is flipped because z values in front of the camera are negative
let step_length = (prev_view_z - view_z);
prev_view_z = view_z;

let local_r = get_local_r(r, mu, view_z);
if local_r > atmosphere.top_radius { break; }
let local_up = get_local_up(r, view_z * view_dir.xyz);

let local_atmosphere = sample_atmosphere(local_r);
optical_depth += local_atmosphere.extinction * step_length; //TODO: units between step_length and atmosphere

let transmittance_to_sample = exp(-optical_depth);

var local_inscattering = sample_local_inscattering(local_atmosphere, transmittance_to_sample, view_dir.xyz, local_r, local_up);
total_inscattering += local_inscattering * step_length;
sum_transmittance += transmittance_to_sample.r + transmittance_to_sample.g + transmittance_to_sample.b;
}
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));
}
}

/// Convert uv [0.0 .. 1.0] coordinate to ndc space xy [-1.0 .. 1.0]
fn uv_to_ndc(uv: vec2<f32>) -> vec2<f32> {
return uv * vec2(2.0, -2.0) + vec2(-1.0, 1.0);
}

/// Convert a ndc space position to world space
fn position_ndc_to_world(ndc_pos: vec3<f32>) -> vec3<f32> {
let world_pos = view.world_from_clip * vec4(ndc_pos, 1.0);
return world_pos.xyz / world_pos.w;
}

//Modified from skybox.wgsl. For this pass we don't need to apply a separate sky transform or consider camera viewport.
//w component is the cosine of the view direction with the view forward vector, to correct step distance at the edges of the viewport
fn uv_to_ray_direction(uv: vec2<f32>) -> vec4<f32> {
// Using world positions of the fragment and camera to calculate a ray direction
// breaks down at large translations. This code only needs to know the ray direction.
// The ray direction is along the direction from the camera to the fragment position.
// In view space, the camera is at the origin, so the view space ray direction is
// along the direction of the fragment position - (0,0,0) which is just the
// fragment position.
// Use the position on the near clipping plane to avoid -inf world position
// because the far plane of an infinite reverse projection is at infinity.
let view_position_homogeneous = view.view_from_clip * vec4(
uv_to_ndc(uv),
1.0,
1.0,
);

let view_ray_direction = view_position_homogeneous.xyz / view_position_homogeneous.w; //TODO: remove this step and just use position_ndc_to_world? we didn't need to transform in view space

// Transforming the view space ray direction by the inverse view matrix, transforms the
// direction to world space. Note that the w element is set to 0.0, as this is a
// vector direction, not a position, That causes the matrix multiplication to ignore
// the translations from the view matrix.
let ray_direction = (view.world_from_view * vec4(view_ray_direction, 0.0)).xyz;

return vec4(normalize(ray_direction), -view_ray_direction.z); //TODO: correct sign?
}


/// Convert ndc depth to linear view z.
/// Note: Depth values in front of the camera will be negative as -z is forward
fn depth_ndc_to_view_z(ndc_depth: f32) -> f32 {
let view_pos = view.view_from_clip * vec4(0.0, 0.0, ndc_depth, 1.0);
return view_pos.z / view_pos.w;
}
21 changes: 21 additions & 0 deletions crates/bevy_pbr/src/atmosphere/bindings.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#define_import_path bevy_pbr::atmosphere::bindings

#import bevy_render::view::View;

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

@group(0) @binding(0) var<uniform> atmosphere: Atmosphere;
@group(0) @binding(1) var<uniform> settings: AtmosphereSettings;
@group(0) @binding(2) var<uniform> view: View;
@group(0) @binding(3) var<uniform> lights: Lights;
@group(0) @binding(4) var transmittance_lut: texture_2d<f32>;
@group(0) @binding(5) var transmittance_lut_sampler: sampler;
@group(0) @binding(6) var multiscattering_lut: texture_2d<f32>;
@group(0) @binding(7) var multiscattering_lut_sampler: sampler;
@group(0) @binding(8) var sky_view_lut: texture_2d<f32>;
@group(0) @binding(9) var sky_view_lut_sampler: sampler;
@group(0) @binding(10) var aerial_view_lut: texture_3d<f32>;
@group(0) @binding(11) var aerial_view_lut_sampler: sampler;
140 changes: 140 additions & 0 deletions crates/bevy_pbr/src/atmosphere/bruneton_functions.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// 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);
}

//TODO: What is m2??? is it just there to catch copyright?????
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; // * m2;
}
Loading
Loading