@@ -213,6 +213,9 @@ layout(set = 0, binding = 19) uniform textureCube sky_texture;
213213#endif
214214#endif // MODE_COPY
215215
216+ layout (set = 0 , binding = 20 ) uniform texture2D decal_atlas_srgb;
217+ layout (set = 0 , binding = 21 ) uniform sampler light_projector_sampler;
218+
216219float get_depth_at_pos(float cell_depth_size, int z) {
217220 float d = float (z) * cell_depth_size + cell_depth_size * 0.5 ; // center of voxels
218221 d = pow (d, params.detail_spread);
@@ -276,7 +279,7 @@ const vec3 halton_map[TEMPORAL_FRAMES] = vec3[](
276279 vec3 (0.03125 , 0.59259259 , 0.32 ));
277280
278281// Higher values will make light in volumetric fog fade out sooner when it's occluded by shadow.
279- const float INV_FOG_FADE = 10 .0 ;
282+ const float INV_FOG_FADE = 300 .0 ; // TODO: We should change this constant to a user setting
280283
281284void main() {
282285 vec3 fog_cell_size = 1.0 / vec3 (params.fog_volume_size);
@@ -385,6 +388,7 @@ void main() {
385388 for (uint i = 0 ; i < params.directional_light_count; i++ ) {
386389 if (directional_lights.data[i].volumetric_fog_energy > 0.001 ) {
387390 vec3 shadow_attenuation = vec3 (1.0 );
391+ vec3 light_color = directional_lights.data[i].color;
388392
389393 if (directional_lights.data[i].shadow_opacity > 0.001 ) {
390394 float depth_z = - view_pos.z;
@@ -420,10 +424,24 @@ void main() {
420424
421425 shadow = mix (shadow, 1.0 , smoothstep (directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, view_pos.z)); // done with negative values for performance
422426
427+ // Compute projector color
428+ if (directional_lights.data[i].projector_rect != vec4 (0.0 )) {
429+ vec4 splane = (directional_lights.data[i].projector_matrix * v);
430+ splane /= splane.w;
431+
432+ splane.xy = (splane.xy * 0.5 + 0.5 ) * directional_lights.data[i].projector_scale.xy + directional_lights.data[i].projector_offset.xy;
433+ splane.xy = fract (splane.xy);
434+ vec2 proj_uv = splane.xy * directional_lights.data[i].projector_rect.zw;
435+
436+ vec4 proj = textureLod(sampler2D (decal_atlas_srgb, light_projector_sampler), proj_uv + directional_lights.data[i].projector_rect.xy, 0.0 );
437+
438+ light_color *= proj.rgb * proj.a;
439+ }
440+
423441 shadow_attenuation = mix (vec3 (1.0 - directional_lights.data[i].shadow_opacity), vec3 (1.0 ), shadow);
424442 }
425443
426- total_light += shadow_attenuation * directional_lights.data[i].color * directional_lights.data[i].energy * henyey_greenstein(dot (normalize (view_pos), normalize (directional_lights.data[i].direction)), params.phase_g) * directional_lights.data[i].volumetric_fog_energy;
444+ total_light += shadow_attenuation * light_color * directional_lights.data[i].energy * henyey_greenstein(dot (normalize (view_pos), normalize (directional_lights.data[i].direction)), params.phase_g) * directional_lights.data[i].volumetric_fog_energy;
427445 }
428446 }
429447
@@ -505,13 +523,16 @@ void main() {
505523
506524 float shadow_len = length (local_vert); // need to remember shadow len from here
507525 vec3 shadow_sample = normalize (local_vert);
526+ float original_shadow_sample_z = shadow_sample.z;
508527
509- if (shadow_sample.z >= 0.0 ) {
528+ if (original_shadow_sample_z >= 0.0 ) {
510529 uv_rect.xy += flip_offset;
511530 }
512531
513532 shadow_sample.z = 1.0 + abs (shadow_sample.z);
514- vec3 pos = vec3 (shadow_sample.xy / shadow_sample.z, shadow_len - omni_lights.data[light_index].shadow_bias);
533+ shadow_sample.xy /= shadow_sample.z;
534+
535+ vec3 pos = vec3 (shadow_sample.xy, shadow_len - omni_lights.data[light_index].shadow_bias);
515536 pos.z *= omni_lights.data[light_index].inv_radius;
516537 pos.z = 1.0 - pos.z;
517538
@@ -520,6 +541,19 @@ void main() {
520541
521542 float depth = texture(sampler2D (shadow_atlas, linear_sampler), pos.xy).r;
522543
544+ // Compute projector color
545+ if (omni_lights.data[light_index].projector_rect != vec4 (0.0 )) {
546+ vec4 atlas_rect = omni_lights.data[light_index].projector_rect;
547+ if (original_shadow_sample_z >= 0.0 ) {
548+ atlas_rect.y += atlas_rect.w;
549+ }
550+
551+ vec2 proj_uv = (shadow_sample.xy * 0.5 + 0.5 ) * atlas_rect.zw;
552+
553+ vec4 proj = textureLod(sampler2D (decal_atlas_srgb, light_projector_sampler), proj_uv + atlas_rect.xy, 0.0 );
554+ light *= proj.rgb * proj.a;
555+ }
556+
523557 shadow_attenuation = mix (1.0 - omni_lights.data[light_index].shadow_opacity, 1.0 , exp (min (0.0 , (pos.z - depth)) / omni_lights.data[light_index].inv_radius * INV_FOG_FADE));
524558 }
525559 total_light += light * attenuation * shadow_attenuation * henyey_greenstein(dot (normalize (light_pos - view_pos), normalize (view_pos)), params.phase_g) * omni_lights.data[light_index].volumetric_fog_energy;
@@ -598,6 +632,14 @@ void main() {
598632
599633 float depth = texture(sampler2D (shadow_atlas, linear_sampler), pos.xy).r;
600634
635+ // Compute projector color
636+ if (spot_lights.data[light_index].projector_rect != vec4 (0.0 )) {
637+ vec2 proj_uv = splane.xy * spot_lights.data[light_index].projector_rect.zw;
638+
639+ vec4 proj = textureLod(sampler2D (decal_atlas_srgb, light_projector_sampler), proj_uv + spot_lights.data[light_index].projector_rect.xy, 0.0 );
640+ light *= proj.rgb * proj.a;
641+ }
642+
601643 shadow_attenuation = mix (1.0 - spot_lights.data[light_index].shadow_opacity, 1.0 , exp (min (0.0 , (pos.z - depth)) / spot_lights.data[light_index].inv_radius * INV_FOG_FADE));
602644 }
603645 total_light += light * attenuation * shadow_attenuation * henyey_greenstein(dot (normalize (light_rel_vec), normalize (view_pos)), params.phase_g) * spot_lights.data[light_index].volumetric_fog_energy;
0 commit comments