@@ -359,7 +359,36 @@ float get_omni_attenuation(float distance, float inv_range, float decay) {
359359 return nd * pow (max (distance , 0.0001 ), - decay);
360360}
361361
362- void trace_direct_light(vec3 p_position, vec3 p_normal, uint p_light_index, bool p_soft_shadowing, out vec3 r_light, out vec3 r_light_dir, inout uint r_noise) {
362+ const int AA_SAMPLES = 16 ;
363+
364+ const vec2 halton_map[AA_SAMPLES] = vec2 [](
365+ vec2 (0.5 , 0.33333333 ),
366+ vec2 (0.25 , 0.66666667 ),
367+ vec2 (0.75 , 0.11111111 ),
368+ vec2 (0.125 , 0.44444444 ),
369+ vec2 (0.625 , 0.77777778 ),
370+ vec2 (0.375 , 0.22222222 ),
371+ vec2 (0.875 , 0.55555556 ),
372+ vec2 (0.0625 , 0.88888889 ),
373+ vec2 (0.5625 , 0.03703704 ),
374+ vec2 (0.3125 , 0.37037037 ),
375+ vec2 (0.8125 , 0.7037037 ),
376+ vec2 (0.1875 , 0.14814815 ),
377+ vec2 (0.6875 , 0.48148148 ),
378+ vec2 (0.4375 , 0.81481481 ),
379+ vec2 (0.9375 , 0.25925926 ),
380+ vec2 (0.03125 , 0.59259259 ));
381+
382+ vec2 get_vogel_disk(float p_i, float p_rotation, float p_sample_count_sqrt) {
383+ const float golden_angle = 2.4 ;
384+
385+ float r = sqrt (p_i + 0.5 ) / p_sample_count_sqrt;
386+ float theta = p_i * golden_angle + p_rotation;
387+
388+ return vec2 (cos (theta), sin (theta)) * r;
389+ }
390+
391+ void trace_direct_light(vec3 p_position, vec3 p_normal, uint p_light_index, bool p_soft_shadowing, out vec3 r_light, out vec3 r_light_dir, inout uint r_noise, float p_texel_size) {
363392 r_light = vec3 (0 .0f);
364393
365394 vec3 light_pos;
@@ -407,46 +436,70 @@ void trace_direct_light(vec3 p_position, vec3 p_normal, uint p_light_index, bool
407436 }
408437
409438 float penumbra = 0.0 ;
410- if ((light_data.size > 0.0 ) && p_soft_shadowing) {
439+ if (p_soft_shadowing) {
440+ const bool use_soft_shadows = (light_data.size > 0.0 );
441+ const uint ray_count = AA_SAMPLES;
442+ const uint total_ray_count = use_soft_shadows ? params.ray_count : ray_count;
443+ const uint shadowing_rays_check_penumbra_denom = 2 ;
444+ const uint shadowing_ray_count = max (1 , params.ray_count / ray_count);
445+ const float shadowing_ray_count_sqrt = sqrt (float (total_ray_count));
446+
447+ // Setup tangent pass to calculate AA samples over the current texel.
448+ vec3 aux = p_normal.y < 0.777 ? vec3 (0.0 , 1.0 , 0.0 ) : vec3 (1.0 , 0.0 , 0.0 );
449+ vec3 tangent = normalize (cross (p_normal, aux));
450+ vec3 bitan = normalize (cross (p_normal, tangent));
451+
452+ // Setup light tangent pass to calculate samples over disk aligned towards the light
411453 vec3 light_to_point = - r_light_dir;
412- vec3 aux = light_to_point.y < 0.777 ? vec3 (0.0 , 1.0 , 0.0 ) : vec3 (1.0 , 0.0 , 0.0 );
413- vec3 light_to_point_tan = normalize (cross (light_to_point, aux ));
454+ vec3 light_aux = light_to_point.y < 0.777 ? vec3 (0.0 , 1.0 , 0.0 ) : vec3 (1.0 , 0.0 , 0.0 );
455+ vec3 light_to_point_tan = normalize (cross (light_to_point, light_aux ));
414456 vec3 light_to_point_bitan = normalize (cross (light_to_point, light_to_point_tan));
415457
416- const uint shadowing_rays_check_penumbra_denom = 2 ;
417- uint shadowing_ray_count = p_soft_shadowing ? params.ray_count : 1 ;
418-
419458 uint hits = 0 ;
420- vec3 light_disk_to_point = light_to_point;
421- for (uint j = 0 ; j < shadowing_ray_count; j++ ) {
422- // Optimization:
423- // Once already traced an important proportion of rays, if all are hits or misses,
424- // assume we're not in the penumbra so we can infer the rest would have the same result
425- if (p_soft_shadowing) {
426- if (j == shadowing_ray_count / shadowing_rays_check_penumbra_denom) {
427- if (hits == j) {
428- // Assume totally lit
429- hits = shadowing_ray_count;
430- break ;
431- } else if (hits == 0 ) {
432- // Assume totally dark
433- hits = 0 ;
434- break ;
459+ for (uint i = 0 ; i < ray_count; i++ ) {
460+ // Create a random sample within the texel.
461+ vec2 disk_sample = (halton_map[i] - vec2 (0.5 )) * p_texel_size * light_data.shadow_blur;
462+ // Align the sample to world space.
463+ vec3 disk_aligned = (disk_sample.x * tangent + disk_sample.y * bitan);
464+ vec3 origin = p_position - disk_aligned;
465+ vec3 light_dir = normalize (light_pos - origin);
466+
467+ if (use_soft_shadows) {
468+ uint soft_shadow_hits = 0 ;
469+ for (uint j = 0 ; j < shadowing_ray_count; j++ ) {
470+ // Optimization:
471+ // Once already traced an important proportion of rays, if all are hits or misses,
472+ // assume we're not in the penumbra so we can infer the rest would have the same result.
473+ if (j == shadowing_ray_count / shadowing_rays_check_penumbra_denom) {
474+ if (soft_shadow_hits == j) {
475+ // Assume totally lit
476+ soft_shadow_hits = shadowing_ray_count;
477+ break ;
478+ } else if (soft_shadow_hits == 0 ) {
479+ // Assume totally dark
480+ soft_shadow_hits = 0 ;
481+ break ;
482+ }
435483 }
436- }
437- }
438-
439- float r = randomize(r_noise);
440- float a = randomize(r_noise) * 2.0 * PI;
441- vec2 disk_sample = (r * vec2 (cos (a), sin (a))) * soft_shadowing_disk_size * light_data.shadow_blur;
442- light_disk_to_point = normalize (light_to_point + disk_sample.x * light_to_point_tan + disk_sample.y * light_to_point_bitan);
443484
444- if (trace_ray_any_hit(p_position - light_disk_to_point * bake_params.bias, p_position - light_disk_to_point * dist) == RAY_MISS) {
445- hits++ ;
485+ float a = randomize(r_noise) * 2.0 * PI;
486+ float vogel_index = float (total_ray_count - 1 - (i * shadowing_ray_count + j)); // Start from (total_ray_count - 1) so we check the outer points first.
487+ vec2 light_disk_sample = (get_vogel_disk(vogel_index, a, shadowing_ray_count_sqrt)) * soft_shadowing_disk_size * light_data.shadow_blur;
488+ vec3 light_disk_to_point = normalize (light_to_point + light_disk_sample.x * light_to_point_tan + light_disk_sample.y * light_to_point_bitan);
489+ // Offset the ray origin for AA, offset the light position for soft shadows.
490+ if (trace_ray_any_hit(origin - light_disk_to_point * (bake_params.bias + length (disk_sample)), p_position - light_disk_to_point * dist) == RAY_MISS) {
491+ soft_shadow_hits++ ;
492+ }
493+ }
494+ hits += soft_shadow_hits;
495+ } else {
496+ // Offset the ray origin based on the disk. Also increase the bias for further samples to avoid bleeding.
497+ if (trace_ray_any_hit(origin + light_dir * (bake_params.bias + length (disk_sample)), light_pos) == RAY_MISS) {
498+ hits++ ;
499+ }
446500 }
447501 }
448-
449- penumbra = float (hits) / float (shadowing_ray_count);
502+ penumbra = float (hits) / float (total_ray_count);
450503 } else {
451504 if (trace_ray_any_hit(p_position + r_light_dir * bake_params.bias, light_pos) == RAY_MISS) {
452505 penumbra = 1.0 ;
@@ -470,7 +523,7 @@ vec3 trace_environment_color(vec3 ray_dir) {
470523 return textureLod(sampler2D (environment, linear_sampler), st / vec2 (PI * 2.0 , PI), 0.0 ).rgb;
471524}
472525
473- vec3 trace_indirect_light(vec3 p_position, vec3 p_ray_dir, inout uint r_noise) {
526+ vec3 trace_indirect_light(vec3 p_position, vec3 p_ray_dir, inout uint r_noise, float p_texel_size ) {
474527 // The lower limit considers the case where the lightmapper might have bounces disabled but light probes are requested.
475528 vec3 position = p_position;
476529 vec3 ray_dir = p_ray_dir;
@@ -502,7 +555,7 @@ vec3 trace_indirect_light(vec3 p_position, vec3 p_ray_dir, inout uint r_noise) {
502555 for (uint i = 0 ; i < bake_params.light_count; i++ ) {
503556 vec3 light;
504557 vec3 light_dir;
505- trace_direct_light(position, normal, i, false, light, light_dir, r_noise);
558+ trace_direct_light(position, normal, i, false, light, light_dir, r_noise, p_texel_size );
506559 direct_light += light * lights.data[i].indirect_energy;
507560 }
508561
@@ -566,6 +619,14 @@ void main() {
566619 return ; // empty texel, no process
567620 }
568621 vec3 position = texelFetch(sampler2DArray (source_position, linear_sampler), ivec3 (atlas_pos, params.atlas_slice), 0 ).xyz;
622+ vec4 neighbor_position = texelFetch(sampler2DArray (source_position, linear_sampler), ivec3 (atlas_pos + ivec2 (1 , 0 ), params.atlas_slice), 0 ).xyzw;
623+
624+ if (neighbor_position.w < 0.001 ) {
625+ // Empty texel, try again.
626+ neighbor_position.xyz = texelFetch(sampler2DArray (source_position, linear_sampler), ivec3 (atlas_pos + ivec2 (- 1 , 0 ), params.atlas_slice), 0 ).xyz;
627+ }
628+ float texel_size_world_space = distance (position, neighbor_position.xyz);
629+
569630 vec3 light_for_texture = vec3 (0.0 );
570631 vec3 light_for_bounces = vec3 (0.0 );
571632
@@ -582,7 +643,7 @@ void main() {
582643 for (uint i = 0 ; i < bake_params.light_count; i++ ) {
583644 vec3 light;
584645 vec3 light_dir;
585- trace_direct_light(position, normal, i, true, light, light_dir, noise);
646+ trace_direct_light(position, normal, i, true, light, light_dir, noise, texel_size_world_space );
586647
587648 if (lights.data[i].static_bake) {
588649 light_for_texture += light;
@@ -640,10 +701,13 @@ void main() {
640701 }
641702
642703 vec3 position = texelFetch(sampler2DArray (source_position, linear_sampler), ivec3 (atlas_pos, params.atlas_slice), 0 ).xyz;
704+ int neighbor_offset = atlas_pos.x < bake_params.atlas_size.x - 1 ? 1 : - 1 ;
705+ vec3 neighbor_position = texelFetch(sampler2DArray (source_position, linear_sampler), ivec3 (atlas_pos + ivec2 (neighbor_offset, 0 ), params.atlas_slice), 0 ).xyz;
706+ float texel_size_world_space = distance (position, neighbor_position);
643707 uint noise = random_seed(ivec3 (params.ray_from, atlas_pos));
644708 for (uint i = params.ray_from; i < params.ray_to; i++ ) {
645709 vec3 ray_dir = generate_ray_dir_from_normal(normal, noise);
646- vec3 light = trace_indirect_light(position, ray_dir, noise);
710+ vec3 light = trace_indirect_light(position, ray_dir, noise, texel_size_world_space );
647711
648712#ifdef USE_SH_LIGHTMAPS
649713 float c[4 ] = float [](
@@ -737,7 +801,7 @@ void main() {
737801 uint noise = random_seed(ivec3 (params.ray_from, probe_index, 49502741 /* some prime */ ));
738802 for (uint i = params.ray_from; i < params.ray_to; i++ ) {
739803 vec3 ray_dir = generate_sphere_uniform_direction(noise);
740- vec3 light = trace_indirect_light(position, ray_dir, noise);
804+ vec3 light = trace_indirect_light(position, ray_dir, noise, 0.0 );
741805
742806 float c[9 ] = float [](
743807 0.282095 , // l0
0 commit comments