@@ -117,23 +117,31 @@ impl ScatteringMedium {
117117 }
118118
119119 /// Returns a scattering medium representing an earthlike atmosphere.
120+ ///
121+ /// Uses physically-based scale heights from Earth's atmosphere, assuming
122+ /// a 60 km atmosphere height:
123+ /// - Rayleigh (molecular) scattering: 8 km scale height
124+ /// - Mie (aerosol) scattering: 1.2 km scale height
120125 pub fn earthlike ( falloff_resolution : u32 , phase_resolution : u32 ) -> Self {
121126 Self :: new (
122127 falloff_resolution,
123128 phase_resolution,
124129 [
130+ // Rayleigh scattering Term
125131 ScatteringTerm {
126132 absorption : Vec3 :: ZERO ,
127133 scattering : Vec3 :: new ( 5.802e-6 , 13.558e-6 , 33.100e-6 ) ,
128- falloff : Falloff :: Exponential { strength : 12.5 } ,
134+ falloff : Falloff :: Exponential { scale : 8.0 / 60.0 } ,
129135 phase : PhaseFunction :: Rayleigh ,
130136 } ,
137+ // Mie scattering Term
131138 ScatteringTerm {
132139 absorption : Vec3 :: splat ( 3.996e-6 ) ,
133140 scattering : Vec3 :: splat ( 0.444e-6 ) ,
134- falloff : Falloff :: Exponential { strength : 83.5 } ,
141+ falloff : Falloff :: Exponential { scale : 1.2 / 60.0 } ,
135142 phase : PhaseFunction :: Mie { asymmetry : 0.8 } ,
136143 } ,
144+ // Ozone scattering Term
137145 ScatteringTerm {
138146 absorption : Vec3 :: new ( 0.650e-6 , 1.881e-6 , 0.085e-6 ) ,
139147 scattering : Vec3 :: ZERO ,
@@ -203,18 +211,30 @@ pub enum Falloff {
203211 /// f(p) = p
204212 #[ default]
205213 Linear ,
206- /// An exponential falloff function with adjustable strength.
214+ /// An exponential falloff function parametrized by a proportional scale.
215+ /// When paired with an absolute "falloff distance" like the distance from
216+ /// Earth's surface to the edge of space, this is analogous to the "height
217+ /// scale" value common in atmospheric scattering literature, though it will
218+ /// diverge from this for large or negative `scale` values.
207219 ///
208220 /// f(1) = 1
209221 /// f(0) = 0
210- /// f(p) = (e^sp - 1) /(e^s - 1 )
222+ /// f(p) = (e^((1-p)/s) - e^(1/s)) /(e - e^(1/s) )
211223 Exponential {
212- /// The "strength" of the exponential falloff. The higher
213- /// this value is, the quicker the medium's density will
214- /// decrease with distance.
224+ /// The "scale" of the exponential falloff. Values closer to zero will
225+ /// produce steeper falloff, and values farther from zero will produce
226+ /// gentler falloff, approaching linear falloff as scale goes to `+-∞`.
227+ ///
228+ /// Negative values change the *concavity* of the falloff function:
229+ /// rather than an initial narrow region of steep falloff followed by a
230+ /// wide region of gentle falloff, there will be an initial wide region
231+ /// of gentle falloff followed by a narrow region of steep falloff.
215232 ///
216233 /// domain: (-∞, ∞)
217- strength : f32 ,
234+ ///
235+ /// NOTE, this function is not defined when `scale == 0`.
236+ /// In that case, it will fall back to linear falloff.
237+ scale : f32 ,
218238 } ,
219239 /// A tent-shaped falloff function, which produces a triangular
220240 /// peak at the center and linearly falls off to either side.
@@ -244,25 +264,23 @@ impl Falloff {
244264 Self :: Curve ( Arc :: new ( curve) )
245265 }
246266
247- fn sample ( & self , falloff : f32 ) -> f32 {
267+ fn sample ( & self , p : f32 ) -> f32 {
248268 match self {
249- Falloff :: Linear => falloff,
250- Falloff :: Exponential { strength } => {
251- // fill discontinuity at strength == 0
252- if * strength == 0.0 {
253- falloff
269+ Falloff :: Linear => p,
270+ Falloff :: Exponential { scale } => {
271+ // fill discontinuity at scale == 0,
272+ // arbitrarily choose linear falloff
273+ if * scale == 0.0 {
274+ p
254275 } else {
255- let scale_exp_m1 = ops:: exp_m1 ( * strength) ;
256- let domain_offset = ops:: ln ( scale_exp_m1. abs ( ) ) ;
257- let range_offset = scale_exp_m1. recip ( ) ;
258- let eval_pos = falloff * strength - domain_offset;
259- scale_exp_m1. signum ( ) * ops:: exp ( eval_pos) - range_offset
276+ let s = -1.0 / scale;
277+ let exp_p_s = ops:: exp ( ( 1.0 - p) * s) ;
278+ let exp_s = ops:: exp ( s) ;
279+ ( exp_p_s - exp_s) / ( 1.0 - exp_s)
260280 }
261281 }
262- Falloff :: Tent { center, width } => {
263- ( 1.0 - ( falloff - center) . abs ( ) / ( 0.5 * width) ) . max ( 0.0 )
264- }
265- Falloff :: Curve ( curve) => curve. sample ( falloff) . unwrap_or ( 0.0 ) ,
282+ Falloff :: Tent { center, width } => ( 1.0 - ( p - center) . abs ( ) / ( 0.5 * width) ) . max ( 0.0 ) ,
283+ Falloff :: Curve ( curve) => curve. sample ( p) . unwrap_or ( 0.0 ) ,
266284 }
267285 }
268286}
0 commit comments