11#import bevy_open_world :: common
22
33const EPSILON = 0 .000001 ;
4+ const MAX_DISTANCE = 1 .0e9 ;
45const WORLEY_RESOLUTION = 32 ;
56const WORLEY_RESOLUTION_F32 = 32 .0 ;
67
@@ -43,6 +44,12 @@ struct Config {
4344@group (1 ) @binding (2 ) var clouds_worley_texture : texture_storage_3d <rgba32float , read_write >;
4445@group (1 ) @binding (3 ) var sky_texture : texture_storage_2d <rgba32float , read_write >;
4546
47+ struct Ray {
48+ step_distance : f32 ,
49+ dir_length : f32 ,
50+ start : f32
51+ }
52+
4653struct RaymarchResult {
4754 dist : f32 ,
4855 color : vec4f ,
@@ -143,47 +150,53 @@ fn henyey_greenstein(ray_dot_sun: f32, g: f32) -> f32 {
143150 return (1 .0 - g_squared ) / pow (1 .0 + g_squared - 2 .0 * g * ray_dot_sun , 1 .5 );
144151}
145152
146- fn raymarch (_ray_origin : vec3f , ray_dir : vec3f , max_dist : f32 ) -> RaymarchResult {
147- if (ray_dir . y < 0 .0 ) {
148- return RaymarchResult (max_dist , vec4f (0 .0 , 0 .0 , 0 .0 , 1 .0 ));
149- }
150-
151- let ray_origin = vec3f (
152- _ray_origin . x ,
153- config . planet_radius - _ray_origin . y ,
154- _ray_origin . z
155- );
156-
157- let start = intersect_planet_sphere (ray_dir , config . clouds_bottom_height );
158- let end = min (intersect_planet_sphere (ray_dir , config . clouds_top_height ), max_dist );
159-
160- if (start > max_dist ) {
161- return RaymarchResult (max_dist , vec4f (0 .0 , 0 .0 , 0 .0 , 1 .0 ));
153+ fn get_ray (ray_origin : vec3f , ray_dir : vec3f , max_dist : f32 ) -> Ray {
154+ var start = intersect_planet_sphere (ray_dir , config . clouds_bottom_height );
155+ var end = intersect_planet_sphere (ray_dir , config . clouds_top_height );
156+ var inside = intersect_planet_sphere (ray_dir , ray_origin . y - config . planet_radius );
157+
158+ if (start <= inside && inside <= end ) {
159+ return Ray (0 .0 , 0 .0 , 0 .0 );
160+ if (ray_dir . y < 0 .0 ) {
161+ end = inside ;
162+ } else {
163+ start = inside ;
164+ }
162165 }
163166
164- let ray_dot_sun = dot ( ray_dir , - config . sun_dir . xyz );
167+ end = min ( end , max_dist );
165168
166169 let step_distance = (end - start ) / f32 (config . clouds_raymarch_steps_count );
167170 let hashed_offset = common :: hash13 (ray_dir + fract (config . time ));
168171 var dir_length = start - step_distance * hashed_offset ;
169172
173+ return Ray (step_distance , dir_length , start );
174+ }
175+
176+ fn raymarch (ray_origin : vec3f , ray_dir : vec3f , max_dist : f32 ) -> RaymarchResult {
177+ let ray = get_ray (ray_origin , ray_dir , max_dist );
178+
179+ if (ray . start > max_dist ) {
180+ return RaymarchResult (max_dist , vec4f (0 .0 , 0 .0 , 0 .0 , 1 .0 ));
181+ }
182+
170183 // Frostbite: dual-lobe phase function
184+ let ray_dot_sun = dot (ray_dir , - config . sun_dir . xyz );
171185 let scattering = mix (
172186 henyey_greenstein (ray_dot_sun , config . forward_scattering_g ),
173187 henyey_greenstein (ray_dot_sun , config . backward_scattering_g ),
174188 config . scattering_lerp
175189 );
176190
191+ var dir_length = ray . dir_length ;
192+ var dist = max_dist ;
177193 var scattered_light = vec3f (0 .0 , 0 .0 , 0 .0 );
178194 var transmittance = 1 .0 ;
179195
180- var dist = config . planet_radius ;
181-
182196 for (var step : u32 = 0 ; step < config . clouds_raymarch_steps_count ; step ++ ) {
183197 let world_position = ray_origin + dir_length * ray_dir ;
184198
185199 let normalized_height = clamp (get_normalized_height (world_position ), 0 .0 , 1 .0 );
186-
187200 let clouds_density_sampled = get_cloud_map_density (world_position , normalized_height );
188201
189202 if (clouds_density_sampled > 0 .0 ) {
@@ -200,7 +213,7 @@ fn raymarch(_ray_origin: vec3f, ray_dir: vec3f, max_dist: f32) -> RaymarchResult
200213 ambient_light . rgb +
201214 config . sun_color . rgb * scattering * volumetric_shadow (world_position , ray_dot_sun )
202215 );
203- let delta_transmittance = exp (- clouds_density_sampled * step_distance );
216+ let delta_transmittance = exp (- clouds_density_sampled * ray . step_distance );
204217 let integrated_scattering = S * (1 .0 - delta_transmittance ) / clouds_density_sampled ;
205218
206219 scattered_light += transmittance * integrated_scattering ;
@@ -209,7 +222,7 @@ fn raymarch(_ray_origin: vec3f, ray_dir: vec3f, max_dist: f32) -> RaymarchResult
209222
210223 if transmittance <= config . clouds_min_transmittance { break ; }
211224
212- dir_length += step_distance ;
225+ dir_length += ray . step_distance ;
213226 }
214227
215228 return RaymarchResult (dist , vec4f (scattered_light , transmittance ));
@@ -276,7 +289,7 @@ fn get_clouds_color(frag_coord: vec2f, camera: mat4x4f, old_cam: mat4x4f, ray_di
276289 return common :: save_camera (camera , frag_coord , ray_origin );
277290 }
278291
279- let result = raymarch (ray_origin , ray_dir , 1e9 );
292+ let result = raymarch (ray_origin , ray_dir , MAX_DISTANCE );
280293 let transmittance = result . color . a ;
281294
282295 let fog_falloff = 1 .0e-4 ;
@@ -293,10 +306,12 @@ fn get_clouds_color(frag_coord: vec2f, camera: mat4x4f, old_cam: mat4x4f, ray_di
293306
294307 // For now, just don't mix two frames when camera transform changed too much.
295308 // TODO: properly reproject old frame's reprojected pixel onto current frame.
296- if length (abs (old_cam [0 ] - camera [0 ])) > EPSILON ||
297- length (abs (old_cam [1 ] - camera [1 ])) > EPSILON ||
298- length (abs (old_cam [2 ] - camera [2 ])) > EPSILON ||
299- length (abs (old_cam [3 ] - camera [3 ])) > EPSILON {
309+ if length (
310+ abs (old_cam [0 ] - camera [0 ]) +
311+ abs (old_cam [1 ] - camera [1 ]) +
312+ abs (old_cam [2 ] - camera [2 ]) +
313+ abs (old_cam [3 ] - camera [3 ])
314+ ) > EPSILON {
300315 return col ;
301316 }
302317
@@ -309,7 +324,11 @@ fn get_clouds_color(frag_coord: vec2f, camera: mat4x4f, old_cam: mat4x4f, ray_di
309324}
310325
311326fn get_ray_origin (time : f32 ) -> vec3f {
312- return config . camera_translation - config . wind_displacement ;
327+ return (
328+ config . camera_translation -
329+ config . wind_displacement +
330+ vec3f (0 .0 , config . planet_radius , 0 .0 )
331+ );
313332}
314333
315334fn get_ray_direction (frag_coord : vec2f ) -> vec3f {
0 commit comments