22
33#define PI 3.14159
44#define TWO_PI (PI * 2.0 )
5+ #define FLOAT_MAX 3.402823e38
56
67#define LIGHTS_MAX 32
78#define RAY_COUNT 360
@@ -29,7 +30,6 @@ in vec2 TexCoord;
2930out vec4 out_Color;
3031
3132layout (binding = 0 ) uniform sampler2D u_OpacityMap;
32- layout (binding = 0 , r32ui) uniform uimageBuffer u_RayBuffer;
3333
3434layout (std140, binding = 2 ) uniform Scene {
3535 vec4 AmbientLightColor;
@@ -43,38 +43,87 @@ layout(std140, binding = 3) uniform Viewport {
4343 Light2D Lights[32 ];
4444} viewport;
4545
46+ vec2 world_to_uv(vec2 world_pos) {
47+ return (viewport.ViewMatrix * vec4 (world_pos, 0.0 , 1.0 )).xy * 0.5 + 0.5 ;
48+ }
49+
50+ vec2 uv_to_world(vec2 uv) {
51+ return (viewport.ViewMatrixInverse * vec4 (uv * 2.0 - 1.0 , 0.0 , 1.0 )).xy;
52+ }
53+
4654void main() {
47- if (viewport.LightCount == 0 ) {
55+ int buf_len = LIGHTS_MAX * RAY_COUNT;
56+ int global_index = int (TexCoord.x * buf_len);
57+ uint light_index = uint (TexCoord.y * LIGHTS_MAX);
58+
59+ if (light_index >= viewport.LightCount) {
4860 discard ;
4961 }
5062
51- if (texture(u_OpacityMap, TexCoord).r == 0.0 ) {
52- // pixel is transparent to light
63+ Light2D light = viewport.Lights[light_index];
64+ if (light.is_occludable == 0U) {
5365 discard ;
5466 }
5567
56- for (int i = 0 ; i < LIGHTS_MAX; i++ ) {
57- if (i >= viewport.LightCount) {
58- break ;
59- }
68+ uint ray_index = uint (TexCoord.x * RAY_COUNT);
69+
70+ vec2 light_pos_uv = world_to_uv(light.position.xy);
71+
72+ float theta = float (ray_index) * TWO_PI / float (RAY_COUNT) - PI;
73+ vec2 dir_world = vec2 (cos (theta), sin (theta));
74+ vec2 dir_uv = (viewport.ViewMatrix * vec4 (dir_world, 0.0 , 0.0 )).xy;
75+ vec2 dir_uv_unit = normalize (dir_uv);
76+
77+ float max_world_dist = light.falloff_buffer + light.falloff_distance + light.shadow_falloff_distance;
78+ float max_uv_dist = max_world_dist * length (dir_uv) * 0.5 ;
79+
80+ vec2 inv_dir = 1.0 / dir_uv_unit;
81+
82+ vec2 t0 = (vec2 (0.0 ) - light_pos_uv) * inv_dir;
83+ vec2 t1 = (vec2 (1.0 ) - light_pos_uv) * inv_dir;
6084
61- Light2D light = viewport.Lights[i];
62- vec2 light_pos = light.position.xy;
63- vec2 offset = WorldPos.xy - light_pos;
85+ vec2 t_min = min (t0, t1);
86+ vec2 t_max = max (t0, t1);
6487
65- if (abs (offset.x) < 0.01 && abs (offset.y) < 0.01 ) {
66- // light is fully occluded
67- for (int j = 0 ; j < RAY_COUNT; j++ ) {
68- imageAtomicExchange(u_RayBuffer, int (i * RAY_COUNT + j), 0 );
69- }
88+ float t_enter = max (max (t_min.x, t_min.y), 0.0 );
89+ float t_exit = min (t_max.x, t_max.y);
90+
91+ if (t_enter > t_exit) {
92+ out_Color = vec4 (FLOAT_MAX, 0.0 , 0.0 , 0.0 );
93+ return ;
94+ }
95+
96+ ivec2 map_size = textureSize(u_OpacityMap, 0 );
97+
98+ float nearest = FLOAT_MAX;
99+ ivec2 last_texel = ivec2 (- 1 );
100+ float step_uv = 1.0 / float (max (map_size.x, map_size.y));
101+ bool did_sample_in_frame = false;
102+ float t_end = min (t_exit, max_uv_dist);
103+ for (float dist_uv = t_enter; dist_uv <= t_end; dist_uv += step_uv) {
104+ vec2 sample_uv = light_pos_uv + dir_uv_unit * dist_uv;
105+ if (sample_uv.x <= 0.0 || sample_uv.y <= 0.0 || sample_uv.x >= 1.0 || sample_uv.y >= 1.0 ) {
70106 continue ;
71107 }
72108
73- float theta = atan (offset.y, offset.x) + PI;
74- uint ray_index = uint (floor (float (RAY_COUNT) * theta / TWO_PI));
75- uint dist = uint (distance (light_pos, WorldPos.xy) * DIST_MULTIPLIER);
76- imageAtomicMin(u_RayBuffer, int (i * RAY_COUNT + ray_index), dist);
109+ ivec2 sample_texel = ivec2 (sample_uv * vec2 (map_size));
110+ if (sample_texel == last_texel) {
111+ continue ;
112+ }
113+ last_texel = sample_texel;
114+
115+ did_sample_in_frame = true;
116+
117+ if (texelFetch(u_OpacityMap, sample_texel, 0 ).r > 0.0 ) {
118+ // pixel is opaque to light
119+ vec2 sample_world = uv_to_world(sample_uv);
120+ float dist_world = distance (sample_world, light.position.xy);
121+ nearest = dist_world;
122+ break ;
123+ }
124+
125+ // else pixel is transparent to light; continue marching
77126 }
78127
79- discard ;
128+ out_Color = vec4 (nearest, 0.0 , 0.0 , 0.0 ) ;
80129}
0 commit comments