summaryrefslogtreecommitdiff
path: root/servers/rendering/renderer_rd/shaders
diff options
context:
space:
mode:
Diffstat (limited to 'servers/rendering/renderer_rd/shaders')
-rw-r--r--servers/rendering/renderer_rd/shaders/blit.glsl6
-rw-r--r--servers/rendering/renderer_rd/shaders/blur_raster.glsl138
-rw-r--r--servers/rendering/renderer_rd/shaders/blur_raster_inc.glsl21
-rw-r--r--servers/rendering/renderer_rd/shaders/bokeh_dof.glsl38
-rw-r--r--servers/rendering/renderer_rd/shaders/bokeh_dof_inc.glsl37
-rw-r--r--servers/rendering/renderer_rd/shaders/bokeh_dof_raster.glsl253
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas.glsl110
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas_sdf.glsl60
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/cluster_render.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/cube_to_dp.glsl14
-rw-r--r--servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl48
-rw-r--r--servers/rendering/renderer_rd/shaders/cubemap_downsampler_inc.glsl48
-rw-r--r--servers/rendering/renderer_rd/shaders/cubemap_downsampler_raster.glsl163
-rw-r--r--servers/rendering/renderer_rd/shaders/cubemap_filter_raster.glsl256
-rw-r--r--servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl95
-rw-r--r--servers/rendering/renderer_rd/shaders/cubemap_roughness_inc.glsl94
-rw-r--r--servers/rendering/renderer_rd/shaders/cubemap_roughness_raster.glsl63
-rw-r--r--servers/rendering/renderer_rd/shaders/decal_data_inc.glsl28
-rw-r--r--servers/rendering/renderer_rd/shaders/fsr_upscale.glsl173
-rw-r--r--servers/rendering/renderer_rd/shaders/gi.glsl97
-rw-r--r--servers/rendering/renderer_rd/shaders/giprobe_write.glsl47
-rw-r--r--servers/rendering/renderer_rd/shaders/light_data_inc.glsl104
-rw-r--r--servers/rendering/renderer_rd/shaders/luminance_reduce_raster.glsl74
-rw-r--r--servers/rendering/renderer_rd/shaders/luminance_reduce_raster_inc.glsl11
-rw-r--r--servers/rendering/renderer_rd/shaders/particles.glsl238
-rw-r--r--servers/rendering/renderer_rd/shaders/particles_copy.glsl49
-rw-r--r--servers/rendering/renderer_rd/shaders/resolve.glsl38
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_aa_inc.glsl5
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl921
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl62
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl32
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl463
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl239
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl134
-rw-r--r--servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl15
-rw-r--r--servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl8
-rw-r--r--servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl6
-rw-r--r--servers/rendering/renderer_rd/shaders/sky.glsl46
-rw-r--r--servers/rendering/renderer_rd/shaders/tonemap.glsl133
-rw-r--r--servers/rendering/renderer_rd/shaders/volumetric_fog.glsl755
-rw-r--r--servers/rendering/renderer_rd/shaders/volumetric_fog_process.glsl776
-rw-r--r--servers/rendering/renderer_rd/shaders/voxel_gi.glsl (renamed from servers/rendering/renderer_rd/shaders/giprobe.glsl)162
-rw-r--r--servers/rendering/renderer_rd/shaders/voxel_gi_debug.glsl (renamed from servers/rendering/renderer_rd/shaders/giprobe_debug.glsl)5
-rw-r--r--servers/rendering/renderer_rd/shaders/voxel_gi_sdf.glsl (renamed from servers/rendering/renderer_rd/shaders/giprobe_sdf.glsl)0
47 files changed, 3814 insertions, 2261 deletions
diff --git a/servers/rendering/renderer_rd/shaders/blit.glsl b/servers/rendering/renderer_rd/shaders/blit.glsl
index 967da1e6e4..8051f96738 100644
--- a/servers/rendering/renderer_rd/shaders/blit.glsl
+++ b/servers/rendering/renderer_rd/shaders/blit.glsl
@@ -5,6 +5,7 @@
#VERSION_DEFINES
layout(push_constant, binding = 0, std140) uniform Pos {
+ vec4 src_rect;
vec4 dst_rect;
vec2 eye_center;
@@ -22,8 +23,8 @@ layout(location = 0) out vec2 uv;
void main() {
vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
- uv = base_arr[gl_VertexIndex];
- vec2 vtx = data.dst_rect.xy + uv * data.dst_rect.zw;
+ uv = data.src_rect.xy + base_arr[gl_VertexIndex] * data.src_rect.zw;
+ vec2 vtx = data.dst_rect.xy + base_arr[gl_VertexIndex] * data.dst_rect.zw;
gl_Position = vec4(vtx * 2.0 - 1.0, 0.0, 1.0);
}
@@ -34,6 +35,7 @@ void main() {
#VERSION_DEFINES
layout(push_constant, binding = 0, std140) uniform Pos {
+ vec4 src_rect;
vec4 dst_rect;
vec2 eye_center;
diff --git a/servers/rendering/renderer_rd/shaders/blur_raster.glsl b/servers/rendering/renderer_rd/shaders/blur_raster.glsl
new file mode 100644
index 0000000000..f8b4e3f610
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/blur_raster.glsl
@@ -0,0 +1,138 @@
+/* clang-format off */
+#[vertex]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "blur_raster_inc.glsl"
+
+layout(location = 0) out vec2 uv_interp;
+/* clang-format on */
+
+void main() {
+ vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
+ uv_interp = base_arr[gl_VertexIndex];
+
+ gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0);
+}
+
+/* clang-format off */
+#[fragment]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "blur_raster_inc.glsl"
+
+layout(location = 0) in vec2 uv_interp;
+/* clang-format on */
+
+layout(set = 0, binding = 0) uniform sampler2D source_color;
+
+#ifdef GLOW_USE_AUTO_EXPOSURE
+layout(set = 1, binding = 0) uniform sampler2D source_auto_exposure;
+#endif
+
+layout(location = 0) out vec4 frag_color;
+
+void main() {
+ // We do not apply our color scale for our mobile renderer here, we'll leave our colors at half brightness and apply scale in the tonemap raster.
+
+#ifdef MODE_MIPMAP
+
+ vec2 pix_size = blur.pixel_size;
+ vec4 color = texture(source_color, uv_interp + vec2(-0.5, -0.5) * pix_size);
+ color += texture(source_color, uv_interp + vec2(0.5, -0.5) * pix_size);
+ color += texture(source_color, uv_interp + vec2(0.5, 0.5) * pix_size);
+ color += texture(source_color, uv_interp + vec2(-0.5, 0.5) * pix_size);
+ frag_color = color / 4.0;
+
+#endif
+
+#ifdef MODE_GAUSSIAN_BLUR
+
+ //Simpler blur uses SIGMA2 for the gaussian kernel for a stronger effect
+
+ if (bool(blur.flags & FLAG_HORIZONTAL)) {
+ vec2 pix_size = blur.pixel_size;
+ pix_size *= 0.5; //reading from larger buffer, so use more samples
+ vec4 color = texture(source_color, uv_interp + vec2(0.0, 0.0) * pix_size) * 0.214607;
+ color += texture(source_color, uv_interp + vec2(1.0, 0.0) * pix_size) * 0.189879;
+ color += texture(source_color, uv_interp + vec2(2.0, 0.0) * pix_size) * 0.131514;
+ color += texture(source_color, uv_interp + vec2(3.0, 0.0) * pix_size) * 0.071303;
+ color += texture(source_color, uv_interp + vec2(-1.0, 0.0) * pix_size) * 0.189879;
+ color += texture(source_color, uv_interp + vec2(-2.0, 0.0) * pix_size) * 0.131514;
+ color += texture(source_color, uv_interp + vec2(-3.0, 0.0) * pix_size) * 0.071303;
+ frag_color = color;
+ } else {
+ vec2 pix_size = blur.pixel_size;
+ vec4 color = texture(source_color, uv_interp + vec2(0.0, 0.0) * pix_size) * 0.38774;
+ color += texture(source_color, uv_interp + vec2(0.0, 1.0) * pix_size) * 0.24477;
+ color += texture(source_color, uv_interp + vec2(0.0, 2.0) * pix_size) * 0.06136;
+ color += texture(source_color, uv_interp + vec2(0.0, -1.0) * pix_size) * 0.24477;
+ color += texture(source_color, uv_interp + vec2(0.0, -2.0) * pix_size) * 0.06136;
+ frag_color = color;
+ }
+#endif
+
+#ifdef MODE_GAUSSIAN_GLOW
+
+ //Glow uses larger sigma 1 for a more rounded blur effect
+
+#define GLOW_ADD(m_ofs, m_mult) \
+ { \
+ vec2 ofs = uv_interp + m_ofs * pix_size; \
+ vec4 c = texture(source_color, ofs) * m_mult; \
+ if (any(lessThan(ofs, vec2(0.0))) || any(greaterThan(ofs, vec2(1.0)))) { \
+ c *= 0.0; \
+ } \
+ color += c; \
+ }
+
+ if (bool(blur.flags & FLAG_HORIZONTAL)) {
+ vec2 pix_size = blur.pixel_size;
+ pix_size *= 0.5; //reading from larger buffer, so use more samples
+ vec4 color = texture(source_color, uv_interp + vec2(0.0, 0.0) * pix_size) * 0.174938;
+ GLOW_ADD(vec2(1.0, 0.0), 0.165569);
+ GLOW_ADD(vec2(2.0, 0.0), 0.140367);
+ GLOW_ADD(vec2(3.0, 0.0), 0.106595);
+ GLOW_ADD(vec2(-1.0, 0.0), 0.165569);
+ GLOW_ADD(vec2(-2.0, 0.0), 0.140367);
+ GLOW_ADD(vec2(-3.0, 0.0), 0.106595);
+ color *= blur.glow_strength;
+ frag_color = color;
+ } else {
+ vec2 pix_size = blur.pixel_size;
+ vec4 color = texture(source_color, uv_interp + vec2(0.0, 0.0) * pix_size) * 0.288713;
+ GLOW_ADD(vec2(0.0, 1.0), 0.233062);
+ GLOW_ADD(vec2(0.0, 2.0), 0.122581);
+ GLOW_ADD(vec2(0.0, -1.0), 0.233062);
+ GLOW_ADD(vec2(0.0, -2.0), 0.122581);
+ color *= blur.glow_strength;
+ frag_color = color;
+ }
+
+#undef GLOW_ADD
+
+ if (bool(blur.flags & FLAG_GLOW_FIRST_PASS)) {
+#ifdef GLOW_USE_AUTO_EXPOSURE
+
+ frag_color /= texelFetch(source_auto_exposure, ivec2(0, 0), 0).r / blur.glow_auto_exposure_grey;
+#endif
+ frag_color *= blur.glow_exposure;
+
+ float luminance = max(frag_color.r, max(frag_color.g, frag_color.b));
+ float feedback = max(smoothstep(blur.glow_hdr_threshold, blur.glow_hdr_threshold + blur.glow_hdr_scale, luminance), blur.glow_bloom);
+
+ frag_color = min(frag_color * feedback, vec4(blur.glow_luminance_cap));
+ }
+
+#endif
+
+#ifdef MODE_COPY
+ vec4 color = textureLod(source_color, uv_interp, 0.0);
+ frag_color = color;
+#endif
+}
diff --git a/servers/rendering/renderer_rd/shaders/blur_raster_inc.glsl b/servers/rendering/renderer_rd/shaders/blur_raster_inc.glsl
new file mode 100644
index 0000000000..52bf2886b5
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/blur_raster_inc.glsl
@@ -0,0 +1,21 @@
+#define FLAG_HORIZONTAL (1 << 0)
+#define FLAG_USE_ORTHOGONAL_PROJECTION (1 << 1)
+#define FLAG_GLOW_FIRST_PASS (1 << 2)
+
+layout(push_constant, binding = 1, std430) uniform Blur {
+ vec2 pixel_size;
+ uint flags;
+ uint pad;
+
+ // Glow.
+ float glow_strength;
+ float glow_bloom;
+ float glow_hdr_threshold;
+ float glow_hdr_scale;
+
+ float glow_exposure;
+ float glow_white;
+ float glow_luminance_cap;
+ float glow_auto_exposure_grey;
+}
+blur;
diff --git a/servers/rendering/renderer_rd/shaders/bokeh_dof.glsl b/servers/rendering/renderer_rd/shaders/bokeh_dof.glsl
index b70e0b6bd5..0438671dd2 100644
--- a/servers/rendering/renderer_rd/shaders/bokeh_dof.glsl
+++ b/servers/rendering/renderer_rd/shaders/bokeh_dof.glsl
@@ -25,34 +25,7 @@ layout(set = 1, binding = 0) uniform sampler2D source_bokeh;
// based on https://www.shadertoy.com/view/Xd3GDl
-layout(push_constant, binding = 1, std430) uniform Params {
- ivec2 size;
- float z_far;
- float z_near;
-
- bool orthogonal;
- float blur_size;
- float blur_scale;
- int blur_steps;
-
- bool blur_near_active;
- float blur_near_begin;
- float blur_near_end;
- bool blur_far_active;
-
- float blur_far_begin;
- float blur_far_end;
- bool second_pass;
- bool half_size;
-
- bool use_jitter;
- float jitter_seed;
- uint pad[2];
-}
-params;
-
-//used to work around downsampling filter
-#define DEPTH_GAP 0.0
+#include "bokeh_dof_inc.glsl"
#ifdef MODE_GEN_BLUR_SIZE
@@ -80,15 +53,6 @@ float get_blur_size(float depth) {
#endif
-const float GOLDEN_ANGLE = 2.39996323;
-
-//note: uniform pdf rand [0;1[
-float hash12n(vec2 p) {
- p = fract(p * vec2(5.3987, 5.4421));
- p += dot(p.yx, p.xy + vec2(21.5351, 14.3137));
- return fract(p.x * p.y * 95.4307);
-}
-
#if defined(MODE_BOKEH_BOX) || defined(MODE_BOKEH_HEXAGONAL)
vec4 weighted_filter_dir(vec2 dir, vec2 uv, vec2 pixel_size) {
diff --git a/servers/rendering/renderer_rd/shaders/bokeh_dof_inc.glsl b/servers/rendering/renderer_rd/shaders/bokeh_dof_inc.glsl
new file mode 100644
index 0000000000..fadea1631c
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/bokeh_dof_inc.glsl
@@ -0,0 +1,37 @@
+layout(push_constant, binding = 1, std430) uniform Params {
+ ivec2 size;
+ float z_far;
+ float z_near;
+
+ bool orthogonal;
+ float blur_size;
+ float blur_scale;
+ int blur_steps;
+
+ bool blur_near_active;
+ float blur_near_begin;
+ float blur_near_end;
+ bool blur_far_active;
+
+ float blur_far_begin;
+ float blur_far_end;
+ bool second_pass;
+ bool half_size;
+
+ bool use_jitter;
+ float jitter_seed;
+ uint pad[2];
+}
+params;
+
+//used to work around downsampling filter
+#define DEPTH_GAP 0.0
+
+const float GOLDEN_ANGLE = 2.39996323;
+
+//note: uniform pdf rand [0;1[
+float hash12n(vec2 p) {
+ p = fract(p * vec2(5.3987, 5.4421));
+ p += dot(p.yx, p.xy + vec2(21.5351, 14.3137));
+ return fract(p.x * p.y * 95.4307);
+}
diff --git a/servers/rendering/renderer_rd/shaders/bokeh_dof_raster.glsl b/servers/rendering/renderer_rd/shaders/bokeh_dof_raster.glsl
new file mode 100644
index 0000000000..a3b3938ee9
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/bokeh_dof_raster.glsl
@@ -0,0 +1,253 @@
+/* clang-format off */
+#[vertex]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "bokeh_dof_inc.glsl"
+
+layout(location = 0) out vec2 uv_interp;
+/* clang-format on */
+
+void main() {
+ vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
+ uv_interp = base_arr[gl_VertexIndex];
+
+ gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0);
+}
+
+/* clang-format off */
+#[fragment]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "bokeh_dof_inc.glsl"
+
+layout(location = 0) in vec2 uv_interp;
+/* clang-format on */
+
+#ifdef MODE_GEN_BLUR_SIZE
+layout(location = 0) out float weight;
+
+layout(set = 0, binding = 0) uniform sampler2D source_depth;
+#else
+layout(location = 0) out vec4 frag_color;
+#ifdef OUTPUT_WEIGHT
+layout(location = 1) out float weight;
+#endif
+
+layout(set = 0, binding = 0) uniform sampler2D source_color;
+layout(set = 1, binding = 0) uniform sampler2D source_weight;
+#ifdef MODE_COMPOSITE_BOKEH
+layout(set = 2, binding = 0) uniform sampler2D original_weight;
+#endif
+#endif
+
+//DOF
+// Bokeh single pass implementation based on https://tuxedolabs.blogspot.com/2018/05/bokeh-depth-of-field-in-single-pass.html
+
+#ifdef MODE_GEN_BLUR_SIZE
+
+float get_depth_at_pos(vec2 uv) {
+ float depth = textureLod(source_depth, uv, 0.0).x;
+ if (params.orthogonal) {
+ depth = ((depth + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0;
+ } else {
+ depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - depth * (params.z_far - params.z_near));
+ }
+ return depth;
+}
+
+float get_blur_size(float depth) {
+ if (params.blur_near_active && depth < params.blur_near_begin) {
+ return -(1.0 - smoothstep(params.blur_near_end, params.blur_near_begin, depth)) * params.blur_size - DEPTH_GAP; //near blur is negative
+ }
+
+ if (params.blur_far_active && depth > params.blur_far_begin) {
+ return smoothstep(params.blur_far_begin, params.blur_far_end, depth) * params.blur_size + DEPTH_GAP;
+ }
+
+ return 0.0;
+}
+
+#endif
+
+#if defined(MODE_BOKEH_BOX) || defined(MODE_BOKEH_HEXAGONAL)
+
+vec4 weighted_filter_dir(vec2 dir, vec2 uv, vec2 pixel_size) {
+ dir *= pixel_size;
+ vec4 color = texture(source_color, uv);
+ color.a = texture(source_weight, uv).r;
+
+ vec4 accum = color;
+ float total = 1.0;
+
+ float blur_scale = params.blur_size / float(params.blur_steps);
+
+ if (params.use_jitter) {
+ uv += dir * (hash12n(uv + params.jitter_seed) - 0.5);
+ }
+
+ for (int i = -params.blur_steps; i <= params.blur_steps; i++) {
+ if (i == 0) {
+ continue;
+ }
+ float radius = float(i) * blur_scale;
+ vec2 suv = uv + dir * radius;
+ radius = abs(radius);
+
+ vec4 sample_color = texture(source_color, suv);
+ sample_color.a = texture(source_weight, suv).r;
+ float limit;
+
+ if (sample_color.a < color.a) {
+ limit = abs(sample_color.a);
+ } else {
+ limit = abs(color.a);
+ }
+
+ limit -= DEPTH_GAP;
+
+ float m = smoothstep(radius - 0.5, radius + 0.5, limit);
+
+ accum += mix(color, sample_color, m);
+
+ total += 1.0;
+ }
+
+ return accum / total;
+}
+
+#endif
+
+void main() {
+ vec2 pixel_size = 1.0 / vec2(params.size);
+ vec2 uv = uv_interp;
+
+#ifdef MODE_GEN_BLUR_SIZE
+ uv += pixel_size * 0.5;
+ float center_depth = get_depth_at_pos(uv);
+ weight = get_blur_size(center_depth);
+#endif
+
+#ifdef MODE_BOKEH_BOX
+ //pixel_size*=0.5; //resolution is doubled
+ if (params.second_pass || !params.half_size) {
+ uv += pixel_size * 0.5; //half pixel to read centers
+ } else {
+ uv += pixel_size * 0.25; //half pixel to read centers from full res
+ }
+
+ float alpha = texture(source_color, uv).a; // retain this
+ vec2 dir = (params.second_pass ? vec2(0.0, 1.0) : vec2(1.0, 0.0));
+
+ vec4 color = weighted_filter_dir(dir, uv, pixel_size);
+
+ frag_color = color;
+ frag_color.a = alpha; // attempt to retain this in case we have a transparent background, ignored if half_size
+#ifdef OUTPUT_WEIGHT
+ weight = color.a;
+#endif
+
+#endif
+
+#ifdef MODE_BOKEH_HEXAGONAL
+
+ //pixel_size*=0.5; //resolution is doubled
+ if (params.second_pass || !params.half_size) {
+ uv += pixel_size * 0.5; //half pixel to read centers
+ } else {
+ uv += pixel_size * 0.25; //half pixel to read centers from full res
+ }
+
+ float alpha = texture(source_color, uv).a; // retain this
+
+ vec2 dir = (params.second_pass ? normalize(vec2(1.0, 0.577350269189626)) : vec2(0.0, 1.0));
+
+ vec4 color = weighted_filter_dir(dir, uv, pixel_size);
+
+ if (params.second_pass) {
+ dir = normalize(vec2(-1.0, 0.577350269189626));
+
+ vec4 color2 = weighted_filter_dir(dir, uv, pixel_size);
+
+ color.rgb = min(color.rgb, color2.rgb);
+ color.a = (color.a + color2.a) * 0.5;
+ }
+
+ frag_color = color;
+ frag_color.a = alpha; // attempt to retain this in case we have a transparent background, ignored if half_size
+#ifdef OUTPUT_WEIGHT
+ weight = color.a;
+#endif
+
+#endif
+
+#ifdef MODE_BOKEH_CIRCULAR
+ if (params.half_size) {
+ pixel_size *= 0.5; //resolution is doubled
+ }
+
+ uv += pixel_size * 0.5; //half pixel to read centers
+
+ vec4 color = texture(source_color, uv);
+ float alpha = color.a; // retain this
+ color.a = texture(source_weight, uv).r;
+
+ vec4 color_accum = color;
+ float accum = 1.0;
+
+ float radius = params.blur_scale;
+ for (float ang = 0.0; radius < params.blur_size; ang += GOLDEN_ANGLE) {
+ vec2 uv_adj = uv + vec2(cos(ang), sin(ang)) * pixel_size * radius;
+
+ vec4 sample_color = texture(source_color, uv_adj);
+ sample_color.a = texture(source_weight, uv_adj).r;
+
+ float limit;
+
+ if (sample_color.a < color.a) {
+ limit = abs(sample_color.a);
+ } else {
+ limit = abs(color.a);
+ }
+
+ limit -= DEPTH_GAP;
+
+ float m = smoothstep(radius - 0.5, radius + 0.5, limit);
+ color_accum += mix(color_accum / accum, sample_color, m);
+ accum += 1.0;
+
+ radius += params.blur_scale / radius;
+ }
+
+ color_accum = color_accum / accum;
+
+ frag_color.rgb = color_accum.rgb;
+ frag_color.a = alpha; // attempt to retain this in case we have a transparent background, ignored if half_size
+#ifdef OUTPUT_WEIGHT
+ weight = color_accum.a;
+#endif
+
+#endif
+
+#ifdef MODE_COMPOSITE_BOKEH
+ frag_color.rgb = texture(source_color, uv).rgb;
+
+ float center_weigth = texture(source_weight, uv).r;
+ float sample_weight = texture(original_weight, uv).r;
+
+ float mix_amount;
+ if (sample_weight < center_weigth) {
+ mix_amount = min(1.0, max(0.0, max(abs(center_weigth), abs(sample_weight)) - DEPTH_GAP));
+ } else {
+ mix_amount = min(1.0, max(0.0, abs(center_weigth) - DEPTH_GAP));
+ }
+
+ // let alpha blending take care of mixing
+ frag_color.a = mix_amount;
+#endif
+}
diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl
index cf4c77db0d..65a621b203 100644
--- a/servers/rendering/renderer_rd/shaders/canvas.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas.glsl
@@ -65,7 +65,7 @@ void main() {
#elif defined(USE_ATTRIBUTES)
vec2 vertex = vertex_attrib;
- vec4 color = color_attrib;
+ vec4 color = color_attrib * draw_data.modulation;
vec2 uv = uv_attrib;
uvec4 bones = bone_attrib;
@@ -91,7 +91,6 @@ void main() {
uint instancing = draw_data.flags & FLAGS_INSTANCING_MASK;
#ifdef USE_ATTRIBUTES
-
if (instancing > 1) {
// trails
@@ -101,66 +100,64 @@ void main() {
uint offset = trail_size * stride * gl_InstanceIndex;
- mat4 matrix;
vec4 pcolor;
+ vec2 new_vertex;
{
uint boffset = offset + bone_attrib.x * stride;
- matrix = mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.x;
- pcolor = transforms.data[boffset + 3] * weight_attrib.x;
+ new_vertex = (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.x;
+ pcolor = transforms.data[boffset + 2] * weight_attrib.x;
}
if (weight_attrib.y > 0.001) {
uint boffset = offset + bone_attrib.y * stride;
- matrix += mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.y;
- pcolor += transforms.data[boffset + 3] * weight_attrib.y;
+ new_vertex += (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.y;
+ pcolor += transforms.data[boffset + 2] * weight_attrib.y;
}
if (weight_attrib.z > 0.001) {
uint boffset = offset + bone_attrib.z * stride;
- matrix += mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.z;
- pcolor += transforms.data[boffset + 3] * weight_attrib.z;
+ new_vertex += (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.z;
+ pcolor += transforms.data[boffset + 2] * weight_attrib.z;
}
if (weight_attrib.w > 0.001) {
uint boffset = offset + bone_attrib.w * stride;
- matrix += mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.w;
- pcolor += transforms.data[boffset + 3] * weight_attrib.w;
+ new_vertex += (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.w;
+ pcolor += transforms.data[boffset + 2] * weight_attrib.w;
}
- instance_custom = transforms.data[offset + 4];
+ instance_custom = transforms.data[offset + 3];
+ vertex = new_vertex;
color *= pcolor;
-
- matrix = transpose(matrix);
- world_matrix = world_matrix * matrix;
-
} else
#endif // USE_ATTRIBUTES
+ {
+ if (instancing == 1) {
+ uint stride = 2;
+ {
+ if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_COLORS)) {
+ stride += 1;
+ }
+ if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_CUSTOM_DATA)) {
+ stride += 1;
+ }
+ }
+
+ uint offset = stride * gl_InstanceIndex;
+
+ mat4 matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));
+ offset += 2;
- if (instancing == 1) {
- uint stride = 2;
- {
if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_COLORS)) {
- stride += 1;
+ color *= transforms.data[offset];
+ offset += 1;
}
+
if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_CUSTOM_DATA)) {
- stride += 1;
+ instance_custom = transforms.data[offset];
}
- }
- uint offset = stride * gl_InstanceIndex;
-
- mat4 matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));
- offset += 2;
-
- if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_COLORS)) {
- color *= transforms.data[offset];
- offset += 1;
+ matrix = transpose(matrix);
+ world_matrix = world_matrix * matrix;
}
-
- if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_CUSTOM_DATA)) {
- instance_custom = transforms.data[offset];
- }
-
- matrix = transpose(matrix);
- world_matrix = world_matrix * matrix;
}
#if !defined(USE_ATTRIBUTES) && !defined(USE_PRIMITIVE)
@@ -283,7 +280,7 @@ vec2 screen_uv_to_sdf(vec2 p_uv) {
float texture_sdf(vec2 p_sdf) {
vec2 uv = p_sdf * canvas_data.sdf_to_tex.xy + canvas_data.sdf_to_tex.zw;
float d = texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv).r;
- d = d * SDF_MAX_LENGTH - 1.0;
+ d *= SDF_MAX_LENGTH;
return d * canvas_data.tex_to_sdf;
}
@@ -460,6 +457,14 @@ void light_blend_compute(uint light_base, vec4 light_color, inout vec3 color) {
#endif
+float msdf_median(float r, float g, float b, float a) {
+ return min(max(min(r, g), min(max(r, g), b)), a);
+}
+
+vec2 msdf_map(vec2 value, vec2 in_min, vec2 in_max, vec2 out_min, vec2 out_max) {
+ return out_min + (out_max - out_min) * (value - in_min) / (in_max - in_min);
+}
+
void main() {
vec4 color = color_interp;
vec2 uv = uv_interp;
@@ -487,7 +492,34 @@ void main() {
#endif
- color *= texture(sampler2D(color_texture, texture_sampler), uv);
+#ifndef USE_PRIMITIVE
+ if (bool(draw_data.flags & FLAGS_USE_MSDF)) {
+ float px_range = draw_data.ninepatch_margins.x;
+ float outline_thickness = draw_data.ninepatch_margins.y;
+ //float reserved1 = draw_data.ninepatch_margins.z;
+ //float reserved2 = draw_data.ninepatch_margins.w;
+
+ vec4 msdf_sample = texture(sampler2D(color_texture, texture_sampler), uv);
+ vec2 msdf_size = vec2(textureSize(sampler2D(color_texture, texture_sampler), 0));
+ vec2 dest_size = vec2(1.0) / fwidth(uv);
+ float px_size = max(0.5 * dot((vec2(px_range) / msdf_size), dest_size), 1.0);
+ float d = msdf_median(msdf_sample.r, msdf_sample.g, msdf_sample.b, msdf_sample.a) - 0.5;
+
+ if (outline_thickness > 0) {
+ float cr = clamp(outline_thickness, 0.0, px_range / 2) / px_range;
+ float a = clamp((d + cr) * px_size, 0.0, 1.0);
+ color.a = a * color.a;
+ } else {
+ float a = clamp(d * px_size + 0.5, 0.0, 1.0);
+ color.a = a * color.a;
+ }
+
+ } else {
+#else
+ {
+#endif
+ color *= texture(sampler2D(color_texture, texture_sampler), uv);
+ }
uint light_count = (draw_data.flags >> FLAGS_LIGHT_COUNT_SHIFT) & 0xF; //max 16 lights
bool using_light = light_count > 0 || canvas_data.directional_light_count > 0;
diff --git a/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl b/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl
index 65a554e839..2bdfbabfcf 100644
--- a/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl
@@ -7,7 +7,7 @@
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
layout(r8, set = 0, binding = 1) uniform restrict readonly image2D src_pixels;
-layout(r16, set = 0, binding = 2) uniform restrict writeonly image2D dst_sdf;
+layout(r16_snorm, set = 0, binding = 2) uniform restrict writeonly image2D dst_sdf;
layout(rg16i, set = 0, binding = 3) uniform restrict readonly iimage2D src_process;
layout(rg16i, set = 0, binding = 4) uniform restrict writeonly iimage2D dst_process;
@@ -32,7 +32,7 @@ void main() {
#ifdef MODE_LOAD
bool solid = imageLoad(src_pixels, pos).r > 0.5;
- imageStore(dst_process, pos, solid ? ivec4(pos, 0, 0) : ivec4(ivec2(32767), 0, 0));
+ imageStore(dst_process, pos, solid ? ivec4(ivec2(-32767), 0, 0) : ivec4(ivec2(32767), 0, 0));
#endif
#ifdef MODE_LOAD_SHRINK
@@ -43,6 +43,8 @@ void main() {
ivec2 rel = ivec2(32767);
float d = 1e20;
+ int found = 0;
+ int solid_found = 0;
for (int i = 0; i < s; i++) {
for (int j = 0; j < s; j++) {
ivec2 src_pos = base + ivec2(i, j);
@@ -56,10 +58,17 @@ void main() {
d = dist;
rel = src_pos;
}
+ solid_found++;
}
+ found++;
}
}
+ if (solid_found == found) {
+ //mark solid only if all are solid
+ rel = ivec2(-32767);
+ }
+
imageStore(dst_process, pos, ivec4(rel, 0, 0));
#endif
@@ -70,6 +79,12 @@ void main() {
ivec2 rel = imageLoad(src_process, pos).xy;
+ bool solid = rel.x < 0;
+
+ if (solid) {
+ rel = -rel - ivec2(1);
+ }
+
if (center != rel) {
//only process if it does not point to itself
const int ofs_table_size = 8;
@@ -92,6 +107,15 @@ void main() {
continue;
}
ivec2 src_rel = imageLoad(src_process, src_pos).xy;
+ bool src_solid = src_rel.x < 0;
+ if (src_solid) {
+ src_rel = -src_rel - ivec2(1);
+ }
+
+ if (src_solid != solid) {
+ src_rel = ivec2(src_pos << params.shift); //point to itself if of different type
+ }
+
float src_dist = length(vec2(src_rel - center));
if (src_dist < dist) {
dist = src_dist;
@@ -100,18 +124,31 @@ void main() {
}
}
+ if (solid) {
+ rel = -rel - ivec2(1);
+ }
+
imageStore(dst_process, pos, ivec4(rel, 0, 0));
#endif
#ifdef MODE_STORE
ivec2 rel = imageLoad(src_process, pos).xy;
+
+ bool solid = rel.x < 0;
+
+ if (solid) {
+ rel = -rel - ivec2(1);
+ }
+
float d = length(vec2(rel - pos));
- if (d > 0.01) {
- d += 1.0; //make it signed
+
+ if (solid) {
+ d = -d;
}
+
d /= SDF_MAX_LENGTH;
- d = clamp(d, 0.0, 1.0);
+ d = clamp(d, -1.0, 1.0);
imageStore(dst_sdf, pos, vec4(d));
#endif
@@ -122,13 +159,20 @@ void main() {
ivec2 center = base + ivec2(params.shift);
ivec2 rel = imageLoad(src_process, pos).xy;
+
+ bool solid = rel.x < 0;
+
+ if (solid) {
+ rel = -rel - ivec2(1);
+ }
+
float d = length(vec2(rel - center));
- if (d > 0.01) {
- d += 1.0; //make it signed
+ if (solid) {
+ d = -d;
}
d /= SDF_MAX_LENGTH;
- d = clamp(d, 0.0, 1.0);
+ d = clamp(d, -1.0, 1.0);
imageStore(dst_sdf, pos, vec4(d));
#endif
diff --git a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
index 451f9b0089..0cff505cae 100644
--- a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
@@ -24,6 +24,8 @@
#define FLAGS_DEFAULT_NORMAL_MAP_USED (1 << 26)
#define FLAGS_DEFAULT_SPECULAR_MAP_USED (1 << 27)
+#define FLAGS_USE_MSDF (1 << 28)
+
#define SAMPLER_NEAREST_CLAMP 0
#define SAMPLER_LINEAR_CLAMP 1
#define SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP 2
diff --git a/servers/rendering/renderer_rd/shaders/cluster_render.glsl b/servers/rendering/renderer_rd/shaders/cluster_render.glsl
index da7d189281..6d95722a57 100644
--- a/servers/rendering/renderer_rd/shaders/cluster_render.glsl
+++ b/servers/rendering/renderer_rd/shaders/cluster_render.glsl
@@ -117,7 +117,7 @@ void main() {
uint cluster_thread_group_index;
if (!gl_HelperInvocation) {
- //http://advances.realtimerendering.com/s2017/2017_Sig_Improved_Culling_final.pdf
+ //https://advances.realtimerendering.com/s2017/2017_Sig_Improved_Culling_final.pdf
uvec4 mask;
diff --git a/servers/rendering/renderer_rd/shaders/cube_to_dp.glsl b/servers/rendering/renderer_rd/shaders/cube_to_dp.glsl
index dfbce29119..69b895ed29 100644
--- a/servers/rendering/renderer_rd/shaders/cube_to_dp.glsl
+++ b/servers/rendering/renderer_rd/shaders/cube_to_dp.glsl
@@ -7,8 +7,7 @@
layout(push_constant, binding = 1, std430) uniform Params {
float z_far;
float z_near;
- bool z_flip;
- uint pad;
+ vec2 texel_size;
vec4 screen_rect;
}
params;
@@ -35,22 +34,23 @@ layout(set = 0, binding = 0) uniform samplerCube source_cube;
layout(push_constant, binding = 1, std430) uniform Params {
float z_far;
float z_near;
- bool z_flip;
- uint pad;
+ vec2 texel_size;
vec4 screen_rect;
}
params;
void main() {
vec2 uv = uv_interp;
+ vec2 texel_size = abs(params.texel_size);
- vec3 normal = vec3(uv * 2.0 - 1.0, 0.0);
+ uv = clamp(uv * (1.0 + 2.0 * texel_size) - texel_size, vec2(0.0), vec2(1.0));
- normal.z = 0.5 - 0.5 * ((normal.x * normal.x) + (normal.y * normal.y));
+ vec3 normal = vec3(uv * 2.0 - 1.0, 0.0);
+ normal.z = 0.5 * (1.0 - dot(normal.xy, normal.xy)); // z = 1/2 - 1/2 * (x^2 + y^2)
normal = normalize(normal);
normal.y = -normal.y; //needs to be flipped to match projection matrix
- if (!params.z_flip) {
+ if (params.texel_size.x >= 0.0) { // Sign is used to encode Z flip
normal.z = -normal.z;
}
diff --git a/servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl b/servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl
index 9fa84657d1..63f0ce690e 100644
--- a/servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl
+++ b/servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl
@@ -32,53 +32,7 @@ layout(set = 0, binding = 0) uniform samplerCube source_cubemap;
layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly imageCube dest_cubemap;
-layout(push_constant, binding = 1, std430) uniform Params {
- uint face_size;
-}
-params;
-
-#define M_PI 3.14159265359
-
-void get_dir_0(out vec3 dir, in float u, in float v) {
- dir[0] = 1.0;
- dir[1] = v;
- dir[2] = -u;
-}
-
-void get_dir_1(out vec3 dir, in float u, in float v) {
- dir[0] = -1.0;
- dir[1] = v;
- dir[2] = u;
-}
-
-void get_dir_2(out vec3 dir, in float u, in float v) {
- dir[0] = u;
- dir[1] = 1.0;
- dir[2] = -v;
-}
-
-void get_dir_3(out vec3 dir, in float u, in float v) {
- dir[0] = u;
- dir[1] = -1.0;
- dir[2] = v;
-}
-
-void get_dir_4(out vec3 dir, in float u, in float v) {
- dir[0] = u;
- dir[1] = v;
- dir[2] = 1.0;
-}
-
-void get_dir_5(out vec3 dir, in float u, in float v) {
- dir[0] = -u;
- dir[1] = v;
- dir[2] = -1.0;
-}
-
-float calcWeight(float u, float v) {
- float val = u * u + v * v + 1.0;
- return val * sqrt(val);
-}
+#include "cubemap_downsampler_inc.glsl"
void main() {
uvec3 id = gl_GlobalInvocationID;
diff --git a/servers/rendering/renderer_rd/shaders/cubemap_downsampler_inc.glsl b/servers/rendering/renderer_rd/shaders/cubemap_downsampler_inc.glsl
new file mode 100644
index 0000000000..b329e67293
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/cubemap_downsampler_inc.glsl
@@ -0,0 +1,48 @@
+layout(push_constant, binding = 1, std430) uniform Params {
+ uint face_size;
+ uint face_id; // only used in raster shader
+}
+params;
+
+#define M_PI 3.14159265359
+
+void get_dir_0(out vec3 dir, in float u, in float v) {
+ dir[0] = 1.0;
+ dir[1] = v;
+ dir[2] = -u;
+}
+
+void get_dir_1(out vec3 dir, in float u, in float v) {
+ dir[0] = -1.0;
+ dir[1] = v;
+ dir[2] = u;
+}
+
+void get_dir_2(out vec3 dir, in float u, in float v) {
+ dir[0] = u;
+ dir[1] = 1.0;
+ dir[2] = -v;
+}
+
+void get_dir_3(out vec3 dir, in float u, in float v) {
+ dir[0] = u;
+ dir[1] = -1.0;
+ dir[2] = v;
+}
+
+void get_dir_4(out vec3 dir, in float u, in float v) {
+ dir[0] = u;
+ dir[1] = v;
+ dir[2] = 1.0;
+}
+
+void get_dir_5(out vec3 dir, in float u, in float v) {
+ dir[0] = -u;
+ dir[1] = v;
+ dir[2] = -1.0;
+}
+
+float calcWeight(float u, float v) {
+ float val = u * u + v * v + 1.0;
+ return val * sqrt(val);
+}
diff --git a/servers/rendering/renderer_rd/shaders/cubemap_downsampler_raster.glsl b/servers/rendering/renderer_rd/shaders/cubemap_downsampler_raster.glsl
new file mode 100644
index 0000000000..0828ffd921
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/cubemap_downsampler_raster.glsl
@@ -0,0 +1,163 @@
+// Copyright 2016 Activision Publishing, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the Software
+// is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+/* clang-format off */
+#[vertex]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "cubemap_downsampler_inc.glsl"
+
+layout(location = 0) out vec2 uv_interp;
+/* clang-format on */
+
+void main() {
+ vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
+ uv_interp = base_arr[gl_VertexIndex] * float(params.face_size);
+ gl_Position = vec4(base_arr[gl_VertexIndex] * 2.0 - 1.0, 0.0, 1.0);
+}
+
+/* clang-format off */
+#[fragment]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "cubemap_downsampler_inc.glsl"
+
+layout(set = 0, binding = 0) uniform samplerCube source_cubemap;
+
+layout(location = 0) in vec2 uv_interp;
+layout(location = 0) out vec4 frag_color;
+/* clang-format on */
+
+void main() {
+ // Converted from compute shader which uses absolute coordinates.
+ // Could possibly simplify this
+ float face_size = float(params.face_size);
+
+ if (uv_interp.x < face_size && uv_interp.y < face_size) {
+ float inv_face_size = 1.0 / face_size;
+
+ float u0 = (uv_interp.x * 2.0 + 1.0 - 0.75) * inv_face_size - 1.0;
+ float u1 = (uv_interp.x * 2.0 + 1.0 + 0.75) * inv_face_size - 1.0;
+
+ float v0 = (uv_interp.y * 2.0 + 1.0 - 0.75) * -inv_face_size + 1.0;
+ float v1 = (uv_interp.y * 2.0 + 1.0 + 0.75) * -inv_face_size + 1.0;
+
+ float weights[4];
+ weights[0] = calcWeight(u0, v0);
+ weights[1] = calcWeight(u1, v0);
+ weights[2] = calcWeight(u0, v1);
+ weights[3] = calcWeight(u1, v1);
+
+ const float wsum = 0.5 / (weights[0] + weights[1] + weights[2] + weights[3]);
+ for (int i = 0; i < 4; i++) {
+ weights[i] = weights[i] * wsum + .125;
+ }
+
+ vec3 dir;
+ vec4 color;
+ switch (params.face_id) {
+ case 0:
+ get_dir_0(dir, u0, v0);
+ color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
+
+ get_dir_0(dir, u1, v0);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
+
+ get_dir_0(dir, u0, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
+
+ get_dir_0(dir, u1, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
+ break;
+ case 1:
+ get_dir_1(dir, u0, v0);
+ color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
+
+ get_dir_1(dir, u1, v0);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
+
+ get_dir_1(dir, u0, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
+
+ get_dir_1(dir, u1, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
+ break;
+ case 2:
+ get_dir_2(dir, u0, v0);
+ color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
+
+ get_dir_2(dir, u1, v0);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
+
+ get_dir_2(dir, u0, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
+
+ get_dir_2(dir, u1, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
+ break;
+ case 3:
+ get_dir_3(dir, u0, v0);
+ color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
+
+ get_dir_3(dir, u1, v0);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
+
+ get_dir_3(dir, u0, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
+
+ get_dir_3(dir, u1, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
+ break;
+ case 4:
+ get_dir_4(dir, u0, v0);
+ color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
+
+ get_dir_4(dir, u1, v0);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
+
+ get_dir_4(dir, u0, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
+
+ get_dir_4(dir, u1, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
+ break;
+ default:
+ get_dir_5(dir, u0, v0);
+ color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
+
+ get_dir_5(dir, u1, v0);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
+
+ get_dir_5(dir, u0, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
+
+ get_dir_5(dir, u1, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
+ break;
+ }
+ frag_color = color;
+ }
+}
diff --git a/servers/rendering/renderer_rd/shaders/cubemap_filter_raster.glsl b/servers/rendering/renderer_rd/shaders/cubemap_filter_raster.glsl
new file mode 100644
index 0000000000..324d306218
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/cubemap_filter_raster.glsl
@@ -0,0 +1,256 @@
+// Copyright 2016 Activision Publishing, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the Software
+// is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+/* clang-format off */
+#[vertex]
+
+#version 450
+
+#VERSION_DEFINES
+
+layout(push_constant, binding = 1, std430) uniform Params {
+ int mip_level;
+ uint face_id;
+}
+params;
+
+layout(location = 0) out vec2 uv_interp;
+/* clang-format on */
+
+void main() {
+ vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
+ uv_interp = base_arr[gl_VertexIndex];
+ gl_Position = vec4(base_arr[gl_VertexIndex] * 2.0 - 1.0, 0.0, 1.0);
+}
+
+/* clang-format off */
+#[fragment]
+
+#version 450
+
+#VERSION_DEFINES
+
+layout(push_constant, binding = 1, std430) uniform Params {
+ int mip_level;
+ uint face_id;
+}
+params;
+
+layout(set = 0, binding = 0) uniform samplerCube source_cubemap;
+
+layout(location = 0) in vec2 uv_interp;
+layout(location = 0) out vec4 frag_color;
+
+/* clang-format on */
+
+#ifdef USE_HIGH_QUALITY
+#define NUM_TAPS 32
+#else
+#define NUM_TAPS 8
+#endif
+
+#define BASE_RESOLUTION 128
+
+#ifdef USE_HIGH_QUALITY
+layout(set = 1, binding = 0, std430) buffer restrict readonly Data {
+ vec4[7][5][3][24] coeffs;
+}
+data;
+#else
+layout(set = 1, binding = 0, std430) buffer restrict readonly Data {
+ vec4[7][5][6] coeffs;
+}
+data;
+#endif
+
+void get_dir(out vec3 dir, in vec2 uv, in uint face) {
+ switch (face) {
+ case 0:
+ dir = vec3(1.0, uv[1], -uv[0]);
+ break;
+ case 1:
+ dir = vec3(-1.0, uv[1], uv[0]);
+ break;
+ case 2:
+ dir = vec3(uv[0], 1.0, -uv[1]);
+ break;
+ case 3:
+ dir = vec3(uv[0], -1.0, uv[1]);
+ break;
+ case 4:
+ dir = vec3(uv[0], uv[1], 1.0);
+ break;
+ default:
+ dir = vec3(-uv[0], uv[1], -1.0);
+ break;
+ }
+}
+
+void main() {
+ // determine dir / pos for the texel
+ vec3 dir, adir, frameZ;
+ {
+ vec2 uv;
+ uv.x = uv_interp.x;
+ uv.y = 1.0 - uv_interp.y;
+ uv = uv * 2.0 - 1.0;
+
+ get_dir(dir, uv, params.face_id);
+ frameZ = normalize(dir);
+
+ adir = abs(dir);
+ }
+
+ // determine which texel this is
+ // NOTE (macOS/MoltenVK): Do not rename, "level" variable name conflicts with the Metal "level(float lod)" mipmap sampling function name.
+ int mip_level = 0;
+
+ if (params.mip_level < 0) {
+ // return as is
+ frag_color.rgb = textureLod(source_cubemap, frameZ, 0.0).rgb;
+ frag_color.a = 1.0;
+ return;
+ } else if (params.mip_level > 6) {
+ // maximum level
+ mip_level = 6;
+ } else {
+ mip_level = params.mip_level;
+ }
+
+ // GGX gather colors
+ vec4 color = vec4(0.0);
+ for (int axis = 0; axis < 3; axis++) {
+ const int otherAxis0 = 1 - (axis & 1) - (axis >> 1);
+ const int otherAxis1 = 2 - (axis >> 1);
+
+ float frameweight = (max(adir[otherAxis0], adir[otherAxis1]) - .75) / .25;
+ if (frameweight > 0.0) {
+ // determine frame
+ vec3 UpVector;
+ switch (axis) {
+ case 0:
+ UpVector = vec3(1, 0, 0);
+ break;
+ case 1:
+ UpVector = vec3(0, 1, 0);
+ break;
+ default:
+ UpVector = vec3(0, 0, 1);
+ break;
+ }
+
+ vec3 frameX = normalize(cross(UpVector, frameZ));
+ vec3 frameY = cross(frameZ, frameX);
+
+ // calculate parametrization for polynomial
+ float Nx = dir[otherAxis0];
+ float Ny = dir[otherAxis1];
+ float Nz = adir[axis];
+
+ float NmaxXY = max(abs(Ny), abs(Nx));
+ Nx /= NmaxXY;
+ Ny /= NmaxXY;
+
+ float theta;
+ if (Ny < Nx) {
+ if (Ny <= -0.999)
+ theta = Nx;
+ else
+ theta = Ny;
+ } else {
+ if (Ny >= 0.999)
+ theta = -Nx;
+ else
+ theta = -Ny;
+ }
+
+ float phi;
+ if (Nz <= -0.999)
+ phi = -NmaxXY;
+ else if (Nz >= 0.999)
+ phi = NmaxXY;
+ else
+ phi = Nz;
+
+ float theta2 = theta * theta;
+ float phi2 = phi * phi;
+
+ // sample
+ for (int iSuperTap = 0; iSuperTap < NUM_TAPS / 4; iSuperTap++) {
+ const int index = (NUM_TAPS / 4) * axis + iSuperTap;
+
+#ifdef USE_HIGH_QUALITY
+ vec4 coeffsDir0[3];
+ vec4 coeffsDir1[3];
+ vec4 coeffsDir2[3];
+ vec4 coeffsLevel[3];
+ vec4 coeffsWeight[3];
+
+ for (int iCoeff = 0; iCoeff < 3; iCoeff++) {
+ coeffsDir0[iCoeff] = data.coeffs[mip_level][0][iCoeff][index];
+ coeffsDir1[iCoeff] = data.coeffs[mip_level][1][iCoeff][index];
+ coeffsDir2[iCoeff] = data.coeffs[mip_level][2][iCoeff][index];
+ coeffsLevel[iCoeff] = data.coeffs[mip_level][3][iCoeff][index];
+ coeffsWeight[iCoeff] = data.coeffs[mip_level][4][iCoeff][index];
+ }
+
+ for (int iSubTap = 0; iSubTap < 4; iSubTap++) {
+ // determine sample attributes (dir, weight, mip_level)
+ vec3 sample_dir = frameX * (coeffsDir0[0][iSubTap] + coeffsDir0[1][iSubTap] * theta2 + coeffsDir0[2][iSubTap] * phi2) + frameY * (coeffsDir1[0][iSubTap] + coeffsDir1[1][iSubTap] * theta2 + coeffsDir1[2][iSubTap] * phi2) + frameZ * (coeffsDir2[0][iSubTap] + coeffsDir2[1][iSubTap] * theta2 + coeffsDir2[2][iSubTap] * phi2);
+
+ float sample_level = coeffsLevel[0][iSubTap] + coeffsLevel[1][iSubTap] * theta2 + coeffsLevel[2][iSubTap] * phi2;
+
+ float sample_weight = coeffsWeight[0][iSubTap] + coeffsWeight[1][iSubTap] * theta2 + coeffsWeight[2][iSubTap] * phi2;
+#else
+ vec4 coeffsDir0 = data.coeffs[mip_level][0][index];
+ vec4 coeffsDir1 = data.coeffs[mip_level][1][index];
+ vec4 coeffsDir2 = data.coeffs[mip_level][2][index];
+ vec4 coeffsLevel = data.coeffs[mip_level][3][index];
+ vec4 coeffsWeight = data.coeffs[mip_level][4][index];
+
+ for (int iSubTap = 0; iSubTap < 4; iSubTap++) {
+ // determine sample attributes (dir, weight, mip_level)
+ vec3 sample_dir = frameX * coeffsDir0[iSubTap] + frameY * coeffsDir1[iSubTap] + frameZ * coeffsDir2[iSubTap];
+
+ float sample_level = coeffsLevel[iSubTap];
+
+ float sample_weight = coeffsWeight[iSubTap];
+#endif
+
+ sample_weight *= frameweight;
+
+ // adjust for jacobian
+ sample_dir /= max(abs(sample_dir[0]), max(abs(sample_dir[1]), abs(sample_dir[2])));
+ sample_level += 0.75 * log2(dot(sample_dir, sample_dir));
+ // sample cubemap
+ color.xyz += textureLod(source_cubemap, normalize(sample_dir), sample_level).xyz * sample_weight;
+ color.w += sample_weight;
+ }
+ }
+ }
+ }
+ color /= color.w;
+
+ // write color
+ color.xyz = max(vec3(0.0), color.xyz);
+ color.w = 1.0;
+
+ frag_color = color;
+}
diff --git a/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl b/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl
index ce7c03c1d4..28f4dc59ec 100644
--- a/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl
+++ b/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl
@@ -12,100 +12,7 @@ layout(set = 0, binding = 0) uniform samplerCube source_cube;
layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly imageCube dest_cubemap;
-layout(push_constant, binding = 1, std430) uniform Params {
- uint face_id;
- uint sample_count;
- float roughness;
- bool use_direct_write;
- float face_size;
-}
-params;
-
-#define M_PI 3.14159265359
-
-vec3 texelCoordToVec(vec2 uv, uint faceID) {
- mat3 faceUvVectors[6];
-
- // -x
- faceUvVectors[1][0] = vec3(0.0, 0.0, 1.0); // u -> +z
- faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y
- faceUvVectors[1][2] = vec3(-1.0, 0.0, 0.0); // -x face
-
- // +x
- faceUvVectors[0][0] = vec3(0.0, 0.0, -1.0); // u -> -z
- faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y
- faceUvVectors[0][2] = vec3(1.0, 0.0, 0.0); // +x face
-
- // -y
- faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x
- faceUvVectors[3][1] = vec3(0.0, 0.0, -1.0); // v -> -z
- faceUvVectors[3][2] = vec3(0.0, -1.0, 0.0); // -y face
-
- // +y
- faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x
- faceUvVectors[2][1] = vec3(0.0, 0.0, 1.0); // v -> +z
- faceUvVectors[2][2] = vec3(0.0, 1.0, 0.0); // +y face
-
- // -z
- faceUvVectors[5][0] = vec3(-1.0, 0.0, 0.0); // u -> -x
- faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y
- faceUvVectors[5][2] = vec3(0.0, 0.0, -1.0); // -z face
-
- // +z
- faceUvVectors[4][0] = vec3(1.0, 0.0, 0.0); // u -> +x
- faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y
- faceUvVectors[4][2] = vec3(0.0, 0.0, 1.0); // +z face
-
- // out = u * s_faceUv[0] + v * s_faceUv[1] + s_faceUv[2].
- vec3 result = (faceUvVectors[faceID][0] * uv.x) + (faceUvVectors[faceID][1] * uv.y) + faceUvVectors[faceID][2];
- return normalize(result);
-}
-
-vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N) {
- float a = Roughness * Roughness; // DISNEY'S ROUGHNESS [see Burley'12 siggraph]
-
- // Compute distribution direction
- float Phi = 2.0 * M_PI * Xi.x;
- float CosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a * a - 1.0) * Xi.y));
- float SinTheta = sqrt(1.0 - CosTheta * CosTheta);
-
- // Convert to spherical direction
- vec3 H;
- H.x = SinTheta * cos(Phi);
- H.y = SinTheta * sin(Phi);
- H.z = CosTheta;
-
- vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
- vec3 TangentX = normalize(cross(UpVector, N));
- vec3 TangentY = cross(N, TangentX);
-
- // Tangent to world space
- return TangentX * H.x + TangentY * H.y + N * H.z;
-}
-
-// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
-float GGX(float NdotV, float a) {
- float k = a / 2.0;
- return NdotV / (NdotV * (1.0 - k) + k);
-}
-
-// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
-float G_Smith(float a, float nDotV, float nDotL) {
- return GGX(nDotL, a * a) * GGX(nDotV, a * a);
-}
-
-float radicalInverse_VdC(uint bits) {
- bits = (bits << 16u) | (bits >> 16u);
- bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
- bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
- bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
- bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
- return float(bits) * 2.3283064365386963e-10; // / 0x100000000
-}
-
-vec2 Hammersley(uint i, uint N) {
- return vec2(float(i) / float(N), radicalInverse_VdC(i));
-}
+#include "cubemap_roughness_inc.glsl"
void main() {
uvec3 id = gl_GlobalInvocationID;
diff --git a/servers/rendering/renderer_rd/shaders/cubemap_roughness_inc.glsl b/servers/rendering/renderer_rd/shaders/cubemap_roughness_inc.glsl
new file mode 100644
index 0000000000..be12be5dec
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/cubemap_roughness_inc.glsl
@@ -0,0 +1,94 @@
+#define M_PI 3.14159265359
+
+layout(push_constant, binding = 1, std430) uniform Params {
+ uint face_id;
+ uint sample_count;
+ float roughness;
+ bool use_direct_write;
+ float face_size;
+}
+params;
+
+vec3 texelCoordToVec(vec2 uv, uint faceID) {
+ mat3 faceUvVectors[6];
+
+ // -x
+ faceUvVectors[1][0] = vec3(0.0, 0.0, 1.0); // u -> +z
+ faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[1][2] = vec3(-1.0, 0.0, 0.0); // -x face
+
+ // +x
+ faceUvVectors[0][0] = vec3(0.0, 0.0, -1.0); // u -> -z
+ faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[0][2] = vec3(1.0, 0.0, 0.0); // +x face
+
+ // -y
+ faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x
+ faceUvVectors[3][1] = vec3(0.0, 0.0, -1.0); // v -> -z
+ faceUvVectors[3][2] = vec3(0.0, -1.0, 0.0); // -y face
+
+ // +y
+ faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x
+ faceUvVectors[2][1] = vec3(0.0, 0.0, 1.0); // v -> +z
+ faceUvVectors[2][2] = vec3(0.0, 1.0, 0.0); // +y face
+
+ // -z
+ faceUvVectors[5][0] = vec3(-1.0, 0.0, 0.0); // u -> -x
+ faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[5][2] = vec3(0.0, 0.0, -1.0); // -z face
+
+ // +z
+ faceUvVectors[4][0] = vec3(1.0, 0.0, 0.0); // u -> +x
+ faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[4][2] = vec3(0.0, 0.0, 1.0); // +z face
+
+ // out = u * s_faceUv[0] + v * s_faceUv[1] + s_faceUv[2].
+ vec3 result = (faceUvVectors[faceID][0] * uv.x) + (faceUvVectors[faceID][1] * uv.y) + faceUvVectors[faceID][2];
+ return normalize(result);
+}
+
+vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N) {
+ float a = Roughness * Roughness; // DISNEY'S ROUGHNESS [see Burley'12 siggraph]
+
+ // Compute distribution direction
+ float Phi = 2.0 * M_PI * Xi.x;
+ float CosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a * a - 1.0) * Xi.y));
+ float SinTheta = sqrt(1.0 - CosTheta * CosTheta);
+
+ // Convert to spherical direction
+ vec3 H;
+ H.x = SinTheta * cos(Phi);
+ H.y = SinTheta * sin(Phi);
+ H.z = CosTheta;
+
+ vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
+ vec3 TangentX = normalize(cross(UpVector, N));
+ vec3 TangentY = cross(N, TangentX);
+
+ // Tangent to world space
+ return TangentX * H.x + TangentY * H.y + N * H.z;
+}
+
+// https://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
+float GGX(float NdotV, float a) {
+ float k = a / 2.0;
+ return NdotV / (NdotV * (1.0 - k) + k);
+}
+
+// https://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
+float G_Smith(float a, float nDotV, float nDotL) {
+ return GGX(nDotL, a * a) * GGX(nDotV, a * a);
+}
+
+float radicalInverse_VdC(uint bits) {
+ bits = (bits << 16u) | (bits >> 16u);
+ bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
+ bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
+ bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
+ bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
+ return float(bits) * 2.3283064365386963e-10; // / 0x100000000
+}
+
+vec2 Hammersley(uint i, uint N) {
+ return vec2(float(i) / float(N), radicalInverse_VdC(i));
+}
diff --git a/servers/rendering/renderer_rd/shaders/cubemap_roughness_raster.glsl b/servers/rendering/renderer_rd/shaders/cubemap_roughness_raster.glsl
new file mode 100644
index 0000000000..2570308816
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/cubemap_roughness_raster.glsl
@@ -0,0 +1,63 @@
+/* clang-format off */
+#[vertex]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "cubemap_roughness_inc.glsl"
+
+layout(location = 0) out vec2 uv_interp;
+/* clang-format on */
+
+void main() {
+ vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
+ uv_interp = base_arr[gl_VertexIndex];
+ gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0);
+}
+
+/* clang-format off */
+#[fragment]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "cubemap_roughness_inc.glsl"
+
+layout(location = 0) in vec2 uv_interp;
+
+layout(set = 0, binding = 0) uniform samplerCube source_cube;
+
+layout(location = 0) out vec4 frag_color;
+/* clang-format on */
+
+void main() {
+ vec3 N = texelCoordToVec(uv_interp * 2.0 - 1.0, params.face_id);
+
+ //vec4 color = color_interp;
+
+ if (params.use_direct_write) {
+ frag_color = vec4(texture(source_cube, N).rgb, 1.0);
+ } else {
+ vec4 sum = vec4(0.0, 0.0, 0.0, 0.0);
+
+ for (uint sampleNum = 0u; sampleNum < params.sample_count; sampleNum++) {
+ vec2 xi = Hammersley(sampleNum, params.sample_count);
+
+ vec3 H = ImportanceSampleGGX(xi, params.roughness, N);
+ vec3 V = N;
+ vec3 L = (2.0 * dot(V, H) * H - V);
+
+ float ndotl = clamp(dot(N, L), 0.0, 1.0);
+
+ if (ndotl > 0.0) {
+ sum.rgb += textureLod(source_cube, L, 0.0).rgb * ndotl;
+ sum.a += ndotl;
+ }
+ }
+ sum /= sum.a;
+
+ frag_color = vec4(sum.rgb, 1.0);
+ }
+}
diff --git a/servers/rendering/renderer_rd/shaders/decal_data_inc.glsl b/servers/rendering/renderer_rd/shaders/decal_data_inc.glsl
index ccaad13311..158096d3c7 100644
--- a/servers/rendering/renderer_rd/shaders/decal_data_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/decal_data_inc.glsl
@@ -1,18 +1,18 @@
struct DecalData {
- mat4 xform; //to decal transform
- vec3 inv_extents;
- float albedo_mix;
- vec4 albedo_rect;
- vec4 normal_rect;
- vec4 orm_rect;
- vec4 emission_rect;
- vec4 modulate;
- float emission_energy;
+ highp mat4 xform; //to decal transform
+ highp vec3 inv_extents;
+ mediump float albedo_mix;
+ highp vec4 albedo_rect;
+ highp vec4 normal_rect;
+ highp vec4 orm_rect;
+ highp vec4 emission_rect;
+ highp vec4 modulate;
+ mediump float emission_energy;
uint mask;
- float upper_fade;
- float lower_fade;
- mat3x4 normal_xform;
- vec3 normal;
- float normal_fade;
+ mediump float upper_fade;
+ mediump float lower_fade;
+ mediump mat3x4 normal_xform;
+ mediump vec3 normal;
+ mediump float normal_fade;
};
diff --git a/servers/rendering/renderer_rd/shaders/fsr_upscale.glsl b/servers/rendering/renderer_rd/shaders/fsr_upscale.glsl
new file mode 100644
index 0000000000..4e2ba84033
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/fsr_upscale.glsl
@@ -0,0 +1,173 @@
+/*************************************************************************/
+/* fsr_upscale.glsl */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#[compute]
+
+#version 450
+
+#VERSION_DEFINES
+
+#define A_GPU
+#define A_GLSL
+
+#ifdef MODE_FSR_UPSCALE_NORMAL
+
+#define A_HALF
+
+#endif
+
+#include "thirdparty/amd-fsr/ffx_a.h"
+
+layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
+
+layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly image2D fsr_image;
+layout(set = 0, binding = 0) uniform sampler2D source_image;
+
+#define FSR_UPSCALE_PASS_TYPE_EASU 0
+#define FSR_UPSCALE_PASS_TYPE_RCAS 1
+
+layout(push_constant, binding = 1, std430) uniform Params {
+ float resolution_width;
+ float resolution_height;
+ float upscaled_width;
+ float upscaled_height;
+ float sharpness;
+ int pass;
+}
+params;
+
+AU4 Const0, Const1, Const2, Const3;
+
+#ifdef MODE_FSR_UPSCALE_FALLBACK
+
+#define FSR_EASU_F
+AF4 FsrEasuRF(AF2 p) {
+ AF4 res = textureGather(source_image, p, 0);
+ return res;
+}
+AF4 FsrEasuGF(AF2 p) {
+ AF4 res = textureGather(source_image, p, 1);
+ return res;
+}
+AF4 FsrEasuBF(AF2 p) {
+ AF4 res = textureGather(source_image, p, 2);
+ return res;
+}
+
+#define FSR_RCAS_F
+AF4 FsrRcasLoadF(ASU2 p) {
+ return AF4(texelFetch(source_image, ASU2(p), 0));
+}
+void FsrRcasInputF(inout AF1 r, inout AF1 g, inout AF1 b) {}
+
+#else
+
+#define FSR_EASU_H
+AH4 FsrEasuRH(AF2 p) {
+ AH4 res = AH4(textureGather(source_image, p, 0));
+ return res;
+}
+AH4 FsrEasuGH(AF2 p) {
+ AH4 res = AH4(textureGather(source_image, p, 1));
+ return res;
+}
+AH4 FsrEasuBH(AF2 p) {
+ AH4 res = AH4(textureGather(source_image, p, 2));
+ return res;
+}
+
+#define FSR_RCAS_H
+AH4 FsrRcasLoadH(ASW2 p) {
+ return AH4(texelFetch(source_image, ASU2(p), 0));
+}
+void FsrRcasInputH(inout AH1 r, inout AH1 g, inout AH1 b) {}
+
+#endif
+
+#include "thirdparty/amd-fsr/ffx_fsr1.h"
+
+void fsr_easu_pass(AU2 pos) {
+#ifdef MODE_FSR_UPSCALE_NORMAL
+
+ AH3 Gamma2Color = AH3(0, 0, 0);
+ FsrEasuH(Gamma2Color, pos, Const0, Const1, Const2, Const3);
+ imageStore(fsr_image, ASU2(pos), AH4(Gamma2Color, 1));
+
+#else
+
+ AF3 Gamma2Color = AF3(0, 0, 0);
+ FsrEasuF(Gamma2Color, pos, Const0, Const1, Const2, Const3);
+ imageStore(fsr_image, ASU2(pos), AF4(Gamma2Color, 1));
+
+#endif
+}
+
+void fsr_rcas_pass(AU2 pos) {
+#ifdef MODE_FSR_UPSCALE_NORMAL
+
+ AH3 Gamma2Color = AH3(0, 0, 0);
+ FsrRcasH(Gamma2Color.r, Gamma2Color.g, Gamma2Color.b, pos, Const0);
+ imageStore(fsr_image, ASU2(pos), AH4(Gamma2Color, 1));
+
+#else
+
+ AF3 Gamma2Color = AF3(0, 0, 0);
+ FsrRcasF(Gamma2Color.r, Gamma2Color.g, Gamma2Color.b, pos, Const0);
+ imageStore(fsr_image, ASU2(pos), AF4(Gamma2Color, 1));
+
+#endif
+}
+
+void fsr_pass(AU2 pos) {
+ if (params.pass == FSR_UPSCALE_PASS_TYPE_EASU) {
+ fsr_easu_pass(pos);
+ } else if (params.pass == FSR_UPSCALE_PASS_TYPE_RCAS) {
+ fsr_rcas_pass(pos);
+ }
+}
+
+void main() {
+ // Clang does not like unused functions. If ffx_a.h is included in the binary, clang will throw a fit and not compile so we must configure FSR in this shader
+ if (params.pass == FSR_UPSCALE_PASS_TYPE_EASU) {
+ FsrEasuCon(Const0, Const1, Const2, Const3, params.resolution_width, params.resolution_height, params.resolution_width, params.resolution_height, params.upscaled_width, params.upscaled_height);
+ } else if (params.pass == FSR_UPSCALE_PASS_TYPE_RCAS) {
+ FsrRcasCon(Const0, params.sharpness);
+ }
+
+ AU2 gxy = ARmp8x8(gl_LocalInvocationID.x) + AU2(gl_WorkGroupID.x << 4u, gl_WorkGroupID.y << 4u);
+
+ fsr_pass(gxy);
+ gxy.x += 8u;
+ fsr_pass(gxy);
+ gxy.y += 8u;
+ fsr_pass(gxy);
+ gxy.x -= 8u;
+ fsr_pass(gxy);
+}
diff --git a/servers/rendering/renderer_rd/shaders/gi.glsl b/servers/rendering/renderer_rd/shaders/gi.glsl
index bfd5c4c88d..5528ea3659 100644
--- a/servers/rendering/renderer_rd/shaders/gi.glsl
+++ b/servers/rendering/renderer_rd/shaders/gi.glsl
@@ -35,7 +35,7 @@ layout(set = 0, binding = 11) uniform texture2DArray lightprobe_texture;
layout(set = 0, binding = 12) uniform texture2D depth_buffer;
layout(set = 0, binding = 13) uniform texture2D normal_roughness_buffer;
-layout(set = 0, binding = 14) uniform utexture2D giprobe_buffer;
+layout(set = 0, binding = 14) uniform utexture2D voxel_gi_buffer;
layout(set = 0, binding = 15, std140) uniform SDFGI {
vec3 grid_size;
@@ -65,9 +65,9 @@ layout(set = 0, binding = 15, std140) uniform SDFGI {
}
sdfgi;
-#define MAX_GI_PROBES 8
+#define MAX_VOXEL_GI_INSTANCES 8
-struct GIProbeData {
+struct VoxelGIData {
mat4 xform;
vec3 bounds;
float dynamic_range;
@@ -77,18 +77,18 @@ struct GIProbeData {
bool blend_ambient;
uint texture_slot;
- float anisotropy_strength;
- float ambient_occlusion;
- float ambient_occlusion_size;
+ uint pad0;
+ uint pad1;
+ uint pad2;
uint mipmaps;
};
-layout(set = 0, binding = 16, std140) uniform GIProbes {
- GIProbeData data[MAX_GI_PROBES];
+layout(set = 0, binding = 16, std140) uniform VoxelGIs {
+ VoxelGIData data[MAX_VOXEL_GI_INSTANCES];
}
-gi_probes;
+voxel_gi_instances;
-layout(set = 0, binding = 17) uniform texture3D gi_probe_textures[MAX_GI_PROBES];
+layout(set = 0, binding = 17) uniform texture3D voxel_gi_textures[MAX_VOXEL_GI_INSTANCES];
layout(push_constant, binding = 0, std430) uniform Params {
ivec2 screen_size;
@@ -97,12 +97,10 @@ layout(push_constant, binding = 0, std430) uniform Params {
vec4 proj_info;
- vec3 ao_color;
- uint max_giprobes;
-
+ uint max_voxel_gi_instances;
bool high_quality_vct;
bool orthogonal;
- uint pad[2];
+ uint pad;
mat3x4 cam_rotation;
}
@@ -155,7 +153,7 @@ vec3 reconstruct_position(ivec2 screen_pos) {
return pos;
}
-void sdfgi_probe_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_normal, vec3 cam_specular_normal, float roughness, out vec3 diffuse_light, out vec3 specular_light) {
+void sdfvoxel_gi_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_normal, vec3 cam_specular_normal, float roughness, out vec3 diffuse_light, out vec3 specular_light) {
cascade_pos += cam_normal * sdfgi.normal_bias;
vec3 base_pos = floor(cascade_pos);
@@ -293,7 +291,7 @@ void sdfgi_process(vec3 vertex, vec3 normal, vec3 reflection, float roughness, o
float blend;
vec3 diffuse, specular;
- sdfgi_probe_process(cascade, cascade_pos, cam_pos, cam_normal, reflection, roughness, diffuse, specular);
+ sdfvoxel_gi_process(cascade, cascade_pos, cam_pos, cam_normal, reflection, roughness, diffuse, specular);
{
//process blend
@@ -323,7 +321,7 @@ void sdfgi_process(vec3 vertex, vec3 normal, vec3 reflection, float roughness, o
} else {
vec3 diffuse2, specular2;
cascade_pos = (cam_pos - sdfgi.cascades[cascade + 1].position) * sdfgi.cascades[cascade + 1].to_probe;
- sdfgi_probe_process(cascade + 1, cascade_pos, cam_pos, cam_normal, reflection, roughness, diffuse2, specular2);
+ sdfvoxel_gi_process(cascade + 1, cascade_pos, cam_pos, cam_normal, reflection, roughness, diffuse2, specular2);
diffuse = mix(diffuse, diffuse2, blend);
specular = mix(specular, specular2, blend);
}
@@ -494,26 +492,26 @@ vec4 voxel_cone_trace_45_degrees(texture3D probe, vec3 cell_size, vec3 pos, vec3
return color;
}
-void gi_probe_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3 normal_xform, float roughness, inout vec4 out_spec, inout vec4 out_diff, inout float out_blend) {
- position = (gi_probes.data[index].xform * vec4(position, 1.0)).xyz;
- ref_vec = normalize((gi_probes.data[index].xform * vec4(ref_vec, 0.0)).xyz);
- normal = normalize((gi_probes.data[index].xform * vec4(normal, 0.0)).xyz);
+void voxel_gi_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3 normal_xform, float roughness, inout vec4 out_spec, inout vec4 out_diff, inout float out_blend) {
+ position = (voxel_gi_instances.data[index].xform * vec4(position, 1.0)).xyz;
+ ref_vec = normalize((voxel_gi_instances.data[index].xform * vec4(ref_vec, 0.0)).xyz);
+ normal = normalize((voxel_gi_instances.data[index].xform * vec4(normal, 0.0)).xyz);
- position += normal * gi_probes.data[index].normal_bias;
+ position += normal * voxel_gi_instances.data[index].normal_bias;
//this causes corrupted pixels, i have no idea why..
- if (any(bvec2(any(lessThan(position, vec3(0.0))), any(greaterThan(position, gi_probes.data[index].bounds))))) {
+ if (any(bvec2(any(lessThan(position, vec3(0.0))), any(greaterThan(position, voxel_gi_instances.data[index].bounds))))) {
return;
}
- mat3 dir_xform = mat3(gi_probes.data[index].xform) * normal_xform;
+ mat3 dir_xform = mat3(voxel_gi_instances.data[index].xform) * normal_xform;
- vec3 blendv = abs(position / gi_probes.data[index].bounds * 2.0 - 1.0);
+ vec3 blendv = abs(position / voxel_gi_instances.data[index].bounds * 2.0 - 1.0);
float blend = clamp(1.0 - max(blendv.x, max(blendv.y, blendv.z)), 0.0, 1.0);
//float blend=1.0;
- float max_distance = length(gi_probes.data[index].bounds);
- vec3 cell_size = 1.0 / gi_probes.data[index].bounds;
+ float max_distance = length(voxel_gi_instances.data[index].bounds);
+ vec3 cell_size = 1.0 / voxel_gi_instances.data[index].bounds;
//irradiance
@@ -534,7 +532,7 @@ void gi_probe_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3
for (uint i = 0; i < cone_dir_count; i++) {
vec3 dir = normalize(dir_xform * cone_dirs[i]);
- light += cone_weights[i] * voxel_cone_trace(gi_probe_textures[index], cell_size, position, dir, cone_angle_tan, max_distance, gi_probes.data[index].bias);
+ light += cone_weights[i] * voxel_cone_trace(voxel_gi_textures[index], cell_size, position, dir, cone_angle_tan, max_distance, voxel_gi_instances.data[index].bias);
}
} else {
const uint cone_dir_count = 4;
@@ -547,42 +545,21 @@ void gi_probe_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3
float cone_weights[cone_dir_count] = float[](0.25, 0.25, 0.25, 0.25);
for (int i = 0; i < cone_dir_count; i++) {
vec3 dir = normalize(dir_xform * cone_dirs[i]);
- light += cone_weights[i] * voxel_cone_trace_45_degrees(gi_probe_textures[index], cell_size, position, dir, max_distance, gi_probes.data[index].bias);
- }
- }
-
- if (gi_probes.data[index].ambient_occlusion > 0.001) {
- float size = 1.0 + gi_probes.data[index].ambient_occlusion_size * 7.0;
-
- float taps, blend;
- blend = modf(size, taps);
- float ao = 0.0;
- for (float i = 1.0; i <= taps; i++) {
- vec3 ofs = (position + normal * (i * 0.5 + 1.0)) * cell_size;
- ao += textureLod(sampler3D(gi_probe_textures[index], linear_sampler_with_mipmaps), ofs, i - 1.0).a * i;
+ light += cone_weights[i] * voxel_cone_trace_45_degrees(voxel_gi_textures[index], cell_size, position, dir, max_distance, voxel_gi_instances.data[index].bias);
}
-
- if (blend > 0.001) {
- vec3 ofs = (position + normal * ((taps + 1.0) * 0.5 + 1.0)) * cell_size;
- ao += textureLod(sampler3D(gi_probe_textures[index], linear_sampler_with_mipmaps), ofs, taps).a * (taps + 1.0) * blend;
- }
-
- ao = 1.0 - min(1.0, ao);
-
- light.rgb = mix(params.ao_color, light.rgb, mix(1.0, ao, gi_probes.data[index].ambient_occlusion));
}
- light.rgb *= gi_probes.data[index].dynamic_range;
- if (!gi_probes.data[index].blend_ambient) {
+ light.rgb *= voxel_gi_instances.data[index].dynamic_range;
+ if (!voxel_gi_instances.data[index].blend_ambient) {
light.a = 1.0;
}
out_diff += light * blend;
//radiance
- vec4 irr_light = voxel_cone_trace(gi_probe_textures[index], cell_size, position, ref_vec, tan(roughness * 0.5 * M_PI * 0.99), max_distance, gi_probes.data[index].bias);
- irr_light.rgb *= gi_probes.data[index].dynamic_range;
- if (!gi_probes.data[index].blend_ambient) {
+ vec4 irr_light = voxel_cone_trace(voxel_gi_textures[index], cell_size, position, ref_vec, tan(roughness * 0.5 * M_PI * 0.99), max_distance, voxel_gi_instances.data[index].bias);
+ irr_light.rgb *= voxel_gi_instances.data[index].dynamic_range;
+ if (!voxel_gi_instances.data[index].blend_ambient) {
irr_light.a = 1.0;
}
@@ -614,9 +591,9 @@ void process_gi(ivec2 pos, vec3 vertex, inout vec4 ambient_light, inout vec4 ref
sdfgi_process(vertex, normal, reflection, roughness, ambient_light, reflection_light);
#endif
-#ifdef USE_GIPROBES
+#ifdef USE_VOXEL_GI_INSTANCES
{
- uvec2 giprobe_tex = texelFetch(usampler2D(giprobe_buffer, linear_sampler), pos, 0).rg;
+ uvec2 voxel_gi_tex = texelFetch(usampler2D(voxel_gi_buffer, linear_sampler), pos, 0).rg;
roughness *= roughness;
//find arbitrary tangent and bitangent, then build a matrix
vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);
@@ -628,9 +605,9 @@ void process_gi(ivec2 pos, vec3 vertex, inout vec4 ambient_light, inout vec4 ref
vec4 spec_accum = vec4(0.0);
float blend_accum = 0.0;
- for (uint i = 0; i < params.max_giprobes; i++) {
- if (any(equal(uvec2(i), giprobe_tex))) {
- gi_probe_compute(i, vertex, normal, reflection, normal_mat, roughness, spec_accum, amb_accum, blend_accum);
+ for (uint i = 0; i < params.max_voxel_gi_instances; i++) {
+ if (any(equal(uvec2(i), voxel_gi_tex))) {
+ voxel_gi_compute(i, vertex, normal, reflection, normal_mat, roughness, spec_accum, amb_accum, blend_accum);
}
}
if (blend_accum > 0.0) {
diff --git a/servers/rendering/renderer_rd/shaders/giprobe_write.glsl b/servers/rendering/renderer_rd/shaders/giprobe_write.glsl
index 5dc2d08a3b..25d87ca45d 100644
--- a/servers/rendering/renderer_rd/shaders/giprobe_write.glsl
+++ b/servers/rendering/renderer_rd/shaders/giprobe_write.glsl
@@ -202,12 +202,7 @@ void main() {
vec3 emission = vec3(ivec3(cell_data.data[cell_index].emission & 0x3FF, (cell_data.data[cell_index].emission >> 10) & 0x7FF, cell_data.data[cell_index].emission >> 21)) * params.emission_scale;
vec4 normal = unpackSnorm4x8(cell_data.data[cell_index].normal);
-#ifdef MODE_ANISOTROPIC
- vec3 accum[6] = vec3[](vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0));
- const vec3 accum_dirs[6] = vec3[](vec3(1.0, 0.0, 0.0), vec3(-1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(0.0, -1.0, 0.0), vec3(0.0, 0.0, 1.0), vec3(0.0, 0.0, -1.0));
-#else
vec3 accum = vec3(0.0);
-#endif
for (uint i = 0; i < params.light_count; i++) {
float attenuation;
@@ -242,77 +237,35 @@ void main() {
vec3 light = lights.data[i].color * albedo.rgb * attenuation * lights.data[i].energy;
-#ifdef MODE_ANISOTROPIC
- for (uint j = 0; j < 6; j++) {
- accum[j] += max(0.0, dot(accum_dir, -light_dir)) * light + emission;
- }
-#else
if (length(normal.xyz) > 0.2) {
accum += max(0.0, dot(normal.xyz, -light_dir)) * light + emission;
} else {
//all directions
accum += light + emission;
}
-#endif
}
-#ifdef MODE_ANISOTROPIC
-
- output.data[cell_index * 6 + 0] = vec4(accum[0], 0.0);
- output.data[cell_index * 6 + 1] = vec4(accum[1], 0.0);
- output.data[cell_index * 6 + 2] = vec4(accum[2], 0.0);
- output.data[cell_index * 6 + 3] = vec4(accum[3], 0.0);
- output.data[cell_index * 6 + 4] = vec4(accum[4], 0.0);
- output.data[cell_index * 6 + 5] = vec4(accum[5], 0.0);
-#else
output.data[cell_index] = vec4(accum, 0.0);
-#endif
-
#endif //MODE_COMPUTE_LIGHT
#ifdef MODE_UPDATE_MIPMAPS
{
-#ifdef MODE_ANISOTROPIC
- vec3 light_accum[6] = vec3[](vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0));
-#else
vec3 light_accum = vec3(0.0);
-#endif
float count = 0.0;
for (uint i = 0; i < 8; i++) {
uint child_index = cell_children.data[cell_index].children[i];
if (child_index == NO_CHILDREN) {
continue;
}
-#ifdef MODE_ANISOTROPIC
- light_accum[1] += output.data[child_index * 6 + 0].rgb;
- light_accum[2] += output.data[child_index * 6 + 1].rgb;
- light_accum[3] += output.data[child_index * 6 + 2].rgb;
- light_accum[4] += output.data[child_index * 6 + 3].rgb;
- light_accum[5] += output.data[child_index * 6 + 4].rgb;
- light_accum[6] += output.data[child_index * 6 + 5].rgb;
-
-#else
light_accum += output.data[child_index].rgb;
-#endif
-
count += 1.0;
}
float divisor = mix(8.0, count, params.propagation);
-#ifdef MODE_ANISOTROPIC
- output.data[cell_index * 6 + 0] = vec4(light_accum[0] / divisor, 0.0);
- output.data[cell_index * 6 + 1] = vec4(light_accum[1] / divisor, 0.0);
- output.data[cell_index * 6 + 2] = vec4(light_accum[2] / divisor, 0.0);
- output.data[cell_index * 6 + 3] = vec4(light_accum[3] / divisor, 0.0);
- output.data[cell_index * 6 + 4] = vec4(light_accum[4] / divisor, 0.0);
- output.data[cell_index * 6 + 5] = vec4(light_accum[5] / divisor, 0.0);
-
-#else
output.data[cell_index] = vec4(light_accum / divisor, 0.0);
-#endif
}
#endif
diff --git a/servers/rendering/renderer_rd/shaders/light_data_inc.glsl b/servers/rendering/renderer_rd/shaders/light_data_inc.glsl
index 2fce258cff..fdc7729338 100644
--- a/servers/rendering/renderer_rd/shaders/light_data_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/light_data_inc.glsl
@@ -3,31 +3,31 @@
#define LIGHT_BAKE_STATIC 2
struct LightData { //this structure needs to be as packed as possible
- vec3 position;
- float inv_radius;
+ highp vec3 position;
+ highp float inv_radius;
- vec3 direction;
- float size;
+ mediump vec3 direction;
+ highp float size;
- vec3 color;
- float attenuation;
+ mediump vec3 color;
+ mediump float attenuation;
- float cone_attenuation;
- float cone_angle;
- float specular_amount;
+ mediump float cone_attenuation;
+ mediump float cone_angle;
+ mediump float specular_amount;
bool shadow_enabled;
- vec4 atlas_rect; // rect in the shadow atlas
- mat4 shadow_matrix;
- float shadow_bias;
- float shadow_normal_bias;
- float transmittance_bias;
- float soft_shadow_size; // for spot, it's the size in uv coordinates of the light, for omni it's the span angle
- float soft_shadow_scale; // scales the shadow kernel for blurrier shadows
+ highp vec4 atlas_rect; // rect in the shadow atlas
+ highp mat4 shadow_matrix;
+ highp float shadow_bias;
+ highp float shadow_normal_bias;
+ highp float transmittance_bias;
+ highp float soft_shadow_size; // for spot, it's the size in uv coordinates of the light, for omni it's the span angle
+ highp float soft_shadow_scale; // scales the shadow kernel for blurrier shadows
uint mask;
- float shadow_volumetric_fog_fade;
+ mediump float shadow_volumetric_fog_fade;
uint bake_mode;
- vec4 projector_rect; //projector rect in srgb decal atlas
+ highp vec4 projector_rect; //projector rect in srgb decal atlas
};
#define REFLECTION_AMBIENT_DISABLED 0
@@ -35,53 +35,53 @@ struct LightData { //this structure needs to be as packed as possible
#define REFLECTION_AMBIENT_COLOR 2
struct ReflectionData {
- vec3 box_extents;
- float index;
- vec3 box_offset;
+ highp vec3 box_extents;
+ mediump float index;
+ highp vec3 box_offset;
uint mask;
- vec3 ambient; // ambient color
- float intensity;
+ mediump vec3 ambient; // ambient color
+ mediump float intensity;
bool exterior;
bool box_project;
uint ambient_mode;
uint pad;
//0-8 is intensity,8-9 is ambient, mode
- mat4 local_matrix; // up to here for spot and omni, rest is for directional
+ highp mat4 local_matrix; // up to here for spot and omni, rest is for directional
// notes: for ambientblend, use distance to edge to blend between already existing global environment
};
struct DirectionalLightData {
- vec3 direction;
- float energy;
- vec3 color;
- float size;
- float specular;
+ mediump vec3 direction;
+ mediump float energy;
+ mediump vec3 color;
+ mediump float size;
+ mediump float specular;
uint mask;
- float softshadow_angle;
- float soft_shadow_scale;
+ highp float softshadow_angle;
+ highp float soft_shadow_scale;
bool blend_splits;
bool shadow_enabled;
- float fade_from;
- float fade_to;
+ highp float fade_from;
+ highp float fade_to;
uvec2 pad;
uint bake_mode;
- float shadow_volumetric_fog_fade;
- vec4 shadow_bias;
- vec4 shadow_normal_bias;
- vec4 shadow_transmittance_bias;
- vec4 shadow_z_range;
- vec4 shadow_range_begin;
- vec4 shadow_split_offsets;
- mat4 shadow_matrix1;
- mat4 shadow_matrix2;
- mat4 shadow_matrix3;
- mat4 shadow_matrix4;
- vec4 shadow_color1;
- vec4 shadow_color2;
- vec4 shadow_color3;
- vec4 shadow_color4;
- vec2 uv_scale1;
- vec2 uv_scale2;
- vec2 uv_scale3;
- vec2 uv_scale4;
+ mediump float shadow_volumetric_fog_fade;
+ highp vec4 shadow_bias;
+ highp vec4 shadow_normal_bias;
+ highp vec4 shadow_transmittance_bias;
+ highp vec4 shadow_z_range;
+ highp vec4 shadow_range_begin;
+ highp vec4 shadow_split_offsets;
+ highp mat4 shadow_matrix1;
+ highp mat4 shadow_matrix2;
+ highp mat4 shadow_matrix3;
+ highp mat4 shadow_matrix4;
+ mediump vec4 shadow_color1;
+ mediump vec4 shadow_color2;
+ mediump vec4 shadow_color3;
+ mediump vec4 shadow_color4;
+ highp vec2 uv_scale1;
+ highp vec2 uv_scale2;
+ highp vec2 uv_scale3;
+ highp vec2 uv_scale4;
};
diff --git a/servers/rendering/renderer_rd/shaders/luminance_reduce_raster.glsl b/servers/rendering/renderer_rd/shaders/luminance_reduce_raster.glsl
new file mode 100644
index 0000000000..29ebd74a90
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/luminance_reduce_raster.glsl
@@ -0,0 +1,74 @@
+/* clang-format off */
+#[vertex]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "luminance_reduce_raster_inc.glsl"
+
+layout(location = 0) out vec2 uv_interp;
+/* clang-format on */
+
+void main() {
+ vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
+ uv_interp = base_arr[gl_VertexIndex];
+
+ gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0);
+}
+
+/* clang-format off */
+#[fragment]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "luminance_reduce_raster_inc.glsl"
+
+layout(location = 0) in vec2 uv_interp;
+/* clang-format on */
+
+layout(set = 0, binding = 0) uniform sampler2D source_exposure;
+
+#ifdef FINAL_PASS
+layout(set = 1, binding = 0) uniform sampler2D prev_luminance;
+#endif
+
+layout(location = 0) out highp float luminance;
+
+void main() {
+ ivec2 dest_pos = ivec2(uv_interp * settings.dest_size);
+ ivec2 src_pos = ivec2(uv_interp * settings.source_size);
+
+ ivec2 next_pos = (dest_pos + ivec2(1)) * settings.source_size / settings.dest_size;
+ next_pos = max(next_pos, src_pos + ivec2(1)); //so it at least reads one pixel
+
+ highp vec3 source_color = vec3(0.0);
+ for (int i = src_pos.x; i < next_pos.x; i++) {
+ for (int j = src_pos.y; j < next_pos.y; j++) {
+ source_color += texelFetch(source_exposure, ivec2(i, j), 0).rgb;
+ }
+ }
+
+ source_color /= float((next_pos.x - src_pos.x) * (next_pos.y - src_pos.y));
+
+#ifdef FIRST_PASS
+ luminance = max(source_color.r, max(source_color.g, source_color.b));
+
+ // This formula should be more "accurate" but gave an overexposed result when testing.
+ // Leaving it here so we can revisit it if we want.
+ // luminance = source_color.r * 0.21 + source_color.g * 0.71 + source_color.b * 0.07;
+#else
+ luminance = source_color.r;
+#endif
+
+#ifdef FINAL_PASS
+ // Obtain our target luminance
+ luminance = clamp(luminance, settings.min_luminance, settings.max_luminance);
+
+ // Now smooth to our transition
+ highp float prev_lum = texelFetch(prev_luminance, ivec2(0, 0), 0).r; //1 pixel previous luminance
+ luminance = prev_lum + (luminance - prev_lum) * clamp(settings.exposure_adjust, 0.0, 1.0);
+#endif
+}
diff --git a/servers/rendering/renderer_rd/shaders/luminance_reduce_raster_inc.glsl b/servers/rendering/renderer_rd/shaders/luminance_reduce_raster_inc.glsl
new file mode 100644
index 0000000000..3cde9923fa
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/luminance_reduce_raster_inc.glsl
@@ -0,0 +1,11 @@
+
+layout(push_constant, binding = 1, std430) uniform PushConstant {
+ ivec2 source_size;
+ ivec2 dest_size;
+
+ float exposure_adjust;
+ float min_luminance;
+ float max_luminance;
+ uint pad1;
+}
+settings;
diff --git a/servers/rendering/renderer_rd/shaders/particles.glsl b/servers/rendering/renderer_rd/shaders/particles.glsl
index beaff10793..328becbc20 100644
--- a/servers/rendering/renderer_rd/shaders/particles.glsl
+++ b/servers/rendering/renderer_rd/shaders/particles.glsl
@@ -19,6 +19,8 @@ layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10
#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11
+#define SDF_MAX_LENGTH 16384.0
+
/* SET 0: GLOBAL DATA */
layout(set = 0, binding = 1) uniform sampler material_samplers[12];
@@ -54,6 +56,7 @@ struct Attractor {
#define COLLIDER_TYPE_BOX 1
#define COLLIDER_TYPE_SDF 2
#define COLLIDER_TYPE_HEIGHT_FIELD 3
+#define COLLIDER_TYPE_2D_SDF 4
struct Collider {
mat4 transform;
@@ -452,128 +455,167 @@ void main() {
#endif
- for (uint i = 0; i < FRAME.collider_count; i++) {
- vec3 normal;
- float depth;
- bool col = false;
+ if (FRAME.collider_count == 1 && FRAME.colliders[0].type == COLLIDER_TYPE_2D_SDF) {
+ //2D collision
- vec3 rel_vec = PARTICLE.xform[3].xyz - FRAME.colliders[i].transform[3].xyz;
- vec3 local_pos = rel_vec * mat3(FRAME.colliders[i].transform);
+ vec2 pos = PARTICLE.xform[3].xy;
+ vec4 to_sdf_x = FRAME.colliders[0].transform[0];
+ vec4 to_sdf_y = FRAME.colliders[0].transform[1];
+ vec2 sdf_pos = vec2(dot(vec4(pos, 0, 1), to_sdf_x), dot(vec4(pos, 0, 1), to_sdf_y));
- switch (FRAME.colliders[i].type) {
- case COLLIDER_TYPE_SPHERE: {
- float d = length(rel_vec) - (particle_size + FRAME.colliders[i].extents.x);
+ vec4 sdf_to_screen = vec4(FRAME.colliders[0].extents, FRAME.colliders[0].scale);
- if (d < 0.0) {
- col = true;
- depth = -d;
- normal = normalize(rel_vec);
- }
+ vec2 uv_pos = sdf_pos * sdf_to_screen.xy + sdf_to_screen.zw;
- } break;
- case COLLIDER_TYPE_BOX: {
- vec3 abs_pos = abs(local_pos);
- vec3 sgn_pos = sign(local_pos);
+ if (all(greaterThan(uv_pos, vec2(0.0))) && all(lessThan(uv_pos, vec2(1.0)))) {
+ vec2 pos2 = pos + vec2(0, particle_size);
+ vec2 sdf_pos2 = vec2(dot(vec4(pos2, 0, 1), to_sdf_x), dot(vec4(pos2, 0, 1), to_sdf_y));
+ float sdf_particle_size = distance(sdf_pos, sdf_pos2);
+
+ float d = texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv_pos).r * SDF_MAX_LENGTH;
+
+ d -= sdf_particle_size;
+
+ if (d < 0.0) {
+ const float EPSILON = 0.001;
+ vec2 n = normalize(vec2(
+ texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv_pos + vec2(EPSILON, 0.0)).r - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv_pos - vec2(EPSILON, 0.0)).r,
+ texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv_pos + vec2(0.0, EPSILON)).r - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv_pos - vec2(0.0, EPSILON)).r));
+
+ collided = true;
+ sdf_pos2 = sdf_pos + n * d;
+ pos2 = vec2(dot(vec4(sdf_pos2, 0, 1), FRAME.colliders[0].transform[2]), dot(vec4(sdf_pos2, 0, 1), FRAME.colliders[0].transform[3]));
+
+ n = pos - pos2;
+
+ collision_normal = normalize(vec3(n, 0.0));
+ collision_depth = length(n);
+ }
+ }
+
+ } else {
+ for (uint i = 0; i < FRAME.collider_count; i++) {
+ vec3 normal;
+ float depth;
+ bool col = false;
- if (any(greaterThan(abs_pos, FRAME.colliders[i].extents))) {
- //point outside box
+ vec3 rel_vec = PARTICLE.xform[3].xyz - FRAME.colliders[i].transform[3].xyz;
+ vec3 local_pos = rel_vec * mat3(FRAME.colliders[i].transform);
- vec3 closest = min(abs_pos, FRAME.colliders[i].extents);
- vec3 rel = abs_pos - closest;
- depth = length(rel) - particle_size;
- if (depth < 0.0) {
+ switch (FRAME.colliders[i].type) {
+ case COLLIDER_TYPE_SPHERE: {
+ float d = length(rel_vec) - (particle_size + FRAME.colliders[i].extents.x);
+
+ if (d < 0.0) {
col = true;
- normal = mat3(FRAME.colliders[i].transform) * (normalize(rel) * sgn_pos);
- depth = -depth;
+ depth = -d;
+ normal = normalize(rel_vec);
}
- } else {
- //point inside box
- vec3 axis_len = FRAME.colliders[i].extents - abs_pos;
- // there has to be a faster way to do this?
- if (all(lessThan(axis_len.xx, axis_len.yz))) {
- normal = vec3(1, 0, 0);
- } else if (all(lessThan(axis_len.yy, axis_len.xz))) {
- normal = vec3(0, 1, 0);
+
+ } break;
+ case COLLIDER_TYPE_BOX: {
+ vec3 abs_pos = abs(local_pos);
+ vec3 sgn_pos = sign(local_pos);
+
+ if (any(greaterThan(abs_pos, FRAME.colliders[i].extents))) {
+ //point outside box
+
+ vec3 closest = min(abs_pos, FRAME.colliders[i].extents);
+ vec3 rel = abs_pos - closest;
+ depth = length(rel) - particle_size;
+ if (depth < 0.0) {
+ col = true;
+ normal = mat3(FRAME.colliders[i].transform) * (normalize(rel) * sgn_pos);
+ depth = -depth;
+ }
} else {
- normal = vec3(0, 0, 1);
+ //point inside box
+ vec3 axis_len = FRAME.colliders[i].extents - abs_pos;
+ // there has to be a faster way to do this?
+ if (all(lessThan(axis_len.xx, axis_len.yz))) {
+ normal = vec3(1, 0, 0);
+ } else if (all(lessThan(axis_len.yy, axis_len.xz))) {
+ normal = vec3(0, 1, 0);
+ } else {
+ normal = vec3(0, 0, 1);
+ }
+
+ col = true;
+ depth = dot(normal * axis_len, vec3(1)) + particle_size;
+ normal = mat3(FRAME.colliders[i].transform) * (normal * sgn_pos);
}
- col = true;
- depth = dot(normal * axis_len, vec3(1)) + particle_size;
- normal = mat3(FRAME.colliders[i].transform) * (normal * sgn_pos);
- }
+ } break;
+ case COLLIDER_TYPE_SDF: {
+ vec3 apos = abs(local_pos);
+ float extra_dist = 0.0;
+ if (any(greaterThan(apos, FRAME.colliders[i].extents))) { //outside
+ vec3 mpos = min(apos, FRAME.colliders[i].extents);
+ extra_dist = distance(mpos, apos);
+ }
- } break;
- case COLLIDER_TYPE_SDF: {
- vec3 apos = abs(local_pos);
- float extra_dist = 0.0;
- if (any(greaterThan(apos, FRAME.colliders[i].extents))) { //outside
- vec3 mpos = min(apos, FRAME.colliders[i].extents);
- extra_dist = distance(mpos, apos);
- }
+ if (extra_dist > particle_size) {
+ continue;
+ }
- if (extra_dist > particle_size) {
- continue;
- }
+ vec3 uvw_pos = (local_pos / FRAME.colliders[i].extents) * 0.5 + 0.5;
+ float s = texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos).r;
+ s *= FRAME.colliders[i].scale;
+ s += extra_dist;
+ if (s < particle_size) {
+ col = true;
+ depth = particle_size - s;
+ const float EPSILON = 0.001;
+ normal = mat3(FRAME.colliders[i].transform) *
+ normalize(
+ vec3(
+ texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(EPSILON, 0.0, 0.0)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(EPSILON, 0.0, 0.0)).r,
+ texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(0.0, EPSILON, 0.0)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(0.0, EPSILON, 0.0)).r,
+ texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(0.0, 0.0, EPSILON)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(0.0, 0.0, EPSILON)).r));
+ }
- vec3 uvw_pos = (local_pos / FRAME.colliders[i].extents) * 0.5 + 0.5;
- float s = texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos).r;
- s *= FRAME.colliders[i].scale;
- s += extra_dist;
- if (s < particle_size) {
- col = true;
- depth = particle_size - s;
- const float EPSILON = 0.001;
- normal = mat3(FRAME.colliders[i].transform) *
- normalize(
- vec3(
- texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(EPSILON, 0.0, 0.0)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(EPSILON, 0.0, 0.0)).r,
- texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(0.0, EPSILON, 0.0)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(0.0, EPSILON, 0.0)).r,
- texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(0.0, 0.0, EPSILON)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(0.0, 0.0, EPSILON)).r));
- }
+ } break;
+ case COLLIDER_TYPE_HEIGHT_FIELD: {
+ vec3 local_pos_bottom = local_pos;
+ local_pos_bottom.y -= particle_size;
- } break;
- case COLLIDER_TYPE_HEIGHT_FIELD: {
- vec3 local_pos_bottom = local_pos;
- local_pos_bottom.y -= particle_size;
+ if (any(greaterThan(abs(local_pos_bottom), FRAME.colliders[i].extents))) {
+ continue;
+ }
+ const float DELTA = 1.0 / 8192.0;
- if (any(greaterThan(abs(local_pos_bottom), FRAME.colliders[i].extents))) {
- continue;
- }
+ vec3 uvw_pos = vec3(local_pos_bottom / FRAME.colliders[i].extents) * 0.5 + 0.5;
- const float DELTA = 1.0 / 8192.0;
+ float y = 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz).r;
- vec3 uvw_pos = vec3(local_pos_bottom / FRAME.colliders[i].extents) * 0.5 + 0.5;
+ if (y > uvw_pos.y) {
+ //inside heightfield
- float y = 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz).r;
+ vec3 pos1 = (vec3(uvw_pos.x, y, uvw_pos.z) * 2.0 - 1.0) * FRAME.colliders[i].extents;
+ vec3 pos2 = (vec3(uvw_pos.x + DELTA, 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz + vec2(DELTA, 0)).r, uvw_pos.z) * 2.0 - 1.0) * FRAME.colliders[i].extents;
+ vec3 pos3 = (vec3(uvw_pos.x, 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz + vec2(0, DELTA)).r, uvw_pos.z + DELTA) * 2.0 - 1.0) * FRAME.colliders[i].extents;
- if (y > uvw_pos.y) {
- //inside heightfield
+ normal = normalize(cross(pos1 - pos2, pos1 - pos3));
+ float local_y = (vec3(local_pos / FRAME.colliders[i].extents) * 0.5 + 0.5).y;
- vec3 pos1 = (vec3(uvw_pos.x, y, uvw_pos.z) * 2.0 - 1.0) * FRAME.colliders[i].extents;
- vec3 pos2 = (vec3(uvw_pos.x + DELTA, 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz + vec2(DELTA, 0)).r, uvw_pos.z) * 2.0 - 1.0) * FRAME.colliders[i].extents;
- vec3 pos3 = (vec3(uvw_pos.x, 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz + vec2(0, DELTA)).r, uvw_pos.z + DELTA) * 2.0 - 1.0) * FRAME.colliders[i].extents;
+ col = true;
+ depth = dot(normal, pos1) - dot(normal, local_pos_bottom);
+ }
- normal = normalize(cross(pos1 - pos2, pos1 - pos3));
- float local_y = (vec3(local_pos / FRAME.colliders[i].extents) * 0.5 + 0.5).y;
+ } break;
+ }
- col = true;
- depth = dot(normal, pos1) - dot(normal, local_pos_bottom);
+ if (col) {
+ if (!collided) {
+ collided = true;
+ collision_normal = normal;
+ collision_depth = depth;
+ } else {
+ vec3 c = collision_normal * collision_depth;
+ c += normal * max(0.0, depth - dot(normal, c));
+ collision_normal = normalize(c);
+ collision_depth = length(c);
}
-
- } break;
- }
-
- if (col) {
- if (!collided) {
- collided = true;
- collision_normal = normal;
- collision_depth = depth;
- } else {
- vec3 c = collision_normal * collision_depth;
- c += normal * max(0.0, depth - dot(normal, c));
- collision_normal = normalize(c);
- collision_depth = length(c);
}
}
}
diff --git a/servers/rendering/renderer_rd/shaders/particles_copy.glsl b/servers/rendering/renderer_rd/shaders/particles_copy.glsl
index e2bebadf1a..e88e68b511 100644
--- a/servers/rendering/renderer_rd/shaders/particles_copy.glsl
+++ b/servers/rendering/renderer_rd/shaders/particles_copy.glsl
@@ -53,6 +53,11 @@ layout(push_constant, binding = 0, std430) uniform Params {
vec3 align_up;
uint align_mode;
+
+ bool order_by_lifetime;
+ uint lifetime_split;
+ bool lifetime_reverse;
+ uint pad;
}
params;
@@ -80,7 +85,6 @@ void main() {
#ifdef MODE_FILL_INSTANCES
uint particle = gl_GlobalInvocationID.x;
- uint write_offset = gl_GlobalInvocationID.x * (3 + 1 + 1); //xform + color + custom
if (particle >= params.total_particles) {
return; //discard
@@ -93,14 +97,48 @@ void main() {
} else {
particle = uint(sort_buffer.data[particle].y); //use index from sort buffer
}
-#endif
+#else
+ if (params.order_by_lifetime) {
+ if (params.trail_size > 1) {
+ uint limit = (params.total_particles / params.trail_size) - params.lifetime_split;
+
+ uint base_index = particle / params.trail_size;
+ uint base_offset = particle % params.trail_size;
+
+ if (params.lifetime_reverse) {
+ base_index = (params.total_particles / params.trail_size) - base_index - 1;
+ }
+
+ if (base_index < limit) {
+ base_index = params.lifetime_split + base_index;
+ } else {
+ base_index -= limit;
+ }
+
+ particle = base_index * params.trail_size + base_offset;
+
+ } else {
+ uint limit = params.total_particles - params.lifetime_split;
+
+ if (params.lifetime_reverse) {
+ particle = params.total_particles - particle - 1;
+ }
+
+ if (particle < limit) {
+ particle = params.lifetime_split + particle;
+ } else {
+ particle -= limit;
+ }
+ }
+ }
+#endif // USE_SORT_BUFFER
mat4 txform;
if (bool(particles.data[particle].flags & PARTICLE_FLAG_ACTIVE) || bool(particles.data[particle].flags & PARTICLE_FLAG_TRAILED)) {
txform = particles.data[particle].xform;
if (params.trail_size > 1) {
- // since the steps dont fit precisely in the history frames, must do a tiny bit of
+ // Since the steps don't fit precisely in the history frames, must do a tiny bit of
// interpolation to get them close to their intended location.
uint part_ofs = particle % params.trail_size;
float natural_ofs = fract((float(part_ofs) / float(params.trail_size)) * float(params.trail_total)) * params.frame_delta;
@@ -165,12 +203,17 @@ void main() {
#ifdef MODE_2D
+ uint write_offset = gl_GlobalInvocationID.x * (2 + 1 + 1); //xform + color + custom
+
instances.data[write_offset + 0] = txform[0];
instances.data[write_offset + 1] = txform[1];
instances.data[write_offset + 2] = particles.data[particle].color;
instances.data[write_offset + 3] = particles.data[particle].custom;
#else
+
+ uint write_offset = gl_GlobalInvocationID.x * (3 + 1 + 1); //xform + color + custom
+
instances.data[write_offset + 0] = txform[0];
instances.data[write_offset + 1] = txform[1];
instances.data[write_offset + 2] = txform[2];
diff --git a/servers/rendering/renderer_rd/shaders/resolve.glsl b/servers/rendering/renderer_rd/shaders/resolve.glsl
index 2286a26485..fecf812a8c 100644
--- a/servers/rendering/renderer_rd/shaders/resolve.glsl
+++ b/servers/rendering/renderer_rd/shaders/resolve.glsl
@@ -6,6 +6,11 @@
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
+#ifdef MODE_RESOLVE_DEPTH
+layout(set = 0, binding = 0) uniform sampler2DMS source_depth;
+layout(r32f, set = 1, binding = 0) uniform restrict writeonly image2D dest_depth;
+#endif
+
#ifdef MODE_RESOLVE_GI
layout(set = 0, binding = 0) uniform sampler2DMS source_depth;
layout(set = 0, binding = 1) uniform sampler2DMS source_normal_roughness;
@@ -13,9 +18,9 @@ layout(set = 0, binding = 1) uniform sampler2DMS source_normal_roughness;
layout(r32f, set = 1, binding = 0) uniform restrict writeonly image2D dest_depth;
layout(rgba8, set = 1, binding = 1) uniform restrict writeonly image2D dest_normal_roughness;
-#ifdef GIPROBE_RESOLVE
-layout(set = 2, binding = 0) uniform usampler2DMS source_giprobe;
-layout(rg8ui, set = 3, binding = 0) uniform restrict writeonly uimage2D dest_giprobe;
+#ifdef VOXEL_GI_RESOLVE
+layout(set = 2, binding = 0) uniform usampler2DMS source_voxel_gi;
+layout(rg8ui, set = 3, binding = 0) uniform restrict writeonly uimage2D dest_voxel_gi;
#endif
#endif
@@ -34,12 +39,23 @@ void main() {
return;
}
+#ifdef MODE_RESOLVE_DEPTH
+
+ float depth_avg = 0.0;
+ for (int i = 0; i < params.sample_count; i++) {
+ depth_avg += texelFetch(source_depth, pos, i).r;
+ }
+ depth_avg /= float(params.sample_count);
+ imageStore(dest_depth, pos, vec4(depth_avg));
+
+#endif
+
#ifdef MODE_RESOLVE_GI
float best_depth = 1e20;
vec4 best_normal_roughness = vec4(0.0);
-#ifdef GIPROBE_RESOLVE
- uvec2 best_giprobe;
+#ifdef VOXEL_GI_RESOLVE
+ uvec2 best_voxel_gi;
#endif
#if 0
@@ -50,8 +66,8 @@ void main() {
best_depth = depth;
best_normal_roughness = texelFetch(source_normal_roughness,pos,i);
-#ifdef GIPROBE_RESOLVE
- best_giprobe = texelFetch(source_giprobe,pos,i).rg;
+#ifdef VOXEL_GI_RESOLVE
+ best_voxel_gi = texelFetch(source_voxel_gi,pos,i).rg;
#endif
}
}
@@ -204,16 +220,16 @@ void main() {
#endif
best_depth = texelFetch(source_depth, pos, best_index).r;
best_normal_roughness = texelFetch(source_normal_roughness, pos, best_index);
-#ifdef GIPROBE_RESOLVE
- best_giprobe = texelFetch(source_giprobe, pos, best_index).rg;
+#ifdef VOXEL_GI_RESOLVE
+ best_voxel_gi = texelFetch(source_voxel_gi, pos, best_index).rg;
#endif
#endif
imageStore(dest_depth, pos, vec4(best_depth));
imageStore(dest_normal_roughness, pos, vec4(best_normal_roughness));
-#ifdef GIPROBE_RESOLVE
- imageStore(dest_giprobe, pos, uvec4(best_giprobe, 0, 0));
+#ifdef VOXEL_GI_RESOLVE
+ imageStore(dest_voxel_gi, pos, uvec4(best_voxel_gi, 0, 0));
#endif
#endif
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_aa_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_aa_inc.glsl
index 99714b4504..97c913d489 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_aa_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_aa_inc.glsl
@@ -2,7 +2,7 @@
float hash_2d(vec2 p) {
return fract(1.0e4 * sin(17.0 * p.x + 0.1 * p.y) *
- (0.1 + abs(sin(13.0 * p.y + p.x))));
+ (0.1 + abs(sin(13.0 * p.y + p.x))));
}
float hash_3d(vec3 p) {
@@ -29,8 +29,7 @@ float compute_alpha_hash_threshold(vec3 pos, float hash_scale) {
vec3 cases = vec3(a_interp * a_interp / (2.0 * min_lerp * (1.0 - min_lerp)),
(a_interp - 0.5 * min_lerp) / (1.0 - min_lerp),
- 1.0 - ((1.0 - a_interp) * (1.0 - a_interp) /
- (2.0 * min_lerp * (1.0 - min_lerp))));
+ 1.0 - ((1.0 - a_interp) * (1.0 - a_interp) / (2.0 * min_lerp * (1.0 - min_lerp))));
float alpha_hash_threshold =
(lerp_factor < (1.0 - min_lerp)) ? ((lerp_factor < min_lerp) ? cases.x : cases.y) : cases.z;
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
index 1d67a3f1df..e4628b2d5a 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
@@ -6,6 +6,8 @@
#include "scene_forward_clustered_inc.glsl"
+#define SHADER_IS_SRGB false
+
/* INPUT ATTRIBS */
layout(location = 0) in vec3 vertex_attrib;
@@ -95,7 +97,7 @@ layout(location = 8) out float dp_clip;
#endif
-layout(location = 9) out flat uint instance_index;
+layout(location = 9) out flat uint instance_index_interp;
invariant gl_Position;
@@ -107,18 +109,20 @@ void main() {
color_interp = color_attrib;
#endif
- instance_index = draw_call.instance_index;
+ uint instance_index = draw_call.instance_index;
bool is_multimesh = bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH);
if (!is_multimesh) {
instance_index += gl_InstanceIndex;
}
+ instance_index_interp = instance_index;
+
mat4 world_matrix = instances.data[instance_index].transform;
mat3 world_normal_matrix;
if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_NON_UNIFORM_SCALE)) {
- world_normal_matrix = inverse(mat3(world_matrix));
+ world_normal_matrix = transpose(inverse(mat3(world_matrix)));
} else {
world_normal_matrix = mat3(world_matrix);
}
@@ -356,6 +360,29 @@ void main() {
#VERSION_DEFINES
+#define SHADER_IS_SRGB false
+
+/* Specialization Constants (Toggles) */
+
+layout(constant_id = 0) const bool sc_use_forward_gi = false;
+layout(constant_id = 1) const bool sc_use_light_projector = false;
+layout(constant_id = 2) const bool sc_use_light_soft_shadows = false;
+layout(constant_id = 3) const bool sc_use_directional_soft_shadows = false;
+
+/* Specialization Constants (Values) */
+
+layout(constant_id = 6) const uint sc_soft_shadow_samples = 4;
+layout(constant_id = 7) const uint sc_penumbra_shadow_samples = 4;
+
+layout(constant_id = 8) const uint sc_directional_soft_shadow_samples = 4;
+layout(constant_id = 9) const uint sc_directional_penumbra_shadow_samples = 4;
+
+layout(constant_id = 10) const bool sc_decal_use_mipmaps = true;
+layout(constant_id = 11) const bool sc_projector_use_mipmaps = true;
+
+// not used in clustered renderer but we share some code with the mobile renderer that requires this.
+const float sc_luminance_multiplier = 1.0;
+
#include "scene_forward_clustered_inc.glsl"
/* Varyings */
@@ -389,7 +416,7 @@ layout(location = 8) in float dp_clip;
#endif
-layout(location = 9) in flat uint instance_index;
+layout(location = 9) in flat uint instance_index_interp;
//defines to keep compatibility with vertex
@@ -426,8 +453,8 @@ layout(location = 4) out float depth_output_buffer;
#ifdef MODE_RENDER_NORMAL_ROUGHNESS
layout(location = 0) out vec4 normal_roughness_output_buffer;
-#ifdef MODE_RENDER_GIPROBE
-layout(location = 1) out uvec2 giprobe_buffer;
+#ifdef MODE_RENDER_VOXEL_GI
+layout(location = 1) out uvec2 voxel_gi_buffer;
#endif
#endif //MODE_RENDER_NORMAL
@@ -448,14 +475,15 @@ layout(location = 0) out vec4 frag_color;
#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
-#include "scene_forward_lights_inc.glsl"
+/* Make a default specular mode SPECULAR_SCHLICK_GGX. */
+#if !defined(SPECULAR_DISABLED) && !defined(SPECULAR_SCHLICK_GGX) && !defined(SPECULAR_BLINN) && !defined(SPECULAR_PHONG) && !defined(SPECULAR_TOON)
+#define SPECULAR_SCHLICK_GGX
+#endif
-#ifdef USE_FORWARD_GI
+#include "scene_forward_lights_inc.glsl"
#include "scene_forward_gi_inc.glsl"
-#endif //USE_FORWARD_GI
-
#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
#ifndef MODE_RENDER_DEPTH
@@ -502,14 +530,14 @@ vec4 fog_process(vec3 vertex) {
}
}
- float fog_amount = 1.0 - exp(min(0.0, vertex.z * scene_data.fog_density));
+ float fog_amount = 1.0 - exp(min(0.0, -length(vertex) * scene_data.fog_density));
- if (abs(scene_data.fog_height_density) > 0.001) {
+ if (abs(scene_data.fog_height_density) >= 0.0001) {
float y = (scene_data.camera_matrix * vec4(vertex, 1.0)).y;
- float y_dist = scene_data.fog_height - y;
+ float y_dist = y - scene_data.fog_height;
- float vfog_amount = clamp(exp(y_dist * scene_data.fog_height_density), 0.0, 1.0);
+ float vfog_amount = 1.0 - exp(min(0.0, y_dist * scene_data.fog_height_density));
fog_amount = max(vfog_amount, fog_amount);
}
@@ -542,14 +570,15 @@ void main() {
discard;
#endif
+ uint instance_index = instance_index_interp;
+
//lay out everything, whathever is unused is optimized away anyway
vec3 vertex = vertex_interp;
vec3 view = -normalize(vertex_interp);
vec3 albedo = vec3(1.0);
vec3 backlight = vec3(0.0);
- vec4 transmittance_color = vec4(0.0);
+ vec4 transmittance_color = vec4(0.0, 0.0, 0.0, 1.0);
float transmittance_depth = 0.0;
- float transmittance_curve = 1.0;
float transmittance_boost = 0.0;
float metallic = 0.0;
float specular = 0.5;
@@ -572,7 +601,7 @@ void main() {
float ao = 1.0;
float ao_light_affect = 0.0;
- float alpha = 1.0;
+ float alpha = float(instances.data[instance_index].flags >> INSTANCE_FLAGS_FADE_SHIFT) / float(255.0);
#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
vec3 binormal = normalize(binormal_interp);
@@ -634,12 +663,8 @@ void main() {
}
#ifdef LIGHT_TRANSMITTANCE_USED
-#ifdef SSS_MODE_SKIN
- transmittance_color.a = sss_strength;
-#else
transmittance_color.a *= sss_strength;
#endif
-#endif
#ifndef USE_SHADOW_TO_OPACITY
@@ -662,7 +687,7 @@ void main() {
#endif
#ifdef ALPHA_ANTIALIASING_EDGE_USED
-// If alpha scissor is used, we must further the edge threshold, otherwise we wont get any edge feather
+// If alpha scissor is used, we must further the edge threshold, otherwise we won't get any edge feather
#ifdef ALPHA_SCISSOR_USED
alpha_antialiasing_edge = clamp(alpha_scissor_threshold + alpha_antialiasing_edge, 0.0, 1.0);
#endif
@@ -670,7 +695,7 @@ void main() {
#endif // ALPHA_ANTIALIASING_EDGE_USED
#ifdef USE_OPAQUE_PREPASS
- if (alpha < opaque_prepass_threshold) {
+ if (alpha < scene_data.opaque_prepass_threshold) {
discard;
}
#endif // USE_OPAQUE_PREPASS
@@ -798,25 +823,35 @@ void main() {
continue; //out of decal
}
- //we need ddx/ddy for mipmaps, so simulate them
- vec2 ddx = (decals.data[decal_index].xform * vec4(vertex_ddx, 0.0)).xz;
- vec2 ddy = (decals.data[decal_index].xform * vec4(vertex_ddy, 0.0)).xz;
-
float fade = pow(1.0 - (uv_local.y > 0.0 ? uv_local.y : -uv_local.y), uv_local.y > 0.0 ? decals.data[decal_index].upper_fade : decals.data[decal_index].lower_fade);
if (decals.data[decal_index].normal_fade > 0.0) {
fade *= smoothstep(decals.data[decal_index].normal_fade, 1.0, dot(normal_interp, decals.data[decal_index].normal) * 0.5 + 0.5);
}
+ //we need ddx/ddy for mipmaps, so simulate them
+ vec2 ddx = (decals.data[decal_index].xform * vec4(vertex_ddx, 0.0)).xz;
+ vec2 ddy = (decals.data[decal_index].xform * vec4(vertex_ddy, 0.0)).xz;
+
if (decals.data[decal_index].albedo_rect != vec4(0.0)) {
//has albedo
- vec4 decal_albedo = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, ddx * decals.data[decal_index].albedo_rect.zw, ddy * decals.data[decal_index].albedo_rect.zw);
+ vec4 decal_albedo;
+ if (sc_decal_use_mipmaps) {
+ decal_albedo = textureGrad(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, ddx * decals.data[decal_index].albedo_rect.zw, ddy * decals.data[decal_index].albedo_rect.zw);
+ } else {
+ decal_albedo = textureLod(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, 0.0);
+ }
decal_albedo *= decals.data[decal_index].modulate;
decal_albedo.a *= fade;
albedo = mix(albedo, decal_albedo.rgb, decal_albedo.a * decals.data[decal_index].albedo_mix);
if (decals.data[decal_index].normal_rect != vec4(0.0)) {
- vec3 decal_normal = textureGrad(sampler2D(decal_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, ddx * decals.data[decal_index].normal_rect.zw, ddy * decals.data[decal_index].normal_rect.zw).xyz;
+ vec3 decal_normal;
+ if (sc_decal_use_mipmaps) {
+ decal_normal = textureGrad(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, ddx * decals.data[decal_index].normal_rect.zw, ddy * decals.data[decal_index].normal_rect.zw).xyz;
+ } else {
+ decal_normal = textureLod(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, 0.0).xyz;
+ }
decal_normal.xy = decal_normal.xy * vec2(2.0, -2.0) - vec2(1.0, -1.0); //users prefer flipped y normal maps in most authoring software
decal_normal.z = sqrt(max(0.0, 1.0 - dot(decal_normal.xy, decal_normal.xy)));
//convert to view space, use xzy because y is up
@@ -826,7 +861,12 @@ void main() {
}
if (decals.data[decal_index].orm_rect != vec4(0.0)) {
- vec3 decal_orm = textureGrad(sampler2D(decal_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, ddx * decals.data[decal_index].orm_rect.zw, ddy * decals.data[decal_index].orm_rect.zw).xyz;
+ vec3 decal_orm;
+ if (sc_decal_use_mipmaps) {
+ decal_orm = textureGrad(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, ddx * decals.data[decal_index].orm_rect.zw, ddy * decals.data[decal_index].orm_rect.zw).xyz;
+ } else {
+ decal_orm = textureLod(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, 0.0).xyz;
+ }
ao = mix(ao, decal_orm.r, decal_albedo.a);
roughness = mix(roughness, decal_orm.g, decal_albedo.a);
metallic = mix(metallic, decal_orm.b, decal_albedo.a);
@@ -835,7 +875,11 @@ void main() {
if (decals.data[decal_index].emission_rect != vec4(0.0)) {
//emission is additive, so its independent from albedo
- emission += textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, ddx * decals.data[decal_index].emission_rect.zw, ddy * decals.data[decal_index].emission_rect.zw).xyz * decals.data[decal_index].emission_energy * fade;
+ if (sc_decal_use_mipmaps) {
+ emission += textureGrad(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, ddx * decals.data[decal_index].emission_rect.zw, ddy * decals.data[decal_index].emission_rect.zw).xyz * decals.data[decal_index].emission_energy * fade;
+ } else {
+ emission += textureLod(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, 0.0).xyz * decals.data[decal_index].emission_energy * fade;
+ }
}
}
}
@@ -848,9 +892,9 @@ void main() {
#ifdef NORMAL_USED
if (scene_data.roughness_limiter_enabled) {
- //http://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA.pdf
+ //https://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA.pdf
float roughness2 = roughness * roughness;
- vec3 dndu = dFdx(normal), dndv = dFdx(normal);
+ vec3 dndu = dFdx(normal), dndv = dFdy(normal);
float variance = scene_data.roughness_limiter_amount * (dot(dndu, dndu) + dot(dndv, dndv));
float kernelRoughness2 = min(2.0 * variance, scene_data.roughness_limiter_limit); //limit effect
float filteredRoughness2 = min(1.0, roughness2 + kernelRoughness2);
@@ -867,6 +911,7 @@ void main() {
if (scene_data.use_reflection_cubemap) {
vec3 ref_vec = reflect(-view, normal);
+ float horizon = min(1.0 + dot(ref_vec, normal), 1.0);
ref_vec = scene_data.radiance_inverse_xform * ref_vec;
#ifdef USE_RADIANCE_CUBEMAP_ARRAY
@@ -879,6 +924,7 @@ void main() {
specular_light = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ref_vec, roughness * MAX_ROUGHNESS_LOD).rgb;
#endif //USE_RADIANCE_CUBEMAP_ARRAY
+ specular_light *= horizon * horizon;
specular_light *= scene_data.ambient_light_color_energy.a;
}
@@ -904,7 +950,7 @@ void main() {
}
#endif // USE_LIGHTMAP
#if defined(CUSTOM_IRRADIANCE_USED)
- ambient_light = mix(specular_light, custom_irradiance.rgb, custom_irradiance.a);
+ ambient_light = mix(ambient_light, custom_irradiance.rgb, custom_irradiance.a);
#endif
#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
@@ -926,15 +972,15 @@ void main() {
const float c4 = 0.886227;
const float c5 = 0.247708;
ambient_light += (c1 * lightmap_captures.data[index].sh[8].rgb * (wnormal.x * wnormal.x - wnormal.y * wnormal.y) +
- c3 * lightmap_captures.data[index].sh[6].rgb * wnormal.z * wnormal.z +
- c4 * lightmap_captures.data[index].sh[0].rgb -
- c5 * lightmap_captures.data[index].sh[6].rgb +
- 2.0 * c1 * lightmap_captures.data[index].sh[4].rgb * wnormal.x * wnormal.y +
- 2.0 * c1 * lightmap_captures.data[index].sh[7].rgb * wnormal.x * wnormal.z +
- 2.0 * c1 * lightmap_captures.data[index].sh[5].rgb * wnormal.y * wnormal.z +
- 2.0 * c2 * lightmap_captures.data[index].sh[3].rgb * wnormal.x +
- 2.0 * c2 * lightmap_captures.data[index].sh[1].rgb * wnormal.y +
- 2.0 * c2 * lightmap_captures.data[index].sh[2].rgb * wnormal.z);
+ c3 * lightmap_captures.data[index].sh[6].rgb * wnormal.z * wnormal.z +
+ c4 * lightmap_captures.data[index].sh[0].rgb -
+ c5 * lightmap_captures.data[index].sh[6].rgb +
+ 2.0 * c1 * lightmap_captures.data[index].sh[4].rgb * wnormal.x * wnormal.y +
+ 2.0 * c1 * lightmap_captures.data[index].sh[7].rgb * wnormal.x * wnormal.z +
+ 2.0 * c1 * lightmap_captures.data[index].sh[5].rgb * wnormal.y * wnormal.z +
+ 2.0 * c2 * lightmap_captures.data[index].sh[3].rgb * wnormal.x +
+ 2.0 * c2 * lightmap_captures.data[index].sh[1].rgb * wnormal.y +
+ 2.0 * c2 * lightmap_captures.data[index].sh[2].rgb * wnormal.z);
} else if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { // has actual lightmap
bool uses_sh = bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_SH_LIGHTMAP);
@@ -968,9 +1014,9 @@ void main() {
ambient_light += textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw, 0.0).rgb;
}
}
-#elif defined(USE_FORWARD_GI)
+#else
- if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_SDFGI)) { //has lightmap capture
+ if (sc_use_forward_gi && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_SDFGI)) { //has lightmap capture
//make vertex orientation the world one, but still align to camera
vec3 cam_pos = mat3(scene_data.camera_matrix) * vertex;
@@ -1042,7 +1088,7 @@ void main() {
}
}
- if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_GIPROBE)) { // process giprobes
+ if (sc_use_forward_gi && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_VOXEL_GI)) { // process voxel_gi_instances
uint index1 = instances.data[instance_index].gi_offset & 0xFFFF;
vec3 ref_vec = normalize(reflect(normalize(vertex), normal));
@@ -1054,12 +1100,12 @@ void main() {
vec4 amb_accum = vec4(0.0);
vec4 spec_accum = vec4(0.0);
- gi_probe_compute(index1, vertex, normal, ref_vec, normal_mat, roughness * roughness, ambient_light, specular_light, spec_accum, amb_accum);
+ voxel_gi_compute(index1, vertex, normal, ref_vec, normal_mat, roughness * roughness, ambient_light, specular_light, spec_accum, amb_accum);
uint index2 = instances.data[instance_index].gi_offset >> 16;
if (index2 != 0xFFFF) {
- gi_probe_compute(index2, vertex, normal, ref_vec, normal_mat, roughness * roughness, ambient_light, specular_light, spec_accum, amb_accum);
+ voxel_gi_compute(index2, vertex, normal, ref_vec, normal_mat, roughness * roughness, ambient_light, specular_light, spec_accum, amb_accum);
}
if (amb_accum.a > 0.0) {
@@ -1073,9 +1119,8 @@ void main() {
specular_light = spec_accum.rgb;
ambient_light = amb_accum.rgb;
}
-#else
- if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_GI_BUFFERS)) { //use GI buffers
+ if (!sc_use_forward_gi && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_GI_BUFFERS)) { //use GI buffers
vec2 coord;
@@ -1106,7 +1151,7 @@ void main() {
ambient_light = mix(ambient_light, buffer_ambient.rgb, buffer_ambient.a);
specular_light = mix(specular_light, buffer_reflection.rgb, buffer_reflection.a);
}
-#endif
+#endif // !USE_LIGHTMAP
if (scene_data.ssao_enabled) {
float ssao = texture(sampler2D(ao_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), screen_uv).r;
@@ -1187,7 +1232,7 @@ void main() {
specular_light *= specular * metallic * albedo * 2.0;
#else
- // scales the specular reflections, needs to be be computed before lighting happens,
+ // scales the specular reflections, needs to be computed before lighting happens,
// but after environment, GI, and reflection probes are added
// Environment brdf approximation (Lazarov 2013)
// see https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile
@@ -1212,9 +1257,10 @@ void main() {
// LIGHTING
#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
- { //directional light
+ { // Directional light.
- // Do shadow and lighting in two passes to reduce register pressure
+ // Do shadow and lighting in two passes to reduce register pressure.
+#ifndef SHADOWS_DISABLED
uint shadow0 = 0;
uint shadow1 = 0;
@@ -1233,306 +1279,178 @@ void main() {
float shadow = 1.0;
-#ifdef USE_SOFT_SHADOWS
- //version with soft shadows, more expensive
if (directional_lights.data[i].shadow_enabled) {
float depth_z = -vertex.z;
-
- vec4 pssm_coord;
- vec3 shadow_color = vec3(0.0);
vec3 light_dir = directional_lights.data[i].direction;
+ vec3 base_normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(light_dir, -normalize(normal_interp))));
-#define BIAS_FUNC(m_var, m_idx) \
- m_var.xyz += light_dir * directional_lights.data[i].shadow_bias[m_idx]; \
- vec3 normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(light_dir, -normalize(normal_interp)))) * directional_lights.data[i].shadow_normal_bias[m_idx]; \
- normal_bias -= light_dir * dot(light_dir, normal_bias); \
+#define BIAS_FUNC(m_var, m_idx) \
+ m_var.xyz += light_dir * directional_lights.data[i].shadow_bias[m_idx]; \
+ vec3 normal_bias = base_normal_bias * directional_lights.data[i].shadow_normal_bias[m_idx]; \
+ normal_bias -= light_dir * dot(light_dir, normal_bias); \
m_var.xyz += normal_bias;
- if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
- vec4 v = vec4(vertex, 1.0);
+ //version with soft shadows, more expensive
+ if (sc_use_directional_soft_shadows && directional_lights.data[i].softshadow_angle > 0) {
+ uint blend_count = 0;
+ const uint blend_max = directional_lights.data[i].blend_splits ? 2 : 1;
- BIAS_FUNC(v, 0)
+ if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
+ vec4 v = vec4(vertex, 1.0);
- pssm_coord = (directional_lights.data[i].shadow_matrix1 * v);
- pssm_coord /= pssm_coord.w;
+ BIAS_FUNC(v, 0)
+
+ vec4 pssm_coord = (directional_lights.data[i].shadow_matrix1 * v);
+ pssm_coord /= pssm_coord.w;
- if (directional_lights.data[i].softshadow_angle > 0) {
float range_pos = dot(directional_lights.data[i].direction, v.xyz);
float range_begin = directional_lights.data[i].shadow_range_begin.x;
float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
vec2 tex_scale = directional_lights.data[i].uv_scale1 * test_radius;
shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
- } else {
- shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+ blend_count++;
}
- shadow_color = directional_lights.data[i].shadow_color1.rgb;
-
- } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
- vec4 v = vec4(vertex, 1.0);
+ if (blend_count < blend_max && depth_z < directional_lights.data[i].shadow_split_offsets.y) {
+ vec4 v = vec4(vertex, 1.0);
- BIAS_FUNC(v, 1)
+ BIAS_FUNC(v, 1)
- pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
- pssm_coord /= pssm_coord.w;
+ vec4 pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
+ pssm_coord /= pssm_coord.w;
- if (directional_lights.data[i].softshadow_angle > 0) {
float range_pos = dot(directional_lights.data[i].direction, v.xyz);
float range_begin = directional_lights.data[i].shadow_range_begin.y;
float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
vec2 tex_scale = directional_lights.data[i].uv_scale2 * test_radius;
- shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
- } else {
- shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+ float s = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
+
+ if (blend_count == 0) {
+ shadow = s;
+ } else {
+ //blend
+ float blend = smoothstep(0.0, directional_lights.data[i].shadow_split_offsets.x, depth_z);
+ shadow = mix(shadow, s, blend);
+ }
+
+ blend_count++;
}
- shadow_color = directional_lights.data[i].shadow_color2.rgb;
- } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
- vec4 v = vec4(vertex, 1.0);
+ if (blend_count < blend_max && depth_z < directional_lights.data[i].shadow_split_offsets.z) {
+ vec4 v = vec4(vertex, 1.0);
- BIAS_FUNC(v, 2)
+ BIAS_FUNC(v, 2)
- pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
- pssm_coord /= pssm_coord.w;
+ vec4 pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
+ pssm_coord /= pssm_coord.w;
- if (directional_lights.data[i].softshadow_angle > 0) {
float range_pos = dot(directional_lights.data[i].direction, v.xyz);
float range_begin = directional_lights.data[i].shadow_range_begin.z;
float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
vec2 tex_scale = directional_lights.data[i].uv_scale3 * test_radius;
- shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
- } else {
- shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
- }
+ float s = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
- shadow_color = directional_lights.data[i].shadow_color3.rgb;
+ if (blend_count == 0) {
+ shadow = s;
+ } else {
+ //blend
+ float blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x, directional_lights.data[i].shadow_split_offsets.y, depth_z);
+ shadow = mix(shadow, s, blend);
+ }
- } else {
- vec4 v = vec4(vertex, 1.0);
+ blend_count++;
+ }
- BIAS_FUNC(v, 3)
+ if (blend_count < blend_max) {
+ vec4 v = vec4(vertex, 1.0);
- pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
- pssm_coord /= pssm_coord.w;
+ BIAS_FUNC(v, 3)
+
+ vec4 pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
+ pssm_coord /= pssm_coord.w;
- if (directional_lights.data[i].softshadow_angle > 0) {
float range_pos = dot(directional_lights.data[i].direction, v.xyz);
float range_begin = directional_lights.data[i].shadow_range_begin.w;
float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
vec2 tex_scale = directional_lights.data[i].uv_scale4 * test_radius;
- shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
- } else {
- shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
- }
+ float s = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
- shadow_color = directional_lights.data[i].shadow_color4.rgb;
- }
+ if (blend_count == 0) {
+ shadow = s;
+ } else {
+ //blend
+ float blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y, directional_lights.data[i].shadow_split_offsets.z, depth_z);
+ shadow = mix(shadow, s, blend);
+ }
+ }
- if (directional_lights.data[i].blend_splits) {
- vec3 shadow_color_blend = vec3(0.0);
- float pssm_blend;
- float shadow2;
+ } else { //no soft shadows
+ vec4 pssm_coord;
if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
vec4 v = vec4(vertex, 1.0);
- BIAS_FUNC(v, 1)
- pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
- pssm_coord /= pssm_coord.w;
- if (directional_lights.data[i].softshadow_angle > 0) {
- float range_pos = dot(directional_lights.data[i].direction, v.xyz);
- float range_begin = directional_lights.data[i].shadow_range_begin.y;
- float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
- vec2 tex_scale = directional_lights.data[i].uv_scale2 * test_radius;
- shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
- } else {
- shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
- }
+ BIAS_FUNC(v, 0)
- pssm_blend = smoothstep(0.0, directional_lights.data[i].shadow_split_offsets.x, depth_z);
- shadow_color_blend = directional_lights.data[i].shadow_color2.rgb;
+ pssm_coord = (directional_lights.data[i].shadow_matrix1 * v);
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
vec4 v = vec4(vertex, 1.0);
- BIAS_FUNC(v, 2)
- pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
- pssm_coord /= pssm_coord.w;
- if (directional_lights.data[i].softshadow_angle > 0) {
- float range_pos = dot(directional_lights.data[i].direction, v.xyz);
- float range_begin = directional_lights.data[i].shadow_range_begin.z;
- float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
- vec2 tex_scale = directional_lights.data[i].uv_scale3 * test_radius;
- shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
- } else {
- shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
- }
-
- pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x, directional_lights.data[i].shadow_split_offsets.y, depth_z);
+ BIAS_FUNC(v, 1)
- shadow_color_blend = directional_lights.data[i].shadow_color3.rgb;
+ pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
vec4 v = vec4(vertex, 1.0);
- BIAS_FUNC(v, 3)
- pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
- pssm_coord /= pssm_coord.w;
- if (directional_lights.data[i].softshadow_angle > 0) {
- float range_pos = dot(directional_lights.data[i].direction, v.xyz);
- float range_begin = directional_lights.data[i].shadow_range_begin.w;
- float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
- vec2 tex_scale = directional_lights.data[i].uv_scale4 * test_radius;
- shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
- } else {
- shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
- }
-
- pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y, directional_lights.data[i].shadow_split_offsets.z, depth_z);
- shadow_color_blend = directional_lights.data[i].shadow_color4.rgb;
- } else {
- pssm_blend = 0.0; //if no blend, same coord will be used (divide by z will result in same value, and already cached)
- }
-
- pssm_blend = sqrt(pssm_blend);
-
- shadow = mix(shadow, shadow2, pssm_blend);
- shadow_color = mix(shadow_color, shadow_color_blend, pssm_blend);
- }
-
- shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance
-
-#undef BIAS_FUNC
- }
-#else
- // Soft shadow disabled version
-
- if (directional_lights.data[i].shadow_enabled) {
- float depth_z = -vertex.z;
-
- vec4 pssm_coord;
- vec3 light_dir = directional_lights.data[i].direction;
- vec3 base_normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(light_dir, -normalize(normal_interp))));
-
-#define BIAS_FUNC(m_var, m_idx) \
- m_var.xyz += light_dir * directional_lights.data[i].shadow_bias[m_idx]; \
- vec3 normal_bias = base_normal_bias * directional_lights.data[i].shadow_normal_bias[m_idx]; \
- normal_bias -= light_dir * dot(light_dir, normal_bias); \
- m_var.xyz += normal_bias;
-
- if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
- vec4 v = vec4(vertex, 1.0);
-
- BIAS_FUNC(v, 0)
-
- pssm_coord = (directional_lights.data[i].shadow_matrix1 * v);
-#ifdef LIGHT_TRANSMITTANCE_USED
- {
- vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.x, 1.0);
- vec4 trans_coord = directional_lights.data[i].shadow_matrix1 * trans_vertex;
- trans_coord /= trans_coord.w;
-
- float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r;
- shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.x;
- float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.x;
-
- transmittance_z = z - shadow_z;
- }
-#endif
- } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
- vec4 v = vec4(vertex, 1.0);
-
- BIAS_FUNC(v, 1)
-
- pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
-#ifdef LIGHT_TRANSMITTANCE_USED
- {
- vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.y, 1.0);
- vec4 trans_coord = directional_lights.data[i].shadow_matrix2 * trans_vertex;
- trans_coord /= trans_coord.w;
-
- float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r;
- shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.y;
- float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.y;
-
- transmittance_z = z - shadow_z;
- }
-#endif
- } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
- vec4 v = vec4(vertex, 1.0);
-
- BIAS_FUNC(v, 2)
- pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
-#ifdef LIGHT_TRANSMITTANCE_USED
- {
- vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.z, 1.0);
- vec4 trans_coord = directional_lights.data[i].shadow_matrix3 * trans_vertex;
- trans_coord /= trans_coord.w;
-
- float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r;
- shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.z;
- float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.z;
-
- transmittance_z = z - shadow_z;
- }
-#endif
-
- } else {
- vec4 v = vec4(vertex, 1.0);
+ BIAS_FUNC(v, 2)
- BIAS_FUNC(v, 3)
+ pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
- pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
-#ifdef LIGHT_TRANSMITTANCE_USED
- {
- vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.w, 1.0);
- vec4 trans_coord = directional_lights.data[i].shadow_matrix4 * trans_vertex;
- trans_coord /= trans_coord.w;
+ } else {
+ vec4 v = vec4(vertex, 1.0);
- float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r;
- shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.w;
- float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.w;
+ BIAS_FUNC(v, 3)
- transmittance_z = z - shadow_z;
+ pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
}
-#endif
- }
- pssm_coord /= pssm_coord.w;
+ pssm_coord /= pssm_coord.w;
- shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+ shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+
+ if (directional_lights.data[i].blend_splits) {
+ float pssm_blend;
+
+ if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
+ vec4 v = vec4(vertex, 1.0);
+ BIAS_FUNC(v, 1)
+ pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
+ pssm_blend = smoothstep(0.0, directional_lights.data[i].shadow_split_offsets.x, depth_z);
+ } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
+ vec4 v = vec4(vertex, 1.0);
+ BIAS_FUNC(v, 2)
+ pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
+ pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x, directional_lights.data[i].shadow_split_offsets.y, depth_z);
+ } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
+ vec4 v = vec4(vertex, 1.0);
+ BIAS_FUNC(v, 3)
+ pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
+ pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y, directional_lights.data[i].shadow_split_offsets.z, depth_z);
+ } else {
+ pssm_blend = 0.0; //if no blend, same coord will be used (divide by z will result in same value, and already cached)
+ }
- if (directional_lights.data[i].blend_splits) {
- float pssm_blend;
+ pssm_coord /= pssm_coord.w;
- if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
- vec4 v = vec4(vertex, 1.0);
- BIAS_FUNC(v, 1)
- pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
- pssm_blend = smoothstep(0.0, directional_lights.data[i].shadow_split_offsets.x, depth_z);
- } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
- vec4 v = vec4(vertex, 1.0);
- BIAS_FUNC(v, 2)
- pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
- pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x, directional_lights.data[i].shadow_split_offsets.y, depth_z);
- } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
- vec4 v = vec4(vertex, 1.0);
- BIAS_FUNC(v, 3)
- pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
- pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y, directional_lights.data[i].shadow_split_offsets.z, depth_z);
- } else {
- pssm_blend = 0.0; //if no blend, same coord will be used (divide by z will result in same value, and already cached)
+ float shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+ shadow = mix(shadow, shadow2, pssm_blend);
}
-
- pssm_coord /= pssm_coord.w;
-
- float shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
- shadow = mix(shadow, shadow2, pssm_blend);
}
shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance
#undef BIAS_FUNC
- }
-#endif
+ } // shadows
if (i < 4) {
shadow0 |= uint(clamp(shadow * 255.0, 0.0, 255.0)) << (i * 8);
@@ -1540,6 +1458,7 @@ void main() {
shadow1 |= uint(clamp(shadow * 255.0, 0.0, 255.0)) << ((i - 4) * 8);
}
}
+#endif // SHADOWS_DISABLED
for (uint i = 0; i < 8; i++) {
if (i >= scene_data.directional_light_count) {
@@ -1562,8 +1481,8 @@ void main() {
trans_coord /= trans_coord.w;
float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r;
- shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.x;
- float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.x;
+ shadow_z *= directional_lights.data[i].shadow_z_range.x;
+ float z = trans_coord.z * directional_lights.data[i].shadow_z_range.x;
transmittance_z = z - shadow_z;
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
@@ -1572,8 +1491,8 @@ void main() {
trans_coord /= trans_coord.w;
float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r;
- shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.y;
- float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.y;
+ shadow_z *= directional_lights.data[i].shadow_z_range.y;
+ float z = trans_coord.z * directional_lights.data[i].shadow_z_range.y;
transmittance_z = z - shadow_z;
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
@@ -1582,8 +1501,8 @@ void main() {
trans_coord /= trans_coord.w;
float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r;
- shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.z;
- float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.z;
+ shadow_z *= directional_lights.data[i].shadow_z_range.z;
+ float z = trans_coord.z * directional_lights.data[i].shadow_z_range.z;
transmittance_z = z - shadow_z;
@@ -1593,221 +1512,208 @@ void main() {
trans_coord /= trans_coord.w;
float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r;
- shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.w;
- float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.w;
+ shadow_z *= directional_lights.data[i].shadow_z_range.w;
+ float z = trans_coord.z * directional_lights.data[i].shadow_z_range.w;
transmittance_z = z - shadow_z;
}
+ }
#endif
- float shadow = 1.0;
+ float shadow = 1.0;
+#ifndef SHADOWS_DISABLED
+ if (i < 4) {
+ shadow = float(shadow0 >> (i * 8) & 0xFF) / 255.0;
+ } else {
+ shadow = float(shadow1 >> ((i - 4) * 8) & 0xFF) / 255.0;
+ }
+#endif
- if (i < 4) {
- shadow = float(shadow0 >> (i * 8) & 0xFF) / 255.0;
- } else {
- shadow = float(shadow1 >> ((i - 4) * 8) & 0xFF) / 255.0;
- }
+ blur_shadow(shadow);
- blur_shadow(shadow);
+ float size_A = sc_use_light_soft_shadows ? directional_lights.data[i].size : 0.0;
- light_compute(normal, directional_lights.data[i].direction, normalize(view), directional_lights.data[i].color * directional_lights.data[i].energy, shadow, f0, orms, 1.0,
+ light_compute(normal, directional_lights.data[i].direction, normalize(view), size_A, directional_lights.data[i].color * directional_lights.data[i].energy, shadow, f0, orms, 1.0, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
- backlight,
+ backlight,
#endif
#ifdef LIGHT_TRANSMITTANCE_USED
- transmittance_color,
- transmittance_depth,
- transmittance_curve,
- transmittance_boost,
- transmittance_z,
+ transmittance_color,
+ transmittance_depth,
+ transmittance_boost,
+ transmittance_z,
#endif
#ifdef LIGHT_RIM_USED
- rim, rim_tint, albedo,
+ rim, rim_tint,
#endif
#ifdef LIGHT_CLEARCOAT_USED
- clearcoat, clearcoat_gloss,
+ clearcoat, clearcoat_gloss,
#endif
#ifdef LIGHT_ANISOTROPY_USED
- binormal, tangent, anisotropy,
+ binormal, tangent, anisotropy,
#endif
-#ifdef USE_SOFT_SHADOW
- directional_lights.data[i].size,
-#endif
-#ifdef USE_SHADOW_TO_OPACITY
- alpha,
-#endif
- diffuse_light,
- specular_light);
- }
+ diffuse_light,
+ specular_light);
}
+ }
- { //omni lights
+ { //omni lights
- uint cluster_omni_offset = cluster_offset;
+ uint cluster_omni_offset = cluster_offset;
- uint item_min;
- uint item_max;
- uint item_from;
- uint item_to;
+ uint item_min;
+ uint item_max;
+ uint item_from;
+ uint item_to;
- cluster_get_item_range(cluster_omni_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
+ cluster_get_item_range(cluster_omni_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
#ifdef USE_SUBGROUPS
- item_from = subgroupBroadcastFirst(subgroupMin(item_from));
- item_to = subgroupBroadcastFirst(subgroupMax(item_to));
+ item_from = subgroupBroadcastFirst(subgroupMin(item_from));
+ item_to = subgroupBroadcastFirst(subgroupMax(item_to));
#endif
- for (uint i = item_from; i < item_to; i++) {
- uint mask = cluster_buffer.data[cluster_omni_offset + i];
- mask &= cluster_get_range_clip_mask(i, item_min, item_max);
+ for (uint i = item_from; i < item_to; i++) {
+ uint mask = cluster_buffer.data[cluster_omni_offset + i];
+ mask &= cluster_get_range_clip_mask(i, item_min, item_max);
#ifdef USE_SUBGROUPS
- uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask));
+ uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask));
#else
uint merged_mask = mask;
#endif
- while (merged_mask != 0) {
- uint bit = findMSB(merged_mask);
- merged_mask &= ~(1 << bit);
+ while (merged_mask != 0) {
+ uint bit = findMSB(merged_mask);
+ merged_mask &= ~(1 << bit);
#ifdef USE_SUBGROUPS
- if (((1 << bit) & mask) == 0) { //do not process if not originally here
- continue;
- }
+ if (((1 << bit) & mask) == 0) { //do not process if not originally here
+ continue;
+ }
#endif
- uint light_index = 32 * i + bit;
+ uint light_index = 32 * i + bit;
- if (!bool(omni_lights.data[light_index].mask & instances.data[instance_index].layer_mask)) {
- continue; //not masked
- }
+ if (!bool(omni_lights.data[light_index].mask & instances.data[instance_index].layer_mask)) {
+ continue; //not masked
+ }
- if (omni_lights.data[light_index].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) {
- continue; // Statically baked light and object uses lightmap, skip
- }
+ if (omni_lights.data[light_index].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) {
+ continue; // Statically baked light and object uses lightmap, skip
+ }
- float shadow = light_process_omni_shadow(light_index, vertex, view);
+ float shadow = light_process_omni_shadow(light_index, vertex, normal);
- shadow = blur_shadow(shadow);
+ shadow = blur_shadow(shadow);
- light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow,
+ light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
- backlight,
+ backlight,
#endif
#ifdef LIGHT_TRANSMITTANCE_USED
- transmittance_color,
- transmittance_depth,
- transmittance_curve,
- transmittance_boost,
+ transmittance_color,
+ transmittance_depth,
+ transmittance_boost,
#endif
#ifdef LIGHT_RIM_USED
- rim,
- rim_tint,
- albedo,
+ rim,
+ rim_tint,
#endif
#ifdef LIGHT_CLEARCOAT_USED
- clearcoat, clearcoat_gloss,
+ clearcoat, clearcoat_gloss,
#endif
#ifdef LIGHT_ANISOTROPY_USED
- tangent, binormal, anisotropy,
+ tangent, binormal, anisotropy,
#endif
-#ifdef USE_SHADOW_TO_OPACITY
- alpha,
-#endif
- diffuse_light, specular_light);
- }
+ diffuse_light, specular_light);
}
}
+ }
- { //spot lights
+ { //spot lights
- uint cluster_spot_offset = cluster_offset + scene_data.cluster_type_size;
+ uint cluster_spot_offset = cluster_offset + scene_data.cluster_type_size;
- uint item_min;
- uint item_max;
- uint item_from;
- uint item_to;
+ uint item_min;
+ uint item_max;
+ uint item_from;
+ uint item_to;
- cluster_get_item_range(cluster_spot_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
+ cluster_get_item_range(cluster_spot_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
#ifdef USE_SUBGROUPS
- item_from = subgroupBroadcastFirst(subgroupMin(item_from));
- item_to = subgroupBroadcastFirst(subgroupMax(item_to));
+ item_from = subgroupBroadcastFirst(subgroupMin(item_from));
+ item_to = subgroupBroadcastFirst(subgroupMax(item_to));
#endif
- for (uint i = item_from; i < item_to; i++) {
- uint mask = cluster_buffer.data[cluster_spot_offset + i];
- mask &= cluster_get_range_clip_mask(i, item_min, item_max);
+ for (uint i = item_from; i < item_to; i++) {
+ uint mask = cluster_buffer.data[cluster_spot_offset + i];
+ mask &= cluster_get_range_clip_mask(i, item_min, item_max);
#ifdef USE_SUBGROUPS
- uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask));
+ uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask));
#else
uint merged_mask = mask;
#endif
- while (merged_mask != 0) {
- uint bit = findMSB(merged_mask);
- merged_mask &= ~(1 << bit);
+ while (merged_mask != 0) {
+ uint bit = findMSB(merged_mask);
+ merged_mask &= ~(1 << bit);
#ifdef USE_SUBGROUPS
- if (((1 << bit) & mask) == 0) { //do not process if not originally here
- continue;
- }
+ if (((1 << bit) & mask) == 0) { //do not process if not originally here
+ continue;
+ }
#endif
- uint light_index = 32 * i + bit;
+ uint light_index = 32 * i + bit;
- if (!bool(spot_lights.data[light_index].mask & instances.data[instance_index].layer_mask)) {
- continue; //not masked
- }
+ if (!bool(spot_lights.data[light_index].mask & instances.data[instance_index].layer_mask)) {
+ continue; //not masked
+ }
- if (spot_lights.data[light_index].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) {
- continue; // Statically baked light and object uses lightmap, skip
- }
+ if (spot_lights.data[light_index].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) {
+ continue; // Statically baked light and object uses lightmap, skip
+ }
- float shadow = light_process_spot_shadow(light_index, vertex, view);
+ float shadow = light_process_spot_shadow(light_index, vertex, normal);
- shadow = blur_shadow(shadow);
+ shadow = blur_shadow(shadow);
- light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow,
+ light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
- backlight,
+ backlight,
#endif
#ifdef LIGHT_TRANSMITTANCE_USED
- transmittance_color,
- transmittance_depth,
- transmittance_curve,
- transmittance_boost,
+ transmittance_color,
+ transmittance_depth,
+ transmittance_boost,
#endif
#ifdef LIGHT_RIM_USED
- rim,
- rim_tint,
- albedo,
+ rim,
+ rim_tint,
#endif
#ifdef LIGHT_CLEARCOAT_USED
- clearcoat, clearcoat_gloss,
+ clearcoat, clearcoat_gloss,
#endif
#ifdef LIGHT_ANISOTROPY_USED
- tangent, binormal, anisotropy,
+ tangent, binormal, anisotropy,
#endif
-#ifdef USE_SHADOW_TO_OPACITY
- alpha,
-#endif
- diffuse_light, specular_light);
- }
+ diffuse_light, specular_light);
}
}
+ }
#ifdef USE_SHADOW_TO_OPACITY
- alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0));
+ alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0));
#if defined(ALPHA_SCISSOR_USED)
- if (alpha < alpha_scissor) {
- discard;
- }
+ if (alpha < alpha_scissor) {
+ discard;
+ }
#endif // ALPHA_SCISSOR_USED
#ifdef USE_OPAQUE_PREPASS
- if (alpha < opaque_prepass_threshold) {
- discard;
- }
+ if (alpha < scene_data.opaque_prepass_threshold) {
+ discard;
+ }
#endif // USE_OPAQUE_PREPASS
@@ -1819,126 +1725,130 @@ void main() {
#ifdef MODE_RENDER_SDF
- {
- vec3 local_pos = (scene_data.sdf_to_bounds * vec4(vertex, 1.0)).xyz;
- ivec3 grid_pos = scene_data.sdf_offset + ivec3(local_pos * vec3(scene_data.sdf_size));
-
- uint albedo16 = 0x1; //solid flag
- albedo16 |= clamp(uint(albedo.r * 31.0), 0, 31) << 11;
- albedo16 |= clamp(uint(albedo.g * 31.0), 0, 31) << 6;
- albedo16 |= clamp(uint(albedo.b * 31.0), 0, 31) << 1;
-
- imageStore(albedo_volume_grid, grid_pos, uvec4(albedo16));
-
- uint facing_bits = 0;
- const vec3 aniso_dir[6] = vec3[](
- vec3(1, 0, 0),
- vec3(0, 1, 0),
- vec3(0, 0, 1),
- vec3(-1, 0, 0),
- vec3(0, -1, 0),
- vec3(0, 0, -1));
-
- vec3 cam_normal = mat3(scene_data.camera_matrix) * normalize(normal_interp);
-
- float closest_dist = -1e20;
-
- for (uint i = 0; i < 6; i++) {
- float d = dot(cam_normal, aniso_dir[i]);
- if (d > closest_dist) {
- closest_dist = d;
- facing_bits = (1 << i);
- }
+ {
+ vec3 local_pos = (scene_data.sdf_to_bounds * vec4(vertex, 1.0)).xyz;
+ ivec3 grid_pos = scene_data.sdf_offset + ivec3(local_pos * vec3(scene_data.sdf_size));
+
+ uint albedo16 = 0x1; //solid flag
+ albedo16 |= clamp(uint(albedo.r * 31.0), 0, 31) << 11;
+ albedo16 |= clamp(uint(albedo.g * 31.0), 0, 31) << 6;
+ albedo16 |= clamp(uint(albedo.b * 31.0), 0, 31) << 1;
+
+ imageStore(albedo_volume_grid, grid_pos, uvec4(albedo16));
+
+ uint facing_bits = 0;
+ const vec3 aniso_dir[6] = vec3[](
+ vec3(1, 0, 0),
+ vec3(0, 1, 0),
+ vec3(0, 0, 1),
+ vec3(-1, 0, 0),
+ vec3(0, -1, 0),
+ vec3(0, 0, -1));
+
+ vec3 cam_normal = mat3(scene_data.camera_matrix) * normalize(normal_interp);
+
+ float closest_dist = -1e20;
+
+ for (uint i = 0; i < 6; i++) {
+ float d = dot(cam_normal, aniso_dir[i]);
+ if (d > closest_dist) {
+ closest_dist = d;
+ facing_bits = (1 << i);
}
+ }
- imageAtomicOr(geom_facing_grid, grid_pos, facing_bits); //store facing bits
+#ifdef MOLTENVK_USED
+ imageStore(geom_facing_grid, grid_pos, uvec4(imageLoad(geom_facing_grid, grid_pos).r | facing_bits)); //store facing bits
+#else
+ imageAtomicOr(geom_facing_grid, grid_pos, facing_bits); //store facing bits
+#endif
- if (length(emission) > 0.001) {
- float lumas[6];
- vec3 light_total = vec3(0);
+ if (length(emission) > 0.001) {
+ float lumas[6];
+ vec3 light_total = vec3(0);
- for (int i = 0; i < 6; i++) {
- float strength = max(0.0, dot(cam_normal, aniso_dir[i]));
- vec3 light = emission * strength;
- light_total += light;
- lumas[i] = max(light.r, max(light.g, light.b));
- }
+ for (int i = 0; i < 6; i++) {
+ float strength = max(0.0, dot(cam_normal, aniso_dir[i]));
+ vec3 light = emission * strength;
+ light_total += light;
+ lumas[i] = max(light.r, max(light.g, light.b));
+ }
- float luma_total = max(light_total.r, max(light_total.g, light_total.b));
+ float luma_total = max(light_total.r, max(light_total.g, light_total.b));
- uint light_aniso = 0;
+ uint light_aniso = 0;
- for (int i = 0; i < 6; i++) {
- light_aniso |= min(31, uint((lumas[i] / luma_total) * 31.0)) << (i * 5);
- }
+ for (int i = 0; i < 6; i++) {
+ light_aniso |= min(31, uint((lumas[i] / luma_total) * 31.0)) << (i * 5);
+ }
- //compress to RGBE9995 to save space
+ //compress to RGBE9995 to save space
- const float pow2to9 = 512.0f;
- const float B = 15.0f;
- const float N = 9.0f;
- const float LN2 = 0.6931471805599453094172321215;
+ const float pow2to9 = 512.0f;
+ const float B = 15.0f;
+ const float N = 9.0f;
+ const float LN2 = 0.6931471805599453094172321215;
- float cRed = clamp(light_total.r, 0.0, 65408.0);
- float cGreen = clamp(light_total.g, 0.0, 65408.0);
- float cBlue = clamp(light_total.b, 0.0, 65408.0);
+ float cRed = clamp(light_total.r, 0.0, 65408.0);
+ float cGreen = clamp(light_total.g, 0.0, 65408.0);
+ float cBlue = clamp(light_total.b, 0.0, 65408.0);
- float cMax = max(cRed, max(cGreen, cBlue));
+ float cMax = max(cRed, max(cGreen, cBlue));
- float expp = max(-B - 1.0f, floor(log(cMax) / LN2)) + 1.0f + B;
+ float expp = max(-B - 1.0f, floor(log(cMax) / LN2)) + 1.0f + B;
- float sMax = floor((cMax / pow(2.0f, expp - B - N)) + 0.5f);
+ float sMax = floor((cMax / pow(2.0f, expp - B - N)) + 0.5f);
- float exps = expp + 1.0f;
+ float exps = expp + 1.0f;
- if (0.0 <= sMax && sMax < pow2to9) {
- exps = expp;
- }
+ if (0.0 <= sMax && sMax < pow2to9) {
+ exps = expp;
+ }
- float sRed = floor((cRed / pow(2.0f, exps - B - N)) + 0.5f);
- float sGreen = floor((cGreen / pow(2.0f, exps - B - N)) + 0.5f);
- float sBlue = floor((cBlue / pow(2.0f, exps - B - N)) + 0.5f);
- //store as 8985 to have 2 extra neighbour bits
- uint light_rgbe = ((uint(sRed) & 0x1FF) >> 1) | ((uint(sGreen) & 0x1FF) << 8) | (((uint(sBlue) & 0x1FF) >> 1) << 17) | ((uint(exps) & 0x1F) << 25);
+ float sRed = floor((cRed / pow(2.0f, exps - B - N)) + 0.5f);
+ float sGreen = floor((cGreen / pow(2.0f, exps - B - N)) + 0.5f);
+ float sBlue = floor((cBlue / pow(2.0f, exps - B - N)) + 0.5f);
+ //store as 8985 to have 2 extra neighbour bits
+ uint light_rgbe = ((uint(sRed) & 0x1FF) >> 1) | ((uint(sGreen) & 0x1FF) << 8) | (((uint(sBlue) & 0x1FF) >> 1) << 17) | ((uint(exps) & 0x1F) << 25);
- imageStore(emission_grid, grid_pos, uvec4(light_rgbe));
- imageStore(emission_aniso_grid, grid_pos, uvec4(light_aniso));
- }
+ imageStore(emission_grid, grid_pos, uvec4(light_rgbe));
+ imageStore(emission_aniso_grid, grid_pos, uvec4(light_aniso));
}
+ }
#endif
#ifdef MODE_RENDER_MATERIAL
- albedo_output_buffer.rgb = albedo;
- albedo_output_buffer.a = alpha;
+ albedo_output_buffer.rgb = albedo;
+ albedo_output_buffer.a = alpha;
- normal_output_buffer.rgb = normal * 0.5 + 0.5;
- normal_output_buffer.a = 0.0;
- depth_output_buffer.r = -vertex.z;
+ normal_output_buffer.rgb = normal * 0.5 + 0.5;
+ normal_output_buffer.a = 0.0;
+ depth_output_buffer.r = -vertex.z;
- orm_output_buffer.r = ao;
- orm_output_buffer.g = roughness;
- orm_output_buffer.b = metallic;
- orm_output_buffer.a = sss_strength;
+ orm_output_buffer.r = ao;
+ orm_output_buffer.g = roughness;
+ orm_output_buffer.b = metallic;
+ orm_output_buffer.a = sss_strength;
- emission_output_buffer.rgb = emission;
- emission_output_buffer.a = 0.0;
+ emission_output_buffer.rgb = emission;
+ emission_output_buffer.a = 0.0;
#endif
#ifdef MODE_RENDER_NORMAL_ROUGHNESS
- normal_roughness_output_buffer = vec4(normal * 0.5 + 0.5, roughness);
-
-#ifdef MODE_RENDER_GIPROBE
- if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_GIPROBE)) { // process giprobes
- uint index1 = instances.data[instance_index].gi_offset & 0xFFFF;
- uint index2 = instances.data[instance_index].gi_offset >> 16;
- giprobe_buffer.x = index1 & 0xFF;
- giprobe_buffer.y = index2 & 0xFF;
- } else {
- giprobe_buffer.x = 0xFF;
- giprobe_buffer.y = 0xFF;
- }
+ normal_roughness_output_buffer = vec4(normal * 0.5 + 0.5, roughness);
+
+#ifdef MODE_RENDER_VOXEL_GI
+ if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_VOXEL_GI)) { // process voxel_gi_instances
+ uint index1 = instances.data[instance_index].gi_offset & 0xFFFF;
+ uint index2 = instances.data[instance_index].gi_offset >> 16;
+ voxel_gi_buffer.x = index1 & 0xFF;
+ voxel_gi_buffer.y = index2 & 0xFF;
+ } else {
+ voxel_gi_buffer.x = 0xFF;
+ voxel_gi_buffer.y = 0xFF;
+ }
#endif
#endif //MODE_RENDER_NORMAL_ROUGHNESS
@@ -1991,9 +1901,8 @@ void main() {
// Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky.
frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a);
- ;
#endif //MODE_MULTIPLE_RENDER_TARGETS
#endif //MODE_RENDER_DEPTH
- }
+}
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl
index ca75d6300e..be29cf4f58 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl
@@ -1,7 +1,7 @@
#define M_PI 3.14159265359
#define ROUGHNESS_MAX_LOD 5
-#define MAX_GI_PROBES 8
+#define MAX_VOXEL_GI_INSTANCES 8
#if defined(has_GL_KHR_shader_subgroup_ballot) && defined(has_GL_KHR_shader_subgroup_arithmetic)
@@ -15,7 +15,7 @@
#include "cluster_data_inc.glsl"
#include "decal_data_inc.glsl"
-#if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(MODE_RENDER_SDF) || defined(MODE_RENDER_NORMAL_ROUGHNESS) || defined(MODE_RENDER_GIPROBE) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED)
+#if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(MODE_RENDER_SDF) || defined(MODE_RENDER_NORMAL_ROUGHNESS) || defined(MODE_RENDER_VOXEL_GI) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED)
#ifndef NORMAL_USED
#define NORMAL_USED
#endif
@@ -52,38 +52,42 @@ layout(set = 0, binding = 1) uniform sampler material_samplers[12];
layout(set = 0, binding = 2) uniform sampler shadow_sampler;
+layout(set = 0, binding = 3) uniform sampler decal_sampler;
+
+layout(set = 0, binding = 4) uniform sampler light_projector_sampler;
+
+#define INSTANCE_FLAGS_NON_UNIFORM_SCALE (1 << 5)
#define INSTANCE_FLAGS_USE_GI_BUFFERS (1 << 6)
#define INSTANCE_FLAGS_USE_SDFGI (1 << 7)
#define INSTANCE_FLAGS_USE_LIGHTMAP_CAPTURE (1 << 8)
#define INSTANCE_FLAGS_USE_LIGHTMAP (1 << 9)
#define INSTANCE_FLAGS_USE_SH_LIGHTMAP (1 << 10)
-#define INSTANCE_FLAGS_USE_GIPROBE (1 << 11)
+#define INSTANCE_FLAGS_USE_VOXEL_GI (1 << 11)
#define INSTANCE_FLAGS_MULTIMESH (1 << 12)
#define INSTANCE_FLAGS_MULTIMESH_FORMAT_2D (1 << 13)
#define INSTANCE_FLAGS_MULTIMESH_HAS_COLOR (1 << 14)
#define INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA (1 << 15)
#define INSTANCE_FLAGS_PARTICLE_TRAIL_SHIFT 16
+#define INSTANCE_FLAGS_FADE_SHIFT 24
//3 bits of stride
#define INSTANCE_FLAGS_PARTICLE_TRAIL_MASK 0xFF
-#define INSTANCE_FLAGS_NON_UNIFORM_SCALE (1 << 24)
-
-layout(set = 0, binding = 3, std430) restrict readonly buffer OmniLights {
+layout(set = 0, binding = 5, std430) restrict readonly buffer OmniLights {
LightData data[];
}
omni_lights;
-layout(set = 0, binding = 4, std430) restrict readonly buffer SpotLights {
+layout(set = 0, binding = 6, std430) restrict readonly buffer SpotLights {
LightData data[];
}
spot_lights;
-layout(set = 0, binding = 5, std430) restrict readonly buffer ReflectionProbeData {
+layout(set = 0, binding = 7, std430) restrict readonly buffer ReflectionProbeData {
ReflectionData data[];
}
reflections;
-layout(set = 0, binding = 6, std140) uniform DirectionalLights {
+layout(set = 0, binding = 8, std140) uniform DirectionalLights {
DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
}
directional_lights;
@@ -95,7 +99,7 @@ struct Lightmap {
mat3 normal_xform;
};
-layout(set = 0, binding = 7, std140) restrict readonly buffer Lightmaps {
+layout(set = 0, binding = 9, std140) restrict readonly buffer Lightmaps {
Lightmap data[];
}
lightmaps;
@@ -104,32 +108,32 @@ struct LightmapCapture {
vec4 sh[9];
};
-layout(set = 0, binding = 8, std140) restrict readonly buffer LightmapCaptures {
+layout(set = 0, binding = 10, std140) restrict readonly buffer LightmapCaptures {
LightmapCapture data[];
}
lightmap_captures;
-layout(set = 0, binding = 9) uniform texture2D decal_atlas;
-layout(set = 0, binding = 10) uniform texture2D decal_atlas_srgb;
+layout(set = 0, binding = 11) uniform texture2D decal_atlas;
+layout(set = 0, binding = 12) uniform texture2D decal_atlas_srgb;
-layout(set = 0, binding = 11, std430) restrict readonly buffer Decals {
+layout(set = 0, binding = 13, std430) restrict readonly buffer Decals {
DecalData data[];
}
decals;
-layout(set = 0, binding = 12, std430) restrict readonly buffer GlobalVariableData {
+layout(set = 0, binding = 14, std430) restrict readonly buffer GlobalVariableData {
vec4 data[];
}
global_variables;
-struct SDFGIProbeCascadeData {
+struct SDFVoxelGICascadeData {
vec3 position;
float to_probe;
ivec3 probe_world_offset;
float to_cell; // 1/bounds * grid_size
};
-layout(set = 0, binding = 13, std140) uniform SDFGI {
+layout(set = 0, binding = 15, std140) uniform SDFGI {
vec3 grid_size;
uint max_cascades;
@@ -153,7 +157,7 @@ layout(set = 0, binding = 13, std140) uniform SDFGI {
vec3 cascade_probe_size;
uint pad5;
- SDFGIProbeCascadeData cascades[SDFGI_MAX_CASCADES];
+ SDFVoxelGICascadeData cascades[SDFGI_MAX_CASCADES];
}
sdfgi;
@@ -174,17 +178,12 @@ layout(set = 1, binding = 0, std140) uniform SceneData {
uint cluster_type_size;
uint max_cluster_element_count_div_32;
- //use vec4s because std140 doesnt play nice with vec2s, z and w are wasted
+ // Use vec4s because std140 doesn't play nice with vec2s, z and w are wasted.
vec4 directional_penumbra_shadow_kernel[32];
vec4 directional_soft_shadow_kernel[32];
vec4 penumbra_shadow_kernel[32];
vec4 soft_shadow_kernel[32];
- uint directional_penumbra_shadow_samples;
- uint directional_soft_shadow_samples;
- uint penumbra_shadow_samples;
- uint soft_shadow_samples;
-
vec4 ambient_light_color_energy;
float ambient_color_sky_mix;
@@ -209,9 +208,8 @@ layout(set = 1, binding = 0, std140) uniform SceneData {
float roughness_limiter_amount;
float roughness_limiter_limit;
- uvec2 roughness_limiter_pad;
-
- vec4 ao_color;
+ float opaque_prepass_threshold;
+ uint roughness_limiter_pad;
mat4 sdf_to_bounds;
@@ -275,7 +273,7 @@ layout(set = 1, binding = 5) uniform texture2D directional_shadow_atlas;
layout(set = 1, binding = 6) uniform texture2DArray lightmap_textures[MAX_LIGHTMAP_TEXTURES];
-layout(set = 1, binding = 7) uniform texture3D gi_probe_textures[MAX_GI_PROBES];
+layout(set = 1, binding = 7) uniform texture3D voxel_gi_textures[MAX_VOXEL_GI_INSTANCES];
layout(set = 1, binding = 8, std430) buffer restrict readonly ClusterBuffer {
uint data[];
@@ -306,7 +304,7 @@ layout(set = 1, binding = 14) uniform texture2D reflection_buffer;
layout(set = 1, binding = 15) uniform texture2DArray sdfgi_lightprobe_texture;
layout(set = 1, binding = 16) uniform texture3D sdfgi_occlusion_cascades;
-struct GIProbeData {
+struct VoxelGIData {
mat4 xform;
vec3 bounds;
float dynamic_range;
@@ -322,10 +320,10 @@ struct GIProbeData {
uint mipmaps;
};
-layout(set = 1, binding = 17, std140) uniform GIProbes {
- GIProbeData data[MAX_GI_PROBES];
+layout(set = 1, binding = 17, std140) uniform VoxelGIs {
+ VoxelGIData data[MAX_VOXEL_GI_INSTANCES];
}
-gi_probes;
+voxel_gi_instances;
layout(set = 1, binding = 18) uniform texture3D volumetric_fog_texture;
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl
index b41f16cbe7..c88bd0a14b 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl
@@ -48,24 +48,24 @@ vec4 voxel_cone_trace_45_degrees(texture3D probe, vec3 cell_size, vec3 pos, vec3
return color;
}
-void gi_probe_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3 normal_xform, float roughness, vec3 ambient, vec3 environment, inout vec4 out_spec, inout vec4 out_diff) {
- position = (gi_probes.data[index].xform * vec4(position, 1.0)).xyz;
- ref_vec = normalize((gi_probes.data[index].xform * vec4(ref_vec, 0.0)).xyz);
- normal = normalize((gi_probes.data[index].xform * vec4(normal, 0.0)).xyz);
+void voxel_gi_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3 normal_xform, float roughness, vec3 ambient, vec3 environment, inout vec4 out_spec, inout vec4 out_diff) {
+ position = (voxel_gi_instances.data[index].xform * vec4(position, 1.0)).xyz;
+ ref_vec = normalize((voxel_gi_instances.data[index].xform * vec4(ref_vec, 0.0)).xyz);
+ normal = normalize((voxel_gi_instances.data[index].xform * vec4(normal, 0.0)).xyz);
- position += normal * gi_probes.data[index].normal_bias;
+ position += normal * voxel_gi_instances.data[index].normal_bias;
//this causes corrupted pixels, i have no idea why..
- if (any(bvec2(any(lessThan(position, vec3(0.0))), any(greaterThan(position, gi_probes.data[index].bounds))))) {
+ if (any(bvec2(any(lessThan(position, vec3(0.0))), any(greaterThan(position, voxel_gi_instances.data[index].bounds))))) {
return;
}
- vec3 blendv = abs(position / gi_probes.data[index].bounds * 2.0 - 1.0);
+ vec3 blendv = abs(position / voxel_gi_instances.data[index].bounds * 2.0 - 1.0);
float blend = clamp(1.0 - max(blendv.x, max(blendv.y, blendv.z)), 0.0, 1.0);
//float blend=1.0;
- float max_distance = length(gi_probes.data[index].bounds);
- vec3 cell_size = 1.0 / gi_probes.data[index].bounds;
+ float max_distance = length(voxel_gi_instances.data[index].bounds);
+ vec3 cell_size = 1.0 / voxel_gi_instances.data[index].bounds;
//radiance
@@ -83,26 +83,26 @@ void gi_probe_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3
vec3 light = vec3(0.0);
for (int i = 0; i < MAX_CONE_DIRS; i++) {
- vec3 dir = normalize((gi_probes.data[index].xform * vec4(normal_xform * cone_dirs[i], 0.0)).xyz);
+ vec3 dir = normalize((voxel_gi_instances.data[index].xform * vec4(normal_xform * cone_dirs[i], 0.0)).xyz);
- vec4 cone_light = voxel_cone_trace_45_degrees(gi_probe_textures[index], cell_size, position, dir, cone_angle_tan, max_distance, gi_probes.data[index].bias);
+ vec4 cone_light = voxel_cone_trace_45_degrees(voxel_gi_textures[index], cell_size, position, dir, cone_angle_tan, max_distance, voxel_gi_instances.data[index].bias);
- if (gi_probes.data[index].blend_ambient) {
+ if (voxel_gi_instances.data[index].blend_ambient) {
cone_light.rgb = mix(ambient, cone_light.rgb, min(1.0, cone_light.a / 0.95));
}
light += cone_weights[i] * cone_light.rgb;
}
- light *= gi_probes.data[index].dynamic_range;
+ light *= voxel_gi_instances.data[index].dynamic_range;
out_diff += vec4(light * blend, blend);
//irradiance
- vec4 irr_light = voxel_cone_trace(gi_probe_textures[index], cell_size, position, ref_vec, tan(roughness * 0.5 * M_PI * 0.99), max_distance, gi_probes.data[index].bias);
- if (gi_probes.data[index].blend_ambient) {
+ vec4 irr_light = voxel_cone_trace(voxel_gi_textures[index], cell_size, position, ref_vec, tan(roughness * 0.5 * M_PI * 0.99), max_distance, voxel_gi_instances.data[index].bias);
+ if (voxel_gi_instances.data[index].blend_ambient) {
irr_light.rgb = mix(environment, irr_light.rgb, min(1.0, irr_light.a / 0.95));
}
- irr_light.rgb *= gi_probes.data[index].dynamic_range;
+ irr_light.rgb *= voxel_gi_instances.data[index].dynamic_range;
//irr_light=vec3(0.0);
out_spec += vec4(irr_light.rgb * blend, blend);
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
index 32a86cb166..d22f936a35 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
@@ -73,19 +73,18 @@ vec3 F0(float metallic, float specular, vec3 albedo) {
return mix(vec3(dielectric), albedo, vec3(metallic));
}
-void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation, vec3 f0, uint orms, float specular_amount,
+void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float attenuation, vec3 f0, uint orms, float specular_amount, vec3 albedo, inout float alpha,
#ifdef LIGHT_BACKLIGHT_USED
vec3 backlight,
#endif
#ifdef LIGHT_TRANSMITTANCE_USED
vec4 transmittance_color,
float transmittance_depth,
- float transmittance_curve,
float transmittance_boost,
float transmittance_z,
#endif
#ifdef LIGHT_RIM_USED
- float rim, float rim_tint, vec3 rim_color,
+ float rim, float rim_tint,
#endif
#ifdef LIGHT_CLEARCOAT_USED
float clearcoat, float clearcoat_gloss,
@@ -93,14 +92,13 @@ void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation,
#ifdef LIGHT_ANISOTROPY_USED
vec3 B, vec3 T, float anisotropy,
#endif
-#ifdef USE_SOFT_SHADOWS
- float A,
-#endif
-#ifdef USE_SHADOW_TO_OPACITY
- inout float alpha,
-#endif
inout vec3 diffuse_light, inout vec3 specular_light) {
+ vec4 orms_unpacked = unpackUnorm4x8(orms);
+
+ float roughness = orms_unpacked.y;
+ float metallic = orms_unpacked.z;
+
#if defined(LIGHT_CODE_USED)
// light is written by the light shader
@@ -112,11 +110,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation,
#else
-#ifdef USE_SOFT_SHADOWS
float NdotL = min(A + dot(N, L), 1.0);
-#else
- float NdotL = dot(N, L);
-#endif
float cNdotL = max(NdotL, 0.0); // clamped NdotL
float NdotV = dot(N, V);
float cNdotV = max(NdotV, 0.0);
@@ -126,30 +120,15 @@ void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation,
#endif
#if defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED)
-#ifdef USE_SOFT_SHADOWS
float cNdotH = clamp(A + dot(N, H), 0.0, 1.0);
-#else
- float cNdotH = clamp(dot(N, H), 0.0, 1.0);
-#endif
#endif
#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED)
-#ifdef USE_SOFT_SHADOWS
float cLdotH = clamp(A + dot(L, H), 0.0, 1.0);
-#else
- float cLdotH = clamp(dot(L, H), 0.0, 1.0);
-#endif
#endif
- float metallic = unpackUnorm4x8(orms).z;
if (metallic < 1.0) {
- float roughness = unpackUnorm4x8(orms).y;
-
-#if defined(DIFFUSE_OREN_NAYAR)
- vec3 diffuse_brdf_NL;
-#else
float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance
-#endif
#if defined(DIFFUSE_LAMBERT_WRAP)
// energy conserving lambert wrap shader
@@ -189,43 +168,37 @@ void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation,
#if defined(LIGHT_RIM_USED)
float rim_light = pow(max(0.0, 1.0 - cNdotV), max(0.0, (1.0 - roughness) * 16.0));
- diffuse_light += rim_light * rim * mix(vec3(1.0), rim_color, rim_tint) * light_color;
+ diffuse_light += rim_light * rim * mix(vec3(1.0), albedo, rim_tint) * light_color;
#endif
#ifdef LIGHT_TRANSMITTANCE_USED
-#ifdef SSS_MODE_SKIN
-
{
+#ifdef SSS_MODE_SKIN
float scale = 8.25 / transmittance_depth;
float d = scale * abs(transmittance_z);
float dd = -d * d;
vec3 profile = vec3(0.233, 0.455, 0.649) * exp(dd / 0.0064) +
- vec3(0.1, 0.336, 0.344) * exp(dd / 0.0484) +
- vec3(0.118, 0.198, 0.0) * exp(dd / 0.187) +
- vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) +
- vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) +
- vec3(0.078, 0.0, 0.0) * exp(dd / 7.41);
+ vec3(0.1, 0.336, 0.344) * exp(dd / 0.0484) +
+ vec3(0.118, 0.198, 0.0) * exp(dd / 0.187) +
+ vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) +
+ vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) +
+ vec3(0.078, 0.0, 0.0) * exp(dd / 7.41);
diffuse_light += profile * transmittance_color.a * light_color * clamp(transmittance_boost - NdotL, 0.0, 1.0) * (1.0 / M_PI);
- }
#else
- if (transmittance_depth > 0.0) {
- float fade = clamp(abs(transmittance_z / transmittance_depth), 0.0, 1.0);
-
- fade = pow(max(0.0, 1.0 - fade), transmittance_curve);
- fade *= clamp(transmittance_boost - NdotL, 0.0, 1.0);
-
- diffuse_light += transmittance_color.rgb * light_color * (1.0 / M_PI) * transmittance_color.a * fade;
+ float scale = 8.25 / transmittance_depth;
+ float d = scale * abs(transmittance_z);
+ float dd = -d * d;
+ diffuse_light += exp(dd) * transmittance_color.rgb * transmittance_color.a * light_color * clamp(transmittance_boost - NdotL, 0.0, 1.0) * (1.0 / M_PI);
+#endif
}
-
-#endif //SSS_MODE_SKIN
+#else
#endif //LIGHT_TRANSMITTANCE_USED
}
- float roughness = unpackUnorm4x8(orms).y;
if (roughness > 0.0) { // FIXME: roughness == 0 should not disable specular light entirely
// D
@@ -234,11 +207,10 @@ void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation,
//normalized blinn
float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25;
- float blinn = pow(cNdotH, shininess) * cNdotL;
- blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI));
- float intensity = blinn;
+ float blinn = pow(cNdotH, shininess);
+ blinn *= (shininess + 2.0) * (1.0 / (8.0 * M_PI));
- specular_light += light_color * intensity * attenuation * specular_amount;
+ specular_light += light_color * attenuation * specular_amount * blinn * f0 * orms_unpacked.w;
#elif defined(SPECULAR_PHONG)
@@ -246,10 +218,9 @@ void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation,
float cRdotV = clamp(A + dot(R, V), 0.0, 1.0);
float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25;
float phong = pow(cRdotV, shininess);
- phong *= (shininess + 8.0) * (1.0 / (8.0 * M_PI));
- float intensity = (phong) / max(4.0 * cNdotV * cNdotL, 0.75);
+ phong *= (shininess + 1.0) * (1.0 / (8.0 * M_PI));
- specular_light += light_color * intensity * attenuation * specular_amount;
+ specular_light += light_color * attenuation * specular_amount * phong * f0 * orms_unpacked.w;
#elif defined(SPECULAR_TOON)
@@ -307,16 +278,16 @@ void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation,
}
#ifdef USE_SHADOW_TO_OPACITY
- alpha = min(alpha, clamp(1.0 - attenuation), 0.0, 1.0));
+ alpha = min(alpha, clamp(1.0 - attenuation, 0.0, 1.0));
#endif
#endif //defined(LIGHT_CODE_USED)
}
-#ifndef USE_NO_SHADOWS
+#ifndef SHADOWS_DISABLED
// Interleaved Gradient Noise
-// http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare
+// https://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare
float quick_hash(vec2 pos) {
const vec3 magic = vec3(0.06711056f, 0.00583715f, 52.9829189f);
return fract(magic.z * fract(dot(pos, magic.xy)));
@@ -327,7 +298,7 @@ float sample_directional_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, ve
float depth = coord.z;
//if only one sample is taken, take it from the center
- if (scene_data.directional_soft_shadow_samples == 1) {
+ if (sc_directional_soft_shadow_samples == 0) {
return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0));
}
@@ -341,19 +312,19 @@ float sample_directional_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, ve
float avg = 0.0;
- for (uint i = 0; i < scene_data.directional_soft_shadow_samples; i++) {
+ for (uint i = 0; i < sc_directional_soft_shadow_samples; i++) {
avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + shadow_pixel_size * (disk_rotation * scene_data.directional_soft_shadow_kernel[i].xy), depth, 1.0));
}
- return avg * (1.0 / float(scene_data.directional_soft_shadow_samples));
+ return avg * (1.0 / float(sc_directional_soft_shadow_samples));
}
-float sample_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) {
+float sample_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec3 coord) {
vec2 pos = coord.xy;
float depth = coord.z;
//if only one sample is taken, take it from the center
- if (scene_data.soft_shadow_samples == 1) {
+ if (sc_soft_shadow_samples == 0) {
return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0));
}
@@ -367,11 +338,54 @@ float sample_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) {
float avg = 0.0;
- for (uint i = 0; i < scene_data.soft_shadow_samples; i++) {
+ for (uint i = 0; i < sc_soft_shadow_samples; i++) {
avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + shadow_pixel_size * (disk_rotation * scene_data.soft_shadow_kernel[i].xy), depth, 1.0));
}
- return avg * (1.0 / float(scene_data.soft_shadow_samples));
+ return avg * (1.0 / float(sc_soft_shadow_samples));
+}
+
+float sample_omni_pcf_shadow(texture2D shadow, float blur_scale, vec2 coord, vec4 uv_rect, vec2 flip_offset, float depth) {
+ //if only one sample is taken, take it from the center
+ if (sc_soft_shadow_samples == 0) {
+ vec2 pos = coord * 0.5 + 0.5;
+ pos = uv_rect.xy + pos * uv_rect.zw;
+ return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0));
+ }
+
+ mat2 disk_rotation;
+ {
+ float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI;
+ float sr = sin(r);
+ float cr = cos(r);
+ disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr));
+ }
+
+ float avg = 0.0;
+ vec2 offset_scale = blur_scale * 2.0 * scene_data.shadow_atlas_pixel_size / uv_rect.zw;
+
+ for (uint i = 0; i < sc_soft_shadow_samples; i++) {
+ vec2 offset = offset_scale * (disk_rotation * scene_data.soft_shadow_kernel[i].xy);
+ vec2 sample_coord = coord + offset;
+
+ float sample_coord_length_sqaured = dot(sample_coord, sample_coord);
+ bool do_flip = sample_coord_length_sqaured > 1.0;
+
+ if (do_flip) {
+ float len = sqrt(sample_coord_length_sqaured);
+ sample_coord = sample_coord * (2.0 / len - 1.0);
+ }
+
+ sample_coord = sample_coord * 0.5 + 0.5;
+ sample_coord = uv_rect.xy + sample_coord * uv_rect.zw;
+
+ if (do_flip) {
+ sample_coord += flip_offset;
+ }
+ avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(sample_coord, depth, 1.0));
+ }
+
+ return avg * (1.0 / float(sc_soft_shadow_samples));
}
float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex_scale) {
@@ -387,7 +401,7 @@ float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex
disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr));
}
- for (uint i = 0; i < scene_data.directional_penumbra_shadow_samples; i++) {
+ for (uint i = 0; i < sc_directional_penumbra_shadow_samples; i++) {
vec2 suv = pssm_coord.xy + (disk_rotation * scene_data.directional_penumbra_shadow_kernel[i].xy) * tex_scale;
float d = textureLod(sampler2D(shadow, material_samplers[SAMPLER_LINEAR_CLAMP]), suv, 0.0).r;
if (d < pssm_coord.z) {
@@ -403,12 +417,12 @@ float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex
tex_scale *= penumbra;
float s = 0.0;
- for (uint i = 0; i < scene_data.directional_penumbra_shadow_samples; i++) {
+ for (uint i = 0; i < sc_directional_penumbra_shadow_samples; i++) {
vec2 suv = pssm_coord.xy + (disk_rotation * scene_data.directional_penumbra_shadow_kernel[i].xy) * tex_scale;
s += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(suv, pssm_coord.z, 1.0));
}
- return s / float(scene_data.directional_penumbra_shadow_samples);
+ return s / float(sc_directional_penumbra_shadow_samples);
} else {
//no blockers found, so no shadow
@@ -416,7 +430,7 @@ float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex
}
}
-#endif //USE_NO_SHADOWS
+#endif // SHADOWS_DISABLED
float get_omni_attenuation(float distance, float inv_range, float decay) {
float nd = distance * inv_range;
@@ -428,29 +442,28 @@ float get_omni_attenuation(float distance, float inv_range, float decay) {
}
float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) {
-#ifndef USE_NO_SHADOWS
+#ifndef SHADOWS_DISABLED
if (omni_lights.data[idx].shadow_enabled) {
// there is a shadowmap
+ vec2 texel_size = scene_data.shadow_atlas_pixel_size;
+ vec4 base_uv_rect = omni_lights.data[idx].atlas_rect;
+ base_uv_rect.xy += texel_size;
+ base_uv_rect.zw -= texel_size * 2.0;
- vec3 light_rel_vec = omni_lights.data[idx].position - vertex;
- float light_length = length(light_rel_vec);
+ // Omni lights use direction.xy to store to store the offset between the two paraboloid regions
+ vec2 flip_offset = omni_lights.data[idx].direction.xy;
- vec4 v = vec4(vertex, 1.0);
+ vec3 local_vert = (omni_lights.data[idx].shadow_matrix * vec4(vertex, 1.0)).xyz;
- vec4 splane = (omni_lights.data[idx].shadow_matrix * v);
- float shadow_len = length(splane.xyz); //need to remember shadow len from here
+ float shadow_len = length(local_vert); //need to remember shadow len from here
+ vec3 shadow_dir = normalize(local_vert);
- {
- vec3 nofs = normal_interp * omni_lights.data[idx].shadow_normal_bias / omni_lights.data[idx].inv_radius;
- nofs *= (1.0 - max(0.0, dot(normalize(light_rel_vec), normalize(normal_interp))));
- v.xyz += nofs;
- splane = (omni_lights.data[idx].shadow_matrix * v);
- }
+ vec3 local_normal = normalize(mat3(omni_lights.data[idx].shadow_matrix) * normal);
+ vec3 normal_bias = local_normal * omni_lights.data[idx].shadow_normal_bias * (1.0 - abs(dot(local_normal, shadow_dir)));
float shadow;
-#ifdef USE_SOFT_SHADOWS
- if (omni_lights.data[idx].soft_shadow_size > 0.0) {
+ if (sc_use_light_soft_shadows && omni_lights.data[idx].soft_shadow_size > 0.0) {
//soft shadow
//find blocker
@@ -466,30 +479,29 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) {
disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr));
}
- vec3 normal = normalize(splane.xyz);
- vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);
- vec3 tangent = normalize(cross(v0, normal));
- vec3 bitangent = normalize(cross(tangent, normal));
+ vec3 basis_normal = shadow_dir;
+ vec3 v0 = abs(basis_normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);
+ vec3 tangent = normalize(cross(v0, basis_normal));
+ vec3 bitangent = normalize(cross(tangent, basis_normal));
float z_norm = shadow_len * omni_lights.data[idx].inv_radius;
tangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale;
bitangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale;
- for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) {
+ for (uint i = 0; i < sc_penumbra_shadow_samples; i++) {
vec2 disk = disk_rotation * scene_data.penumbra_shadow_kernel[i].xy;
- vec3 pos = splane.xyz + tangent * disk.x + bitangent * disk.y;
+ vec3 pos = local_vert + tangent * disk.x + bitangent * disk.y;
pos = normalize(pos);
- vec4 uv_rect = omni_lights.data[idx].atlas_rect;
+
+ vec4 uv_rect = base_uv_rect;
if (pos.z >= 0.0) {
- pos.z += 1.0;
- uv_rect.y += uv_rect.w;
- } else {
- pos.z = 1.0 - pos.z;
+ uv_rect.xy += flip_offset;
}
+ pos.z = 1.0 + abs(pos.z);
pos.xy /= pos.z;
pos.xy = pos.xy * 0.5 + 0.5;
@@ -512,20 +524,20 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) {
z_norm -= omni_lights.data[idx].inv_radius * omni_lights.data[idx].shadow_bias;
shadow = 0.0;
- for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) {
+ for (uint i = 0; i < sc_penumbra_shadow_samples; i++) {
vec2 disk = disk_rotation * scene_data.penumbra_shadow_kernel[i].xy;
- vec3 pos = splane.xyz + tangent * disk.x + bitangent * disk.y;
+ vec3 pos = local_vert + tangent * disk.x + bitangent * disk.y;
pos = normalize(pos);
- vec4 uv_rect = omni_lights.data[idx].atlas_rect;
+ pos = normalize(pos + normal_bias);
+
+ vec4 uv_rect = base_uv_rect;
if (pos.z >= 0.0) {
- pos.z += 1.0;
- uv_rect.y += uv_rect.w;
- } else {
- pos.z = 1.0 - pos.z;
+ uv_rect.xy += flip_offset;
}
+ pos.z = 1.0 + abs(pos.z);
pos.xy /= pos.z;
pos.xy = pos.xy * 0.5 + 0.5;
@@ -533,36 +545,27 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) {
shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(pos.xy, z_norm, 1.0));
}
- shadow /= float(scene_data.penumbra_shadow_samples);
+ shadow /= float(sc_penumbra_shadow_samples);
} else {
//no blockers found, so no shadow
shadow = 1.0;
}
} else {
-#endif
- splane.xyz = normalize(splane.xyz);
- vec4 clamp_rect = omni_lights.data[idx].atlas_rect;
-
- if (splane.z >= 0.0) {
- splane.z += 1.0;
+ vec4 uv_rect = base_uv_rect;
- clamp_rect.y += clamp_rect.w;
-
- } else {
- splane.z = 1.0 - splane.z;
+ vec3 shadow_sample = normalize(shadow_dir + normal_bias);
+ if (shadow_sample.z >= 0.0) {
+ uv_rect.xy += flip_offset;
+ flip_offset *= -1.0;
}
- splane.xy /= splane.z;
-
- splane.xy = splane.xy * 0.5 + 0.5;
- splane.z = (shadow_len - omni_lights.data[idx].shadow_bias) * omni_lights.data[idx].inv_radius;
- splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw;
- splane.w = 1.0; //needed? i think it should be 1 already
- shadow = sample_pcf_shadow(shadow_atlas, omni_lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, splane);
-#ifdef USE_SOFT_SHADOWS
+ shadow_sample.z = 1.0 + abs(shadow_sample.z);
+ vec2 pos = shadow_sample.xy / shadow_sample.z;
+ float depth = shadow_len - omni_lights.data[idx].shadow_bias;
+ depth *= omni_lights.data[idx].inv_radius;
+ shadow = sample_omni_pcf_shadow(shadow_atlas, omni_lights.data[idx].soft_shadow_scale / shadow_sample.z, pos, uv_rect, flip_offset, depth);
}
-#endif
return shadow;
}
@@ -571,18 +574,17 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) {
return 1.0;
}
-void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow,
+void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow, vec3 albedo, inout float alpha,
#ifdef LIGHT_BACKLIGHT_USED
vec3 backlight,
#endif
#ifdef LIGHT_TRANSMITTANCE_USED
vec4 transmittance_color,
float transmittance_depth,
- float transmittance_curve,
float transmittance_boost,
#endif
#ifdef LIGHT_RIM_USED
- float rim, float rim_tint, vec3 rim_color,
+ float rim, float rim_tint,
#endif
#ifdef LIGHT_CLEARCOAT_USED
float clearcoat, float clearcoat_gloss,
@@ -590,9 +592,6 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
#ifdef LIGHT_ANISOTROPY_USED
vec3 binormal, vec3 tangent, float anisotropy,
#endif
-#ifdef USE_SHADOW_TO_OPACITY
- inout float alpha,
-#endif
inout vec3 diffuse_light, inout vec3 specular_light) {
vec3 light_rel_vec = omni_lights.data[idx].position - vertex;
float light_length = length(light_rel_vec);
@@ -600,14 +599,12 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
float light_attenuation = omni_attenuation;
vec3 color = omni_lights.data[idx].color;
-#ifdef USE_SOFT_SHADOWS
float size_A = 0.0;
- if (omni_lights.data[idx].size > 0.0) {
+ if (sc_use_light_soft_shadows && omni_lights.data[idx].size > 0.0) {
float t = omni_lights.data[idx].size / max(0.001, light_length);
size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t));
}
-#endif
#ifdef LIGHT_TRANSMITTANCE_USED
float transmittance_z = transmittance_depth; //no transmittance by default
@@ -618,20 +615,22 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
//redo shadowmapping, but shrink the model a bit to avoid arctifacts
vec4 splane = (omni_lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * omni_lights.data[idx].transmittance_bias, 1.0));
- shadow_len = length(splane.xyz);
- splane = normalize(splane.xyz);
+ float shadow_len = length(splane.xyz);
+ splane.xyz = normalize(splane.xyz);
if (splane.z >= 0.0) {
splane.z += 1.0;
-
+ clamp_rect.y += clamp_rect.w;
} else {
splane.z = 1.0 - splane.z;
}
splane.xy /= splane.z;
+
splane.xy = splane.xy * 0.5 + 0.5;
splane.z = shadow_len * omni_lights.data[idx].inv_radius;
splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw;
+ // splane.xy = clamp(splane.xy,clamp_rect.xy + scene_data.shadow_atlas_pixel_size,clamp_rect.xy + clamp_rect.zw - scene_data.shadow_atlas_pixel_size );
splane.w = 1.0; //needed? i think it should be 1 already
float shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r;
@@ -639,78 +638,77 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
}
#endif
-#if 0
-
- if (omni_lights.data[idx].projector_rect != vec4(0.0)) {
+ if (sc_use_light_projector && omni_lights.data[idx].projector_rect != vec4(0.0)) {
vec3 local_v = (omni_lights.data[idx].shadow_matrix * vec4(vertex, 1.0)).xyz;
local_v = normalize(local_v);
vec4 atlas_rect = omni_lights.data[idx].projector_rect;
if (local_v.z >= 0.0) {
- local_v.z += 1.0;
atlas_rect.y += atlas_rect.w;
-
- } else {
- local_v.z = 1.0 - local_v.z;
}
+ local_v.z = 1.0 + abs(local_v.z);
+
local_v.xy /= local_v.z;
local_v.xy = local_v.xy * 0.5 + 0.5;
vec2 proj_uv = local_v.xy * atlas_rect.zw;
- vec2 proj_uv_ddx;
- vec2 proj_uv_ddy;
- {
- vec3 local_v_ddx = (omni_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddx, 1.0)).xyz;
- local_v_ddx = normalize(local_v_ddx);
+ if (sc_projector_use_mipmaps) {
+ vec2 proj_uv_ddx;
+ vec2 proj_uv_ddy;
+ {
+ vec3 local_v_ddx = (omni_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddx, 1.0)).xyz;
+ local_v_ddx = normalize(local_v_ddx);
- if (local_v_ddx.z >= 0.0) {
- local_v_ddx.z += 1.0;
- } else {
- local_v_ddx.z = 1.0 - local_v_ddx.z;
- }
+ if (local_v_ddx.z >= 0.0) {
+ local_v_ddx.z += 1.0;
+ } else {
+ local_v_ddx.z = 1.0 - local_v_ddx.z;
+ }
- local_v_ddx.xy /= local_v_ddx.z;
- local_v_ddx.xy = local_v_ddx.xy * 0.5 + 0.5;
+ local_v_ddx.xy /= local_v_ddx.z;
+ local_v_ddx.xy = local_v_ddx.xy * 0.5 + 0.5;
- proj_uv_ddx = local_v_ddx.xy * atlas_rect.zw - proj_uv;
+ proj_uv_ddx = local_v_ddx.xy * atlas_rect.zw - proj_uv;
- vec3 local_v_ddy = (omni_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddy, 1.0)).xyz;
- local_v_ddy = normalize(local_v_ddy);
+ vec3 local_v_ddy = (omni_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddy, 1.0)).xyz;
+ local_v_ddy = normalize(local_v_ddy);
- if (local_v_ddy.z >= 0.0) {
- local_v_ddy.z += 1.0;
- } else {
- local_v_ddy.z = 1.0 - local_v_ddy.z;
- }
+ if (local_v_ddy.z >= 0.0) {
+ local_v_ddy.z += 1.0;
+ } else {
+ local_v_ddy.z = 1.0 - local_v_ddy.z;
+ }
- local_v_ddy.xy /= local_v_ddy.z;
- local_v_ddy.xy = local_v_ddy.xy * 0.5 + 0.5;
+ local_v_ddy.xy /= local_v_ddy.z;
+ local_v_ddy.xy = local_v_ddy.xy * 0.5 + 0.5;
- proj_uv_ddy = local_v_ddy.xy * atlas_rect.zw - proj_uv;
- }
+ proj_uv_ddy = local_v_ddy.xy * atlas_rect.zw - proj_uv;
+ }
- vec4 proj = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), proj_uv + atlas_rect.xy, proj_uv_ddx, proj_uv_ddy);
- no_shadow = mix(no_shadow, proj.rgb, proj.a);
+ vec4 proj = textureGrad(sampler2D(decal_atlas_srgb, light_projector_sampler), proj_uv + atlas_rect.xy, proj_uv_ddx, proj_uv_ddy);
+ color *= proj.rgb * proj.a;
+ } else {
+ vec4 proj = textureLod(sampler2D(decal_atlas_srgb, light_projector_sampler), proj_uv + atlas_rect.xy, 0.0);
+ color *= proj.rgb * proj.a;
+ }
}
-#endif
light_attenuation *= shadow;
- light_compute(normal, normalize(light_rel_vec), eye_vec, color, light_attenuation, f0, orms, omni_lights.data[idx].specular_amount,
+ light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, light_attenuation, f0, orms, omni_lights.data[idx].specular_amount, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
#ifdef LIGHT_TRANSMITTANCE_USED
transmittance_color,
transmittance_depth,
- transmittance_curve,
transmittance_boost,
transmittance_z,
#endif
#ifdef LIGHT_RIM_USED
- rim * omni_attenuation, rim_tint, rim_color,
+ rim * omni_attenuation, rim_tint,
#endif
#ifdef LIGHT_CLEARCOAT_USED
clearcoat, clearcoat_gloss,
@@ -718,47 +716,33 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
#ifdef LIGHT_ANISOTROPY_USED
binormal, tangent, anisotropy,
#endif
-#ifdef USE_SOFT_SHADOWS
- size_A,
-#endif
-#ifdef USE_SHADOW_TO_OPACITY
- alpha,
-#endif
diffuse_light,
specular_light);
}
float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) {
-#ifndef USE_NO_SHADOWS
+#ifndef SHADOWS_DISABLED
if (spot_lights.data[idx].shadow_enabled) {
vec3 light_rel_vec = spot_lights.data[idx].position - vertex;
float light_length = length(light_rel_vec);
vec3 spot_dir = spot_lights.data[idx].direction;
- //there is a shadowmap
- vec4 v = vec4(vertex, 1.0);
-
- v.xyz -= spot_dir * spot_lights.data[idx].shadow_bias;
-
- float z_norm = dot(spot_dir, -light_rel_vec) * spot_lights.data[idx].inv_radius;
-
- float depth_bias_scale = 1.0 / (max(0.0001, z_norm)); //the closer to the light origin, the more you have to offset to reach 1px in the map
- vec3 normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(spot_dir, -normalize(normal_interp)))) * spot_lights.data[idx].shadow_normal_bias * depth_bias_scale;
- normal_bias -= spot_dir * dot(spot_dir, normal_bias); //only XY, no Z
- v.xyz += normal_bias;
- //adjust with bias
- z_norm = dot(spot_dir, v.xyz - spot_lights.data[idx].position) * spot_lights.data[idx].inv_radius;
+ vec3 shadow_dir = light_rel_vec / light_length;
+ vec3 normal_bias = normal * light_length * spot_lights.data[idx].shadow_normal_bias * (1.0 - abs(dot(normal, shadow_dir)));
- float shadow;
+ //there is a shadowmap
+ vec4 v = vec4(vertex + normal_bias, 1.0);
vec4 splane = (spot_lights.data[idx].shadow_matrix * v);
+ splane.z -= spot_lights.data[idx].shadow_bias / (light_length * spot_lights.data[idx].inv_radius);
splane /= splane.w;
-#ifdef USE_SOFT_SHADOWS
- if (spot_lights.data[idx].soft_shadow_size > 0.0) {
+ float shadow;
+ if (sc_use_light_soft_shadows && spot_lights.data[idx].soft_shadow_size > 0.0) {
//soft shadow
//find blocker
+ float z_norm = dot(spot_dir, -light_rel_vec) * spot_lights.data[idx].inv_radius;
vec2 shadow_uv = splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy;
@@ -775,11 +759,11 @@ float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) {
float uv_size = spot_lights.data[idx].soft_shadow_size * z_norm * spot_lights.data[idx].soft_shadow_scale;
vec2 clamp_max = spot_lights.data[idx].atlas_rect.xy + spot_lights.data[idx].atlas_rect.zw;
- for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) {
+ for (uint i = 0; i < sc_penumbra_shadow_samples; i++) {
vec2 suv = shadow_uv + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size;
suv = clamp(suv, spot_lights.data[idx].atlas_rect.xy, clamp_max);
float d = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), suv, 0.0).r;
- if (d < z_norm) {
+ if (d < splane.z) {
blocker_average += d;
blocker_count += 1.0;
}
@@ -792,49 +776,55 @@ float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) {
uv_size *= penumbra;
shadow = 0.0;
- for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) {
+ for (uint i = 0; i < sc_penumbra_shadow_samples; i++) {
vec2 suv = shadow_uv + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size;
suv = clamp(suv, spot_lights.data[idx].atlas_rect.xy, clamp_max);
- shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(suv, z_norm, 1.0));
+ shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(suv, splane.z, 1.0));
}
- shadow /= float(scene_data.penumbra_shadow_samples);
+ shadow /= float(sc_penumbra_shadow_samples);
} else {
//no blockers found, so no shadow
shadow = 1.0;
}
-
} else {
-#endif
//hard shadow
- vec4 shadow_uv = vec4(splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy, splane.z, 1.0);
-
+ vec3 shadow_uv = vec3(splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy, splane.z);
shadow = sample_pcf_shadow(shadow_atlas, spot_lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, shadow_uv);
-#ifdef USE_SOFT_SHADOWS
}
-#endif
return shadow;
}
-#endif //USE_NO_SHADOWS
+#endif // SHADOWS_DISABLED
return 1.0;
}
-void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow,
+vec2 normal_to_panorama(vec3 n) {
+ n = normalize(n);
+ vec2 panorama_coords = vec2(atan(n.x, n.z), acos(-n.y));
+
+ if (panorama_coords.x < 0.0) {
+ panorama_coords.x += M_PI * 2.0;
+ }
+
+ panorama_coords /= vec2(M_PI * 2.0, M_PI);
+ return panorama_coords;
+}
+
+void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow, vec3 albedo, inout float alpha,
#ifdef LIGHT_BACKLIGHT_USED
vec3 backlight,
#endif
#ifdef LIGHT_TRANSMITTANCE_USED
vec4 transmittance_color,
float transmittance_depth,
- float transmittance_curve,
float transmittance_boost,
#endif
#ifdef LIGHT_RIM_USED
- float rim, float rim_tint, vec3 rim_color,
+ float rim, float rim_tint,
#endif
#ifdef LIGHT_CLEARCOAT_USED
float clearcoat, float clearcoat_gloss,
@@ -842,9 +832,6 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
#ifdef LIGHT_ANISOTROPY_USED
vec3 binormal, vec3 tangent, float anisotropy,
#endif
-#ifdef USE_SHADOW_TO_OPACITY
- inout float alpha,
-#endif
inout vec3 diffuse_light,
inout vec3 specular_light) {
vec3 light_rel_vec = spot_lights.data[idx].position - vertex;
@@ -858,53 +845,71 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
vec3 color = spot_lights.data[idx].color;
float specular_amount = spot_lights.data[idx].specular_amount;
-#ifdef USE_SOFT_SHADOWS
float size_A = 0.0;
- if (spot_lights.data[idx].size > 0.0) {
+ if (sc_use_light_soft_shadows && spot_lights.data[idx].size > 0.0) {
float t = spot_lights.data[idx].size / max(0.001, light_length);
size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t));
}
-#endif
-
- /*
- if (spot_lights.data[idx].atlas_rect!=vec4(0.0)) {
- //use projector texture
- }
- */
#ifdef LIGHT_TRANSMITTANCE_USED
float transmittance_z = transmittance_depth;
transmittance_color.a *= light_attenuation;
{
- splane = (spot_lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * spot_lights.data[idx].transmittance_bias, 1.0));
+ vec4 splane = (spot_lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * spot_lights.data[idx].transmittance_bias, 1.0));
splane /= splane.w;
splane.xy = splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy;
float shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r;
- //reconstruct depth
- shadow_z /= spot_lights.data[idx].inv_radius;
+
+ shadow_z = shadow_z * 2.0 - 1.0;
+ float z_far = 1.0 / spot_lights.data[idx].inv_radius;
+ float z_near = 0.01;
+ shadow_z = 2.0 * z_near * z_far / (z_far + z_near - shadow_z * (z_far - z_near));
+
//distance to light plane
float z = dot(spot_dir, -light_rel_vec);
transmittance_z = z - shadow_z;
}
#endif //LIGHT_TRANSMITTANCE_USED
+ if (sc_use_light_projector && spot_lights.data[idx].projector_rect != vec4(0.0)) {
+ vec4 splane = (spot_lights.data[idx].shadow_matrix * vec4(vertex, 1.0));
+ splane /= splane.w;
+
+ vec2 proj_uv = normal_to_panorama(splane.xyz) * spot_lights.data[idx].projector_rect.zw;
+
+ if (sc_projector_use_mipmaps) {
+ //ensure we have proper mipmaps
+ vec4 splane_ddx = (spot_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddx, 1.0));
+ splane_ddx /= splane_ddx.w;
+ vec2 proj_uv_ddx = normal_to_panorama(splane_ddx.xyz) * spot_lights.data[idx].projector_rect.zw - proj_uv;
+
+ vec4 splane_ddy = (spot_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddy, 1.0));
+ splane_ddy /= splane_ddy.w;
+ vec2 proj_uv_ddy = normal_to_panorama(splane_ddy.xyz) * spot_lights.data[idx].projector_rect.zw - proj_uv;
+
+ vec4 proj = textureGrad(sampler2D(decal_atlas_srgb, light_projector_sampler), proj_uv + spot_lights.data[idx].projector_rect.xy, proj_uv_ddx, proj_uv_ddy);
+ color *= proj.rgb * proj.a;
+ } else {
+ vec4 proj = textureLod(sampler2D(decal_atlas_srgb, light_projector_sampler), proj_uv + spot_lights.data[idx].projector_rect.xy, 0.0);
+ color *= proj.rgb * proj.a;
+ }
+ }
light_attenuation *= shadow;
- light_compute(normal, normalize(light_rel_vec), eye_vec, color, light_attenuation, f0, orms, spot_lights.data[idx].specular_amount,
+ light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, light_attenuation, f0, orms, spot_lights.data[idx].specular_amount, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
#ifdef LIGHT_TRANSMITTANCE_USED
transmittance_color,
transmittance_depth,
- transmittance_curve,
transmittance_boost,
transmittance_z,
#endif
#ifdef LIGHT_RIM_USED
- rim * spot_attenuation, rim_tint, rim_color,
+ rim * spot_attenuation, rim_tint,
#endif
#ifdef LIGHT_CLEARCOAT_USED
clearcoat, clearcoat_gloss,
@@ -912,12 +917,6 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
#ifdef LIGHT_ANISOTROPY_USED
binormal, tangent, anisotropy,
#endif
-#ifdef USE_SOFT_SHADOW
- size_A,
-#endif
-#ifdef USE_SHADOW_TO_OPACITY
- alpha,
-#endif
diffuse_light, specular_light);
}
@@ -957,7 +956,7 @@ void reflection_process(uint ref_index, vec3 vertex, vec3 normal, float roughnes
vec4 reflection;
- reflection.rgb = textureLod(samplerCubeArray(reflection_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_ref_vec, reflections.data[ref_index].index), roughness * MAX_ROUGHNESS_LOD).rgb;
+ reflection.rgb = textureLod(samplerCubeArray(reflection_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_ref_vec, reflections.data[ref_index].index), roughness * MAX_ROUGHNESS_LOD).rgb * sc_luminance_multiplier;
if (reflections.data[ref_index].exterior) {
reflection.rgb = mix(specular_light, reflection.rgb, blend);
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl
index b38b8d803d..e92fbecfd0 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl
@@ -7,6 +7,8 @@
/* Include our forward mobile UBOs definitions etc. */
#include "scene_forward_mobile_inc.glsl"
+#define SHADER_IS_SRGB false
+
/* INPUT ATTRIBS */
layout(location = 0) in vec3 vertex_attrib;
@@ -59,27 +61,27 @@ layout(location = 11) in vec4 weight_attrib;
/* Varyings */
-layout(location = 0) out vec3 vertex_interp;
+layout(location = 0) highp out vec3 vertex_interp;
#ifdef NORMAL_USED
-layout(location = 1) out vec3 normal_interp;
+layout(location = 1) mediump out vec3 normal_interp;
#endif
#if defined(COLOR_USED)
-layout(location = 2) out vec4 color_interp;
+layout(location = 2) mediump out vec4 color_interp;
#endif
#ifdef UV_USED
-layout(location = 3) out vec2 uv_interp;
+layout(location = 3) mediump out vec2 uv_interp;
#endif
#if defined(UV2_USED) || defined(USE_LIGHTMAP)
-layout(location = 4) out vec2 uv2_interp;
+layout(location = 4) mediump out vec2 uv2_interp;
#endif
#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
-layout(location = 5) out vec3 tangent_interp;
-layout(location = 6) out vec3 binormal_interp;
+layout(location = 5) mediump out vec3 tangent_interp;
+layout(location = 6) mediump out vec3 binormal_interp;
#endif
#ifdef MATERIAL_UNIFORMS_USED
@@ -92,9 +94,21 @@ layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms
#ifdef MODE_DUAL_PARABOLOID
-layout(location = 8) out float dp_clip;
+layout(location = 8) out highp float dp_clip;
+
+#endif
+#ifdef USE_MULTIVIEW
+#ifdef has_VK_KHR_multiview
+#define ViewIndex gl_ViewIndex
+#else
+// !BAS! This needs to become an input once we implement our fallback!
+#define ViewIndex 0
#endif
+#else
+// Set to zero, not supported in non stereo
+#define ViewIndex 0
+#endif //USE_MULTIVIEW
invariant gl_Position;
@@ -112,7 +126,7 @@ void main() {
mat3 world_normal_matrix;
if (bool(draw_call.flags & INSTANCE_FLAGS_NON_UNIFORM_SCALE)) {
- world_normal_matrix = inverse(mat3(world_matrix));
+ world_normal_matrix = transpose(inverse(mat3(world_matrix)));
} else {
world_normal_matrix = mat3(world_matrix);
}
@@ -234,7 +248,13 @@ void main() {
vec4 position;
#endif
+#ifdef USE_MULTIVIEW
+ mat4 projection_matrix = scene_data.projection_matrix_view[ViewIndex];
+ mat4 inv_projection_matrix = scene_data.inv_projection_matrix_view[ViewIndex];
+#else
mat4 projection_matrix = scene_data.projection_matrix;
+ mat4 inv_projection_matrix = scene_data.inv_projection_matrix;
+#endif //USE_MULTIVIEW
//using world coordinates
#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED)
@@ -352,44 +372,95 @@ void main() {
#VERSION_DEFINES
+#define SHADER_IS_SRGB false
+
+/* Specialization Constants */
+
+#if !defined(MODE_RENDER_DEPTH)
+
+#if !defined(MODE_UNSHADED)
+
+layout(constant_id = 0) const bool sc_use_light_projector = false;
+layout(constant_id = 1) const bool sc_use_light_soft_shadows = false;
+layout(constant_id = 2) const bool sc_use_directional_soft_shadows = false;
+
+layout(constant_id = 3) const uint sc_soft_shadow_samples = 4;
+layout(constant_id = 4) const uint sc_penumbra_shadow_samples = 4;
+
+layout(constant_id = 5) const uint sc_directional_soft_shadow_samples = 4;
+layout(constant_id = 6) const uint sc_directional_penumbra_shadow_samples = 4;
+
+layout(constant_id = 8) const bool sc_projector_use_mipmaps = true;
+
+layout(constant_id = 9) const bool sc_disable_omni_lights = false;
+layout(constant_id = 10) const bool sc_disable_spot_lights = false;
+layout(constant_id = 11) const bool sc_disable_reflection_probes = false;
+layout(constant_id = 12) const bool sc_disable_directional_lights = false;
+
+#endif //!MODE_UNSHADED
+
+layout(constant_id = 7) const bool sc_decal_use_mipmaps = true;
+layout(constant_id = 13) const bool sc_disable_decals = false;
+layout(constant_id = 14) const bool sc_disable_fog = false;
+
+#endif //!MODE_RENDER_DEPTH
+
+layout(constant_id = 15) const float sc_luminance_multiplier = 2.0;
+
/* Include our forward mobile UBOs definitions etc. */
#include "scene_forward_mobile_inc.glsl"
/* Varyings */
-layout(location = 0) in vec3 vertex_interp;
+layout(location = 0) highp in vec3 vertex_interp;
#ifdef NORMAL_USED
-layout(location = 1) in vec3 normal_interp;
+layout(location = 1) mediump in vec3 normal_interp;
#endif
#if defined(COLOR_USED)
-layout(location = 2) in vec4 color_interp;
+layout(location = 2) mediump in vec4 color_interp;
#endif
#ifdef UV_USED
-layout(location = 3) in vec2 uv_interp;
+layout(location = 3) mediump in vec2 uv_interp;
#endif
#if defined(UV2_USED) || defined(USE_LIGHTMAP)
-layout(location = 4) in vec2 uv2_interp;
+layout(location = 4) mediump in vec2 uv2_interp;
#endif
#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
-layout(location = 5) in vec3 tangent_interp;
-layout(location = 6) in vec3 binormal_interp;
+layout(location = 5) mediump in vec3 tangent_interp;
+layout(location = 6) mediump in vec3 binormal_interp;
#endif
#ifdef MODE_DUAL_PARABOLOID
-layout(location = 8) in float dp_clip;
+layout(location = 8) highp in float dp_clip;
+
+#endif
+#ifdef USE_MULTIVIEW
+#ifdef has_VK_KHR_multiview
+#define ViewIndex gl_ViewIndex
+#else
+// !BAS! This needs to become an input once we implement our fallback!
+#define ViewIndex 0
#endif
+#else
+// Set to zero, not supported in non stereo
+#define ViewIndex 0
+#endif //USE_MULTIVIEW
//defines to keep compatibility with vertex
#define world_matrix draw_call.transform
+#ifdef USE_MULTIVIEW
+#define projection_matrix scene_data.projection_matrix_view[ViewIndex]
+#else
#define projection_matrix scene_data.projection_matrix
+#endif
#if defined(ENABLE_SSS) && defined(ENABLE_TRANSMITTANCE)
//both required for transmittance to be enabled
@@ -428,7 +499,7 @@ layout(location = 0) out vec4 diffuse_buffer; //diffuse (rgb) and roughness
layout(location = 1) out vec4 specular_buffer; //specular and SSS (subsurface scatter)
#else
-layout(location = 0) out vec4 frag_color;
+layout(location = 0) out mediump vec4 frag_color;
#endif // MODE_MULTIPLE_RENDER_TARGETS
#endif // RENDER DEPTH
@@ -437,6 +508,11 @@ layout(location = 0) out vec4 frag_color;
#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
+/* Make a default specular mode SPECULAR_SCHLICK_GGX. */
+#if !defined(SPECULAR_DISABLED) && !defined(SPECULAR_SCHLICK_GGX) && !defined(SPECULAR_BLINN) && !defined(SPECULAR_PHONG) && !defined(SPECULAR_TOON)
+#define SPECULAR_SCHLICK_GGX
+#endif
+
#include "scene_forward_lights_inc.glsl"
#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
@@ -478,14 +554,14 @@ vec4 fog_process(vec3 vertex) {
}
}
- float fog_amount = 1.0 - exp(min(0.0, vertex.z * scene_data.fog_density));
+ float fog_amount = 1.0 - exp(min(0.0, -length(vertex) * scene_data.fog_density));
- if (abs(scene_data.fog_height_density) > 0.001) {
+ if (abs(scene_data.fog_height_density) >= 0.0001) {
float y = (scene_data.camera_matrix * vec4(vertex, 1.0)).y;
- float y_dist = scene_data.fog_height - y;
+ float y_dist = y - scene_data.fog_height;
- float vfog_amount = clamp(exp(y_dist * scene_data.fog_height_density), 0.0, 1.0);
+ float vfog_amount = 1.0 - exp(min(0.0, y_dist * scene_data.fog_height_density));
fog_amount = max(vfog_amount, fog_amount);
}
@@ -509,7 +585,6 @@ void main() {
vec3 backlight = vec3(0.0);
vec4 transmittance_color = vec4(0.0);
float transmittance_depth = 0.0;
- float transmittance_curve = 1.0;
float transmittance_boost = 0.0;
float metallic = 0.0;
float specular = 0.5;
@@ -622,7 +697,7 @@ void main() {
#endif
#ifdef ALPHA_ANTIALIASING_EDGE_USED
-// If alpha scissor is used, we must further the edge threshold, otherwise we wont get any edge feather
+// If alpha scissor is used, we must further the edge threshold, otherwise we won't get any edge feather
#ifdef ALPHA_SCISSOR_USED
alpha_antialiasing_edge = clamp(alpha_scissor_threshold + alpha_antialiasing_edge, 0.0, 1.0);
#endif
@@ -630,7 +705,7 @@ void main() {
#endif // ALPHA_ANTIALIASING_EDGE_USED
#ifdef USE_OPAQUE_PREPASS
- if (alpha < opaque_prepass_threshold) {
+ if (alpha < scene_data.opaque_prepass_threshold) {
discard;
}
#endif // USE_OPAQUE_PREPASS
@@ -673,7 +748,7 @@ void main() {
// to maximize VGPR usage
// Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky.
- if (scene_data.fog_enabled) {
+ if (!sc_disable_fog && scene_data.fog_enabled) {
fog = fog_process(vertex);
}
@@ -691,7 +766,7 @@ void main() {
vec3 vertex_ddx = dFdx(vertex);
vec3 vertex_ddy = dFdy(vertex);
- { //Decals
+ if (!sc_disable_decals) { //Decals
// must implement
uint decal_indices = draw_call.decals.x;
@@ -712,25 +787,35 @@ void main() {
continue; //out of decal
}
- //we need ddx/ddy for mipmaps, so simulate them
- vec2 ddx = (decals.data[decal_index].xform * vec4(vertex_ddx, 0.0)).xz;
- vec2 ddy = (decals.data[decal_index].xform * vec4(vertex_ddy, 0.0)).xz;
-
float fade = pow(1.0 - (uv_local.y > 0.0 ? uv_local.y : -uv_local.y), uv_local.y > 0.0 ? decals.data[decal_index].upper_fade : decals.data[decal_index].lower_fade);
if (decals.data[decal_index].normal_fade > 0.0) {
fade *= smoothstep(decals.data[decal_index].normal_fade, 1.0, dot(normal_interp, decals.data[decal_index].normal) * 0.5 + 0.5);
}
+ //we need ddx/ddy for mipmaps, so simulate them
+ vec2 ddx = (decals.data[decal_index].xform * vec4(vertex_ddx, 0.0)).xz;
+ vec2 ddy = (decals.data[decal_index].xform * vec4(vertex_ddy, 0.0)).xz;
+
if (decals.data[decal_index].albedo_rect != vec4(0.0)) {
//has albedo
- vec4 decal_albedo = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, ddx * decals.data[decal_index].albedo_rect.zw, ddy * decals.data[decal_index].albedo_rect.zw);
+ vec4 decal_albedo;
+ if (sc_decal_use_mipmaps) {
+ decal_albedo = textureGrad(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, ddx * decals.data[decal_index].albedo_rect.zw, ddy * decals.data[decal_index].albedo_rect.zw);
+ } else {
+ decal_albedo = textureLod(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, 0.0);
+ }
decal_albedo *= decals.data[decal_index].modulate;
decal_albedo.a *= fade;
albedo = mix(albedo, decal_albedo.rgb, decal_albedo.a * decals.data[decal_index].albedo_mix);
if (decals.data[decal_index].normal_rect != vec4(0.0)) {
- vec3 decal_normal = textureGrad(sampler2D(decal_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, ddx * decals.data[decal_index].normal_rect.zw, ddy * decals.data[decal_index].normal_rect.zw).xyz;
+ vec3 decal_normal;
+ if (sc_decal_use_mipmaps) {
+ decal_normal = textureGrad(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, ddx * decals.data[decal_index].normal_rect.zw, ddy * decals.data[decal_index].normal_rect.zw).xyz;
+ } else {
+ decal_normal = textureLod(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, 0.0).xyz;
+ }
decal_normal.xy = decal_normal.xy * vec2(2.0, -2.0) - vec2(1.0, -1.0); //users prefer flipped y normal maps in most authoring software
decal_normal.z = sqrt(max(0.0, 1.0 - dot(decal_normal.xy, decal_normal.xy)));
//convert to view space, use xzy because y is up
@@ -740,7 +825,12 @@ void main() {
}
if (decals.data[decal_index].orm_rect != vec4(0.0)) {
- vec3 decal_orm = textureGrad(sampler2D(decal_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, ddx * decals.data[decal_index].orm_rect.zw, ddy * decals.data[decal_index].orm_rect.zw).xyz;
+ vec3 decal_orm;
+ if (sc_decal_use_mipmaps) {
+ decal_orm = textureGrad(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, ddx * decals.data[decal_index].orm_rect.zw, ddy * decals.data[decal_index].orm_rect.zw).xyz;
+ } else {
+ decal_orm = textureLod(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, 0.0).xyz;
+ }
ao = mix(ao, decal_orm.r, decal_albedo.a);
roughness = mix(roughness, decal_orm.g, decal_albedo.a);
metallic = mix(metallic, decal_orm.b, decal_albedo.a);
@@ -749,7 +839,11 @@ void main() {
if (decals.data[decal_index].emission_rect != vec4(0.0)) {
//emission is additive, so its independent from albedo
- emission += textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, ddx * decals.data[decal_index].emission_rect.zw, ddy * decals.data[decal_index].emission_rect.zw).xyz * decals.data[decal_index].emission_energy * fade;
+ if (sc_decal_use_mipmaps) {
+ emission += textureGrad(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, ddx * decals.data[decal_index].emission_rect.zw, ddy * decals.data[decal_index].emission_rect.zw).xyz * decals.data[decal_index].emission_energy * fade;
+ } else {
+ emission += textureLod(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, 0.0).xyz * decals.data[decal_index].emission_energy * fade;
+ }
}
}
} //Decals
@@ -759,9 +853,9 @@ void main() {
#ifdef NORMAL_USED
if (scene_data.roughness_limiter_enabled) {
- //http://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA.pdf
+ //https://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA.pdf
float roughness2 = roughness * roughness;
- vec3 dndu = dFdx(normal), dndv = dFdx(normal);
+ vec3 dndu = dFdx(normal), dndv = dFdy(normal);
float variance = scene_data.roughness_limiter_amount * (dot(dndu, dndu) + dot(dndv, dndv));
float kernelRoughness2 = min(2.0 * variance, scene_data.roughness_limiter_limit); //limit effect
float filteredRoughness2 = min(1.0, roughness2 + kernelRoughness2);
@@ -778,6 +872,7 @@ void main() {
if (scene_data.use_reflection_cubemap) {
vec3 ref_vec = reflect(-view, normal);
+ float horizon = min(1.0 + dot(ref_vec, normal), 1.0);
ref_vec = scene_data.radiance_inverse_xform * ref_vec;
#ifdef USE_RADIANCE_CUBEMAP_ARRAY
@@ -790,6 +885,7 @@ void main() {
specular_light = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ref_vec, roughness * MAX_ROUGHNESS_LOD).rgb;
#endif //USE_RADIANCE_CUBEMAP_ARRAY
+ specular_light *= horizon * horizon;
specular_light *= scene_data.ambient_light_color_energy.a;
}
@@ -838,15 +934,15 @@ void main() {
const float c4 = 0.886227;
const float c5 = 0.247708;
ambient_light += (c1 * lightmap_captures.data[index].sh[8].rgb * (wnormal.x * wnormal.x - wnormal.y * wnormal.y) +
- c3 * lightmap_captures.data[index].sh[6].rgb * wnormal.z * wnormal.z +
- c4 * lightmap_captures.data[index].sh[0].rgb -
- c5 * lightmap_captures.data[index].sh[6].rgb +
- 2.0 * c1 * lightmap_captures.data[index].sh[4].rgb * wnormal.x * wnormal.y +
- 2.0 * c1 * lightmap_captures.data[index].sh[7].rgb * wnormal.x * wnormal.z +
- 2.0 * c1 * lightmap_captures.data[index].sh[5].rgb * wnormal.y * wnormal.z +
- 2.0 * c2 * lightmap_captures.data[index].sh[3].rgb * wnormal.x +
- 2.0 * c2 * lightmap_captures.data[index].sh[1].rgb * wnormal.y +
- 2.0 * c2 * lightmap_captures.data[index].sh[2].rgb * wnormal.z);
+ c3 * lightmap_captures.data[index].sh[6].rgb * wnormal.z * wnormal.z +
+ c4 * lightmap_captures.data[index].sh[0].rgb -
+ c5 * lightmap_captures.data[index].sh[6].rgb +
+ 2.0 * c1 * lightmap_captures.data[index].sh[4].rgb * wnormal.x * wnormal.y +
+ 2.0 * c1 * lightmap_captures.data[index].sh[7].rgb * wnormal.x * wnormal.z +
+ 2.0 * c1 * lightmap_captures.data[index].sh[5].rgb * wnormal.y * wnormal.z +
+ 2.0 * c2 * lightmap_captures.data[index].sh[3].rgb * wnormal.x +
+ 2.0 * c2 * lightmap_captures.data[index].sh[1].rgb * wnormal.y +
+ 2.0 * c2 * lightmap_captures.data[index].sh[2].rgb * wnormal.z);
} else if (bool(draw_call.flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { // has actual lightmap
bool uses_sh = bool(draw_call.flags & INSTANCE_FLAGS_USE_SH_LIGHTMAP);
@@ -887,7 +983,7 @@ void main() {
// skipping ssao, do we remove ssao totally?
- { //Reflection probes
+ if (!sc_disable_reflection_probes) { //Reflection probes
vec4 reflection_accum = vec4(0.0, 0.0, 0.0, 0.0);
vec4 ambient_accum = vec4(0.0, 0.0, 0.0, 0.0);
@@ -928,7 +1024,7 @@ void main() {
specular_light *= specular * metallic * albedo * 2.0;
#else
- // scales the specular reflections, needs to be be computed before lighting happens,
+ // scales the specular reflections, needs to be computed before lighting happens,
// but after environment, GI, and reflection probes are added
// Environment brdf approximation (Lazarov 2013)
// see https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile
@@ -953,8 +1049,8 @@ void main() {
// LIGHTING
#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
- { //directional light
-
+ if (!sc_disable_directional_lights) { //directional light
+#ifndef SHADOWS_DISABLED
// Do shadow and lighting in two passes to reduce register pressure
uint shadow0 = 0;
uint shadow1 = 0;
@@ -1230,6 +1326,8 @@ void main() {
}
}
+#endif // SHADOWS_DISABLED
+
for (uint i = 0; i < 8; i++) {
if (i >= scene_data.directional_light_count) {
break;
@@ -1242,16 +1340,16 @@ void main() {
// We're not doing light transmittence
float shadow = 1.0;
-
+#ifndef SHADOWS_DISABLED
if (i < 4) {
shadow = float(shadow0 >> (i * 8) & 0xFF) / 255.0;
} else {
shadow = float(shadow1 >> ((i - 4) * 8) & 0xFF) / 255.0;
}
-
+#endif
blur_shadow(shadow);
- light_compute(normal, directional_lights.data[i].direction, normalize(view), directional_lights.data[i].color * directional_lights.data[i].energy, shadow, f0, orms, 1.0,
+ light_compute(normal, directional_lights.data[i].direction, normalize(view), 0.0, directional_lights.data[i].color * directional_lights.data[i].energy, shadow, f0, orms, 1.0, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
@@ -1259,13 +1357,12 @@ void main() {
#ifdef LIGHT_TRANSMITTANCE_USED
transmittance_color,
transmittance_depth,
- transmittance_curve,
transmittance_boost,
transmittance_z,
#endif
*/
#ifdef LIGHT_RIM_USED
- rim, rim_tint, albedo,
+ rim, rim_tint,
#endif
#ifdef LIGHT_CLEARCOAT_USED
clearcoat, clearcoat_gloss,
@@ -1276,15 +1373,12 @@ void main() {
#ifdef USE_SOFT_SHADOW
directional_lights.data[i].size,
#endif
-#ifdef USE_SHADOW_TO_OPACITY
- alpha,
-#endif
diffuse_light,
specular_light);
}
} //directional light
- { //omni lights
+ if (!sc_disable_omni_lights) { //omni lights
uint light_indices = draw_call.omni_lights.x;
for (uint i = 0; i < 8; i++) {
uint light_index = light_indices & 0xFF;
@@ -1298,11 +1392,11 @@ void main() {
break;
}
- float shadow = light_process_omni_shadow(light_index, vertex, view);
+ float shadow = light_process_omni_shadow(light_index, vertex, normal);
shadow = blur_shadow(shadow);
- light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow,
+ light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
@@ -1310,14 +1404,12 @@ void main() {
#ifdef LIGHT_TRANSMITTANCE_USED
transmittance_color,
transmittance_depth,
- transmittance_curve,
transmittance_boost,
#endif
*/
#ifdef LIGHT_RIM_USED
rim,
rim_tint,
- albedo,
#endif
#ifdef LIGHT_CLEARCOAT_USED
clearcoat, clearcoat_gloss,
@@ -1325,14 +1417,11 @@ void main() {
#ifdef LIGHT_ANISOTROPY_USED
tangent, binormal, anisotropy,
#endif
-#ifdef USE_SHADOW_TO_OPACITY
- alpha,
-#endif
diffuse_light, specular_light);
}
} //omni lights
- { //spot lights
+ if (!sc_disable_spot_lights) { //spot lights
uint light_indices = draw_call.spot_lights.x;
for (uint i = 0; i < 8; i++) {
@@ -1347,11 +1436,11 @@ void main() {
break;
}
- float shadow = light_process_spot_shadow(light_index, vertex, view);
+ float shadow = light_process_spot_shadow(light_index, vertex, normal);
shadow = blur_shadow(shadow);
- light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow,
+ light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
@@ -1359,14 +1448,12 @@ void main() {
#ifdef LIGHT_TRANSMITTANCE_USED
transmittance_color,
transmittance_depth,
- transmittance_curve,
transmittance_boost,
#endif
*/
#ifdef LIGHT_RIM_USED
rim,
rim_tint,
- albedo,
#endif
#ifdef LIGHT_CLEARCOAT_USED
clearcoat, clearcoat_gloss,
@@ -1374,9 +1461,6 @@ void main() {
#ifdef LIGHT_ANISOTROPY_USED
tangent, binormal, anisotropy,
#endif
-#ifdef USE_SHADOW_TO_OPACITY
- alpha,
-#endif
diffuse_light, specular_light);
}
} //spot lights
@@ -1392,7 +1476,7 @@ void main() {
#ifdef USE_OPAQUE_PREPASS
- if (alpha < opaque_prepass_threshold) {
+ if (alpha < scene_data.opaque_prepass_threshold) {
discard;
}
@@ -1464,12 +1548,15 @@ void main() {
frag_color = vec4(albedo, alpha);
#else // MODE_UNSHADED
frag_color = vec4(emission + ambient_light + diffuse_light + specular_light, alpha);
- //frag_color = vec4(1.0);
#endif // MODE_UNSHADED
// Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky.
frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a);
+ // On mobile we use a UNORM buffer with 10bpp which results in a range from 0.0 - 1.0 resulting in HDR breaking
+ // We divide by sc_luminance_multiplier to support a range from 0.0 - 2.0 both increasing precision on bright and darker images
+ frag_color.rgb = frag_color.rgb / sc_luminance_multiplier;
+
#endif //MODE_MULTIPLE_RENDER_TARGETS
#endif //MODE_RENDER_DEPTH
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl
index 0156b58574..a9a4fce82a 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl
@@ -1,4 +1,9 @@
#define M_PI 3.14159265359
+#define MAX_VIEWS 2
+
+#if defined(USE_MULTIVIEW) && defined(has_VK_KHR_multiview)
+#extension GL_EXT_multiview : enable
+#endif
#include "decal_data_inc.glsl"
@@ -11,12 +16,12 @@
/* don't exceed 128 bytes!! */
/* put instance data into our push content, not a array */
layout(push_constant, binding = 0, std430) uniform DrawCall {
- mat4 transform; // 64 - 64
+ highp mat4 transform; // 64 - 64
uint flags; // 04 - 68
uint instance_uniforms_ofs; //base offset in global buffer for instance variables // 04 - 72
uint gi_offset; //GI information when using lightmapping (VCT or lightmap index) // 04 - 76
uint layer_mask; // 04 - 80
- vec4 lightmap_uv_scale; // 16 - 96 doubles as uv_offset when needed
+ highp vec4 lightmap_uv_scale; // 16 - 96 doubles as uv_offset when needed
uvec2 reflection_probes; // 08 - 104
uvec2 omni_lights; // 08 - 112
@@ -46,12 +51,16 @@ layout(set = 0, binding = 1) uniform sampler material_samplers[12];
layout(set = 0, binding = 2) uniform sampler shadow_sampler;
+layout(set = 0, binding = 3) uniform sampler decal_sampler;
+layout(set = 0, binding = 4) uniform sampler light_projector_sampler;
+
+#define INSTANCE_FLAGS_NON_UNIFORM_SCALE (1 << 5)
#define INSTANCE_FLAGS_USE_GI_BUFFERS (1 << 6)
#define INSTANCE_FLAGS_USE_SDFGI (1 << 7)
#define INSTANCE_FLAGS_USE_LIGHTMAP_CAPTURE (1 << 8)
#define INSTANCE_FLAGS_USE_LIGHTMAP (1 << 9)
#define INSTANCE_FLAGS_USE_SH_LIGHTMAP (1 << 10)
-#define INSTANCE_FLAGS_USE_GIPROBE (1 << 11)
+#define INSTANCE_FLAGS_USE_VOXEL_GI (1 << 11)
#define INSTANCE_FLAGS_MULTIMESH (1 << 12)
#define INSTANCE_FLAGS_MULTIMESH_FORMAT_2D (1 << 13)
#define INSTANCE_FLAGS_MULTIMESH_HAS_COLOR (1 << 14)
@@ -60,24 +69,22 @@ layout(set = 0, binding = 2) uniform sampler shadow_sampler;
//3 bits of stride
#define INSTANCE_FLAGS_PARTICLE_TRAIL_MASK 0xFF
-#define INSTANCE_FLAGS_NON_UNIFORM_SCALE (1 << 24)
-
-layout(set = 0, binding = 3, std430) restrict readonly buffer OmniLights {
+layout(set = 0, binding = 5, std430) restrict readonly buffer OmniLights {
LightData data[];
}
omni_lights;
-layout(set = 0, binding = 4, std430) restrict readonly buffer SpotLights {
+layout(set = 0, binding = 6, std430) restrict readonly buffer SpotLights {
LightData data[];
}
spot_lights;
-layout(set = 0, binding = 5, std430) restrict readonly buffer ReflectionProbeData {
+layout(set = 0, binding = 7, std430) restrict readonly buffer ReflectionProbeData {
ReflectionData data[];
}
reflections;
-layout(set = 0, binding = 6, std140) uniform DirectionalLights {
+layout(set = 0, binding = 8, std140) uniform DirectionalLights {
DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
}
directional_lights;
@@ -86,100 +93,97 @@ directional_lights;
#define LIGHTMAP_FLAG_USE_SPECULAR_DIRECTION 2
struct Lightmap {
- mat3 normal_xform;
+ mediump mat3 normal_xform;
};
-layout(set = 0, binding = 7, std140) restrict readonly buffer Lightmaps {
+layout(set = 0, binding = 9, std140) restrict readonly buffer Lightmaps {
Lightmap data[];
}
lightmaps;
struct LightmapCapture {
- vec4 sh[9];
+ mediump vec4 sh[9];
};
-layout(set = 0, binding = 8, std140) restrict readonly buffer LightmapCaptures {
+layout(set = 0, binding = 10, std140) restrict readonly buffer LightmapCaptures {
LightmapCapture data[];
}
lightmap_captures;
-layout(set = 0, binding = 9) uniform texture2D decal_atlas;
-layout(set = 0, binding = 10) uniform texture2D decal_atlas_srgb;
+layout(set = 0, binding = 11) uniform mediump texture2D decal_atlas;
+layout(set = 0, binding = 12) uniform mediump texture2D decal_atlas_srgb;
-layout(set = 0, binding = 11, std430) restrict readonly buffer Decals {
+layout(set = 0, binding = 13, std430) restrict readonly buffer Decals {
DecalData data[];
}
decals;
-layout(set = 0, binding = 12, std430) restrict readonly buffer GlobalVariableData {
- vec4 data[];
+layout(set = 0, binding = 14, std430) restrict readonly buffer GlobalVariableData {
+ highp vec4 data[];
}
global_variables;
/* Set 1: Render Pass (changes per render pass) */
layout(set = 1, binding = 0, std140) uniform SceneData {
- mat4 projection_matrix;
- mat4 inv_projection_matrix;
-
- mat4 camera_matrix;
- mat4 inv_camera_matrix;
+ highp mat4 projection_matrix;
+ highp mat4 inv_projection_matrix;
+ highp mat4 camera_matrix;
+ highp mat4 inv_camera_matrix;
- vec2 viewport_size;
- vec2 screen_pixel_size;
+ // only used for multiview
+ highp mat4 projection_matrix_view[MAX_VIEWS];
+ highp mat4 inv_projection_matrix_view[MAX_VIEWS];
- //use vec4s because std140 doesnt play nice with vec2s, z and w are wasted
- vec4 directional_penumbra_shadow_kernel[32];
- vec4 directional_soft_shadow_kernel[32];
- vec4 penumbra_shadow_kernel[32];
- vec4 soft_shadow_kernel[32];
+ highp vec2 viewport_size;
+ highp vec2 screen_pixel_size;
- uint directional_penumbra_shadow_samples;
- uint directional_soft_shadow_samples;
- uint penumbra_shadow_samples;
- uint soft_shadow_samples;
+ // Use vec4s because std140 doesn't play nice with vec2s, z and w are wasted.
+ highp vec4 directional_penumbra_shadow_kernel[32];
+ highp vec4 directional_soft_shadow_kernel[32];
+ highp vec4 penumbra_shadow_kernel[32];
+ highp vec4 soft_shadow_kernel[32];
- vec4 ambient_light_color_energy;
+ mediump vec4 ambient_light_color_energy;
- float ambient_color_sky_mix;
+ mediump float ambient_color_sky_mix;
bool use_ambient_light;
bool use_ambient_cubemap;
bool use_reflection_cubemap;
- mat3 radiance_inverse_xform;
+ mediump mat3 radiance_inverse_xform;
- vec2 shadow_atlas_pixel_size;
- vec2 directional_shadow_pixel_size;
+ highp vec2 shadow_atlas_pixel_size;
+ highp vec2 directional_shadow_pixel_size;
uint directional_light_count;
- float dual_paraboloid_side;
- float z_far;
- float z_near;
+ mediump float dual_paraboloid_side;
+ highp float z_far;
+ highp float z_near;
bool ssao_enabled;
- float ssao_light_affect;
- float ssao_ao_affect;
+ mediump float ssao_light_affect;
+ mediump float ssao_ao_affect;
bool roughness_limiter_enabled;
- float roughness_limiter_amount;
- float roughness_limiter_limit;
- uvec2 roughness_limiter_pad;
-
- vec4 ao_color;
+ mediump float roughness_limiter_amount;
+ mediump float roughness_limiter_limit;
+ mediump float opaque_prepass_threshold;
+ uint roughness_limiter_pad;
bool fog_enabled;
- float fog_density;
- float fog_height;
- float fog_height_density;
+ highp float fog_density;
+ highp float fog_height;
+ highp float fog_height_density;
- vec3 fog_light_color;
- float fog_sun_scatter;
+ mediump vec3 fog_light_color;
+ mediump float fog_sun_scatter;
- float fog_aerial_perspective;
+ mediump float fog_aerial_perspective;
bool material_uv2_mode;
- float time;
- float reflection_multiplier; // one normally, zero when rendering reflections
+ highp float time;
+ mediump float reflection_multiplier; // one normally, zero when rendering reflections
bool pancake_shadows;
uint pad1;
@@ -190,30 +194,30 @@ scene_data;
#ifdef USE_RADIANCE_CUBEMAP_ARRAY
-layout(set = 1, binding = 2) uniform textureCubeArray radiance_cubemap;
+layout(set = 1, binding = 2) uniform mediump textureCubeArray radiance_cubemap;
#else
-layout(set = 1, binding = 2) uniform textureCube radiance_cubemap;
+layout(set = 1, binding = 2) uniform mediump textureCube radiance_cubemap;
#endif
-layout(set = 1, binding = 3) uniform textureCubeArray reflection_atlas;
+layout(set = 1, binding = 3) uniform mediump textureCubeArray reflection_atlas;
-layout(set = 1, binding = 4) uniform texture2D shadow_atlas;
+layout(set = 1, binding = 4) uniform highp texture2D shadow_atlas;
-layout(set = 1, binding = 5) uniform texture2D directional_shadow_atlas;
+layout(set = 1, binding = 5) uniform highp texture2D directional_shadow_atlas;
// this needs to change to providing just the lightmap we're using..
layout(set = 1, binding = 6) uniform texture2DArray lightmap_textures[MAX_LIGHTMAP_TEXTURES];
-layout(set = 1, binding = 9) uniform texture2D depth_buffer;
-layout(set = 1, binding = 10) uniform texture2D color_buffer;
+layout(set = 1, binding = 9) uniform highp texture2D depth_buffer;
+layout(set = 1, binding = 10) uniform mediump texture2D color_buffer;
/* Set 2 Skeleton & Instancing (can change per item) */
layout(set = 2, binding = 0, std430) restrict readonly buffer Transforms {
- vec4 data[];
+ highp vec4 data[];
}
transforms;
diff --git a/servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl b/servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl
index 7e06516d90..2328effe7b 100644
--- a/servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl
+++ b/servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl
@@ -36,12 +36,12 @@ void main() {
float divisor = 0.0;
vec4 color;
float depth;
- vec3 normal;
+ vec4 normal;
if (params.filtered) {
color = vec4(0.0);
depth = 0.0;
- normal = vec3(0.0);
+ normal = vec4(0.0);
for (int i = 0; i < 4; i++) {
ivec2 ofs = ssC << 1;
@@ -53,7 +53,9 @@ void main() {
}
color += texelFetch(source_ssr, ofs, 0);
float d = texelFetch(source_depth, ofs, 0).r;
- normal += texelFetch(source_normal, ofs, 0).xyz * 2.0 - 1.0;
+ vec4 nr = texelFetch(source_normal, ofs, 0);
+ normal.xyz += nr.xyz * 2.0 - 1.0;
+ normal.w += nr.w;
d = d * 2.0 - 1.0;
if (params.orthogonal) {
@@ -66,11 +68,12 @@ void main() {
color /= 4.0;
depth /= 4.0;
- normal = normalize(normal / 4.0) * 0.5 + 0.5;
+ normal.xyz = normalize(normal.xyz / 4.0) * 0.5 + 0.5;
+ normal.w /= 4.0;
} else {
color = texelFetch(source_ssr, ssC << 1, 0);
depth = texelFetch(source_depth, ssC << 1, 0).r;
- normal = texelFetch(source_normal, ssC << 1, 0).xyz;
+ normal = texelFetch(source_normal, ssC << 1, 0);
depth = depth * 2.0 - 1.0;
if (params.orthogonal) {
@@ -83,5 +86,5 @@ void main() {
imageStore(dest_ssr, ssC, color);
imageStore(dest_depth, ssC, vec4(depth));
- imageStore(dest_normal, ssC, vec4(normal, 0.0));
+ imageStore(dest_normal, ssC, normal);
}
diff --git a/servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl
index 0eacbc5363..4290d5b869 100644
--- a/servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl
+++ b/servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl
@@ -24,7 +24,7 @@ layout(push_constant, binding = 0, std430) uniform Params {
}
params;
-// http://in4k.untergrund.net/html_articles/hugi_27_-_coding_corner_polaris_sphere_tessellation_101.htm
+// https://in4k.untergrund.net/html_articles/hugi_27_-_coding_corner_polaris_sphere_tessellation_101.htm
vec3 get_sphere_vertex(uint p_vertex_id) {
float x_angle = float(p_vertex_id & 1u) + (p_vertex_id >> params.band_power);
diff --git a/servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl
index 99db35bb34..d6e5c6a92e 100644
--- a/servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl
+++ b/servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl
@@ -20,10 +20,10 @@ layout(set = 0, binding = 3, std430) restrict readonly buffer DispatchData {
dispatch_data;
struct ProcessVoxel {
- uint position; //xyz 7 bit packed, extra 11 bits for neigbours
- uint albedo; //rgb bits 0-15 albedo, bits 16-21 are normal bits (set if geometry exists toward that side), extra 11 bits for neibhbours
- uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbours
- uint light_aniso; //55555 light anisotropy, extra 2 bits for neighbours
+ uint position; // xyz 7 bit packed, extra 11 bits for neighbors.
+ uint albedo; // rgb bits 0-15 albedo, bits 16-21 are normal bits (set if geometry exists toward that side), extra 11 bits for neighbors.
+ uint light; // rgbe8985 encoded total saved light, extra 2 bits for neighbors.
+ uint light_aniso; // 55555 light anisotropy, extra 2 bits for neighbors.
//total neighbours: 26
};
diff --git a/servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl
index bc376e9522..eedd28959c 100644
--- a/servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl
+++ b/servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl
@@ -266,9 +266,9 @@ void main() {
} else if (params.sky_mode == SKY_MODE_SKY) {
#ifdef USE_CUBEMAP_ARRAY
- light.rgb = textureLod(samplerCubeArray(sky_irradiance, linear_sampler_mipmaps), vec4(ray_dir, 0.0), 2.0).rgb; //use second mipmap because we dont usually throw a lot of rays, so this compensates
+ light.rgb = textureLod(samplerCubeArray(sky_irradiance, linear_sampler_mipmaps), vec4(ray_dir, 0.0), 2.0).rgb; // Use second mipmap because we don't usually throw a lot of rays, so this compensates.
#else
- light.rgb = textureLod(samplerCube(sky_irradiance, linear_sampler_mipmaps), ray_dir, 2.0).rgb; //use second mipmap because we dont usually throw a lot of rays, so this compensates
+ light.rgb = textureLod(samplerCube(sky_irradiance, linear_sampler_mipmaps), ray_dir, 2.0).rgb; // Use second mipmap because we don't usually throw a lot of rays, so this compensates.
#endif
light.rgb *= params.sky_energy;
light.a = 0.0;
diff --git a/servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl
index aa4ded146f..4d9fa85a74 100644
--- a/servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl
+++ b/servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl
@@ -101,7 +101,7 @@ layout(set = 0, binding = 10, std430) restrict buffer DispatchData {
dispatch_data;
struct ProcessVoxel {
- uint position; //xyz 7 bit packed, extra 11 bits for neigbours
+ uint position; // xyz 7 bit packed, extra 11 bits for neighbors.
uint albedo; //rgb bits 0-15 albedo, bits 16-21 are normal bits (set if geometry exists toward that side), extra 11 bits for neibhbours
uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbours
uint light_aniso; //55555 light anisotropy, extra 2 bits for neighbours
@@ -134,7 +134,7 @@ layout(set = 0, binding = 5, std430) restrict buffer readonly DispatchData {
dispatch_data;
struct ProcessVoxel {
- uint position; //xyz 7 bit packed, extra 11 bits for neigbours
+ uint position; // xyz 7 bit packed, extra 11 bits for neighbors.
uint albedo; //rgb bits 0-15 albedo, bits 16-21 are normal bits (set if geometry exists toward that side), extra 11 bits for neibhbours
uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbours
uint light_aniso; //55555 light anisotropy, extra 2 bits for neighbours
@@ -183,7 +183,7 @@ void main() {
ivec3 write_pos = read_pos + params.scroll;
if (any(lessThan(write_pos, ivec3(0))) || any(greaterThanEqual(write_pos, ivec3(params.grid_size)))) {
- return; //fits outside the 3D texture, dont do anything
+ return; // Fits outside the 3D texture, don't do anything.
}
uint albedo = ((src_process_voxels.data[index].albedo & 0x7FFF) << 1) | 1; //add solid bit
diff --git a/servers/rendering/renderer_rd/shaders/sky.glsl b/servers/rendering/renderer_rd/shaders/sky.glsl
index 9924da37d5..d07a454ade 100644
--- a/servers/rendering/renderer_rd/shaders/sky.glsl
+++ b/servers/rendering/renderer_rd/shaders/sky.glsl
@@ -4,13 +4,21 @@
#VERSION_DEFINES
+#define MAX_VIEWS 2
+
+#if defined(USE_MULTIVIEW) && defined(has_VK_KHR_multiview)
+#extension GL_EXT_multiview : enable
+#endif
+
layout(location = 0) out vec2 uv_interp;
layout(push_constant, binding = 1, std430) uniform Params {
mat3 orientation;
- vec4 proj;
+ vec4 projections[MAX_VIEWS];
vec4 position_multiplier;
float time;
+ float luminance_multiplier;
+ float pad[2];
}
params;
@@ -26,15 +34,31 @@ void main() {
#VERSION_DEFINES
+#ifdef USE_MULTIVIEW
+#ifdef has_VK_KHR_multiview
+#extension GL_EXT_multiview : enable
+#define ViewIndex gl_ViewIndex
+#else // has_VK_KHR_multiview
+// !BAS! This needs to become an input once we implement our fallback!
+#define ViewIndex 0
+#endif // has_VK_KHR_multiview
+#else // USE_MULTIVIEW
+// Set to zero, not supported in non stereo
+#define ViewIndex 0
+#endif //USE_MULTIVIEW
+
#define M_PI 3.14159265359
+#define MAX_VIEWS 2
layout(location = 0) in vec2 uv_interp;
layout(push_constant, binding = 1, std430) uniform Params {
mat3 orientation;
- vec4 proj;
+ vec4 projections[MAX_VIEWS];
vec4 position_multiplier;
- float time; //TODO consider adding vec2 screen res, and float radiance size
+ float time;
+ float luminance_multiplier;
+ float pad[2];
}
params;
@@ -85,7 +109,6 @@ struct DirectionalLightData {
layout(set = 0, binding = 3, std140) uniform DirectionalLights {
DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
}
-
directional_lights;
#ifdef MATERIAL_UNIFORMS_USED
@@ -154,8 +177,8 @@ vec4 fog_process(vec3 view, vec3 sky_color) {
void main() {
vec3 cube_normal;
cube_normal.z = -1.0;
- cube_normal.x = (cube_normal.z * (-uv_interp.x - params.proj.x)) / params.proj.y;
- cube_normal.y = -(cube_normal.z * (-uv_interp.y - params.proj.z)) / params.proj.w;
+ cube_normal.x = (cube_normal.z * (-uv_interp.x - params.projections[ViewIndex].x)) / params.projections[ViewIndex].y;
+ cube_normal.y = -(cube_normal.z * (-uv_interp.y - params.projections[ViewIndex].z)) / params.projections[ViewIndex].w;
cube_normal = mat3(params.orientation) * cube_normal;
cube_normal.z = -cube_normal.z;
cube_normal = normalize(cube_normal);
@@ -180,17 +203,17 @@ void main() {
vec3 inverted_cube_normal = cube_normal;
inverted_cube_normal.z *= -1.0;
#ifdef USES_HALF_RES_COLOR
- half_res_color = texture(samplerCube(half_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), inverted_cube_normal);
+ half_res_color = texture(samplerCube(half_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), inverted_cube_normal) * params.luminance_multiplier;
#endif
#ifdef USES_QUARTER_RES_COLOR
- quarter_res_color = texture(samplerCube(quarter_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), inverted_cube_normal);
+ quarter_res_color = texture(samplerCube(quarter_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), inverted_cube_normal) * params.luminance_multiplier;
#endif
#else
#ifdef USES_HALF_RES_COLOR
- half_res_color = textureLod(sampler2D(half_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0);
+ half_res_color = textureLod(sampler2D(half_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0) * params.luminance_multiplier;
#endif
#ifdef USES_QUARTER_RES_COLOR
- quarter_res_color = textureLod(sampler2D(quarter_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0);
+ quarter_res_color = textureLod(sampler2D(quarter_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0) * params.luminance_multiplier;
#endif
#endif
@@ -227,4 +250,7 @@ void main() {
if (!AT_CUBEMAP_PASS && !AT_HALF_RES_PASS && !AT_QUARTER_RES_PASS) {
frag_color.a = 0.0;
}
+
+ // For mobile renderer we're dividing by 2.0 as we're using a UNORM buffer
+ frag_color.rgb = frag_color.rgb / params.luminance_multiplier;
}
diff --git a/servers/rendering/renderer_rd/shaders/tonemap.glsl b/servers/rendering/renderer_rd/shaders/tonemap.glsl
index 86b4da6b08..948c6e1e39 100644
--- a/servers/rendering/renderer_rd/shaders/tonemap.glsl
+++ b/servers/rendering/renderer_rd/shaders/tonemap.glsl
@@ -4,6 +4,12 @@
#VERSION_DEFINES
+#ifdef MULTIVIEW
+#ifdef has_VK_KHR_multiview
+#extension GL_EXT_multiview : enable
+#endif
+#endif
+
layout(location = 0) out vec2 uv_interp;
void main() {
@@ -18,11 +24,28 @@ void main() {
#VERSION_DEFINES
+#ifdef MULTIVIEW
+#ifdef has_VK_KHR_multiview
+#extension GL_EXT_multiview : enable
+#define ViewIndex gl_ViewIndex
+#else // has_VK_KHR_multiview
+#define ViewIndex 0
+#endif // has_VK_KHR_multiview
+#endif //MULTIVIEW
+
layout(location = 0) in vec2 uv_interp;
+#ifdef SUBPASS
+layout(input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput input_color;
+#elif defined(MULTIVIEW)
+layout(set = 0, binding = 0) uniform sampler2DArray source_color;
+#else
layout(set = 0, binding = 0) uniform sampler2D source_color;
+#endif
+
layout(set = 1, binding = 0) uniform sampler2D source_auto_exposure;
layout(set = 2, binding = 0) uniform sampler2D source_glow;
+
#ifdef USE_1D_LUT
layout(set = 3, binding = 0) uniform sampler2D source_color_correction;
#else
@@ -48,7 +71,7 @@ layout(push_constant, binding = 1, std430) uniform Params {
float exposure;
float white;
float auto_exposure_grey;
- uint pad2;
+ float luminance_multiplier;
vec2 pixel_size;
bool use_fxaa;
@@ -117,7 +140,7 @@ vec4 texture2D_bicubic(sampler2D tex, vec2 uv, int p_lod) {
vec2 p3 = (vec2(iuv.x + h1x, iuv.y + h1y) - vec2(0.5f)) * pixel_size;
return (g0(fuv.y) * (g0x * textureLod(tex, p0, lod) + g1x * textureLod(tex, p1, lod))) +
- (g1(fuv.y) * (g0x * textureLod(tex, p2, lod) + g1x * textureLod(tex, p3, lod)));
+ (g1(fuv.y) * (g0x * textureLod(tex, p2, lod) + g1x * textureLod(tex, p3, lod)));
}
#define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) texture2D_bicubic(m_tex, m_uv, m_lod)
@@ -146,25 +169,38 @@ vec3 tonemap_filmic(vec3 color, float white) {
return color_tonemapped / white_tonemapped;
}
+// Adapted from https://github.com/TheRealMJP/BakingLab/blob/master/BakingLab/ACES.hlsl
+// (MIT License).
vec3 tonemap_aces(vec3 color, float white) {
- const float exposure_bias = 0.85f;
- const float A = 2.51f * exposure_bias * exposure_bias;
- const float B = 0.03f * exposure_bias;
- const float C = 2.43f * exposure_bias * exposure_bias;
- const float D = 0.59f * exposure_bias;
- const float E = 0.14f;
-
- vec3 color_tonemapped = (color * (A * color + B)) / (color * (C * color + D) + E);
- float white_tonemapped = (white * (A * white + B)) / (white * (C * white + D) + E);
+ const float exposure_bias = 1.8f;
+ const float A = 0.0245786f;
+ const float B = 0.000090537f;
+ const float C = 0.983729f;
+ const float D = 0.432951f;
+ const float E = 0.238081f;
+
+ // Exposure bias baked into transform to save shader instructions. Equivalent to `color *= exposure_bias`
+ const mat3 rgb_to_rrt = mat3(
+ vec3(0.59719f * exposure_bias, 0.35458f * exposure_bias, 0.04823f * exposure_bias),
+ vec3(0.07600f * exposure_bias, 0.90834f * exposure_bias, 0.01566f * exposure_bias),
+ vec3(0.02840f * exposure_bias, 0.13383f * exposure_bias, 0.83777f * exposure_bias));
+
+ const mat3 odt_to_rgb = mat3(
+ vec3(1.60475f, -0.53108f, -0.07367f),
+ vec3(-0.10208f, 1.10813f, -0.00605f),
+ vec3(-0.00327f, -0.07276f, 1.07602f));
+
+ color *= rgb_to_rrt;
+ vec3 color_tonemapped = (color * (color + A) - B) / (color * (C * color + D) + E);
+ color_tonemapped *= odt_to_rgb;
+
+ white *= exposure_bias;
+ float white_tonemapped = (white * (white + A) - B) / (white * (C * white + D) + E);
return color_tonemapped / white_tonemapped;
}
vec3 tonemap_reinhard(vec3 color, float white) {
- // Ensure color values are positive.
- // They can be negative in the case of negative lights, which leads to undesired behavior.
- color = max(vec3(0.0), color);
-
return (white * color + color) / (color * white + white);
}
@@ -181,15 +217,16 @@ vec3 linear_to_srgb(vec3 color) {
#define TONEMAPPER_ACES 3
vec3 apply_tonemapping(vec3 color, float white) { // inputs are LINEAR, always outputs clamped [0;1] color
-
+ // Ensure color values passed to tonemappers are positive.
+ // They can be negative in the case of negative lights, which leads to undesired behavior.
if (params.tonemapper == TONEMAPPER_LINEAR) {
return color;
} else if (params.tonemapper == TONEMAPPER_REINHARD) {
- return tonemap_reinhard(color, white);
+ return tonemap_reinhard(max(vec3(0.0f), color), white);
} else if (params.tonemapper == TONEMAPPER_FILMIC) {
- return tonemap_filmic(color, white);
- } else { //aces
- return tonemap_aces(color, white);
+ return tonemap_filmic(max(vec3(0.0f), color), white);
+ } else { // TONEMAPPER_ACES
+ return tonemap_aces(max(vec3(0.0f), color), white);
}
}
@@ -272,15 +309,23 @@ vec3 apply_color_correction(vec3 color) {
}
#endif
+#ifndef SUBPASS
vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) {
const float FXAA_REDUCE_MIN = (1.0 / 128.0);
const float FXAA_REDUCE_MUL = (1.0 / 8.0);
const float FXAA_SPAN_MAX = 8.0;
- vec3 rgbNW = textureLod(source_color, uv_interp + vec2(-1.0, -1.0) * params.pixel_size, 0.0).xyz * exposure;
- vec3 rgbNE = textureLod(source_color, uv_interp + vec2(1.0, -1.0) * params.pixel_size, 0.0).xyz * exposure;
- vec3 rgbSW = textureLod(source_color, uv_interp + vec2(-1.0, 1.0) * params.pixel_size, 0.0).xyz * exposure;
- vec3 rgbSE = textureLod(source_color, uv_interp + vec2(1.0, 1.0) * params.pixel_size, 0.0).xyz * exposure;
+#ifdef MULTIVIEW
+ vec3 rgbNW = textureLod(source_color, vec3(uv_interp + vec2(-1.0, -1.0) * params.pixel_size, ViewIndex), 0.0).xyz * exposure * params.luminance_multiplier;
+ vec3 rgbNE = textureLod(source_color, vec3(uv_interp + vec2(1.0, -1.0) * params.pixel_size, ViewIndex), 0.0).xyz * exposure * params.luminance_multiplier;
+ vec3 rgbSW = textureLod(source_color, vec3(uv_interp + vec2(-1.0, 1.0) * params.pixel_size, ViewIndex), 0.0).xyz * exposure * params.luminance_multiplier;
+ vec3 rgbSE = textureLod(source_color, vec3(uv_interp + vec2(1.0, 1.0) * params.pixel_size, ViewIndex), 0.0).xyz * exposure * params.luminance_multiplier;
+#else
+ vec3 rgbNW = textureLod(source_color, uv_interp + vec2(-1.0, -1.0) * params.pixel_size, 0.0).xyz * exposure * params.luminance_multiplier;
+ vec3 rgbNE = textureLod(source_color, uv_interp + vec2(1.0, -1.0) * params.pixel_size, 0.0).xyz * exposure * params.luminance_multiplier;
+ vec3 rgbSW = textureLod(source_color, uv_interp + vec2(-1.0, 1.0) * params.pixel_size, 0.0).xyz * exposure * params.luminance_multiplier;
+ vec3 rgbSE = textureLod(source_color, uv_interp + vec2(1.0, 1.0) * params.pixel_size, 0.0).xyz * exposure * params.luminance_multiplier;
+#endif
vec3 rgbM = color;
vec3 luma = vec3(0.299, 0.587, 0.114);
float lumaNW = dot(rgbNW, luma);
@@ -296,17 +341,22 @@ vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) {
dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE));
float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) *
- (0.25 * FXAA_REDUCE_MUL),
+ (0.25 * FXAA_REDUCE_MUL),
FXAA_REDUCE_MIN);
float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce);
dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX),
max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX),
dir * rcpDirMin)) *
- params.pixel_size;
+ params.pixel_size;
- vec3 rgbA = 0.5 * exposure * (textureLod(source_color, uv_interp + dir * (1.0 / 3.0 - 0.5), 0.0).xyz + textureLod(source_color, uv_interp + dir * (2.0 / 3.0 - 0.5), 0.0).xyz);
- vec3 rgbB = rgbA * 0.5 + 0.25 * exposure * (textureLod(source_color, uv_interp + dir * -0.5, 0.0).xyz + textureLod(source_color, uv_interp + dir * 0.5, 0.0).xyz);
+#ifdef MULTIVIEW
+ vec3 rgbA = 0.5 * exposure * (textureLod(source_color, vec3(uv_interp + dir * (1.0 / 3.0 - 0.5), ViewIndex), 0.0).xyz + textureLod(source_color, vec3(uv_interp + dir * (2.0 / 3.0 - 0.5), ViewIndex), 0.0).xyz) * params.luminance_multiplier;
+ vec3 rgbB = rgbA * 0.5 + 0.25 * exposure * (textureLod(source_color, vec3(uv_interp + dir * -0.5, ViewIndex), 0.0).xyz + textureLod(source_color, vec3(uv_interp + dir * 0.5, ViewIndex), 0.0).xyz) * params.luminance_multiplier;
+#else
+ vec3 rgbA = 0.5 * exposure * (textureLod(source_color, uv_interp + dir * (1.0 / 3.0 - 0.5), 0.0).xyz + textureLod(source_color, uv_interp + dir * (2.0 / 3.0 - 0.5), 0.0).xyz) * params.luminance_multiplier;
+ vec3 rgbB = rgbA * 0.5 + 0.25 * exposure * (textureLod(source_color, uv_interp + dir * -0.5, 0.0).xyz + textureLod(source_color, uv_interp + dir * 0.5, 0.0).xyz) * params.luminance_multiplier;
+#endif
float lumaB = dot(rgbB, luma);
if ((lumaB < lumaMin) || (lumaB > lumaMax)) {
@@ -315,8 +365,9 @@ vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) {
return rgbB;
}
}
+#endif // !SUBPASS
-// From http://alex.vlachos.com/graphics/Alex_Vlachos_Advanced_VR_Rendering_GDC2015.pdf
+// From https://alex.vlachos.com/graphics/Alex_Vlachos_Advanced_VR_Rendering_GDC2015.pdf
// and https://www.shadertoy.com/view/MslGR8 (5th one starting from the bottom)
// NOTE: `frag_coord` is in pixels (i.e. not normalized UV).
vec3 screen_space_dither(vec2 frag_coord) {
@@ -329,41 +380,54 @@ vec3 screen_space_dither(vec2 frag_coord) {
}
void main() {
- vec3 color = textureLod(source_color, uv_interp, 0.0f).rgb;
+#ifdef SUBPASS
+ // SUBPASS and MULTIVIEW can be combined but in that case we're already reading from the correct layer
+ vec3 color = subpassLoad(input_color).rgb * params.luminance_multiplier;
+#elif defined(MULTIVIEW)
+ vec3 color = textureLod(source_color, vec3(uv_interp, ViewIndex), 0.0f).rgb * params.luminance_multiplier;
+#else
+ vec3 color = textureLod(source_color, uv_interp, 0.0f).rgb * params.luminance_multiplier;
+#endif
// Exposure
float exposure = params.exposure;
+#ifndef SUBPASS
if (params.use_auto_exposure) {
- exposure *= 1.0 / (texelFetch(source_auto_exposure, ivec2(0, 0), 0).r / params.auto_exposure_grey);
+ exposure *= 1.0 / (texelFetch(source_auto_exposure, ivec2(0, 0), 0).r * params.luminance_multiplier / params.auto_exposure_grey);
}
+#endif
color *= exposure;
// Early Tonemap & SRGB Conversion
-
+#ifndef SUBPASS
if (params.use_glow && params.glow_mode == GLOW_MODE_MIX) {
- vec3 glow = gather_glow(source_glow, uv_interp);
+ vec3 glow = gather_glow(source_glow, uv_interp) * params.luminance_multiplier;
color.rgb = mix(color.rgb, glow, params.glow_intensity);
}
if (params.use_fxaa) {
color = do_fxaa(color, exposure, uv_interp);
}
+#endif
+
if (params.use_debanding) {
// For best results, debanding should be done before tonemapping.
// Otherwise, we're adding noise to an already-quantized image.
color += screen_space_dither(gl_FragCoord.xy);
}
+
color = apply_tonemapping(color, params.white);
color = linear_to_srgb(color); // regular linear -> SRGB conversion
+#ifndef SUBPASS
// Glow
if (params.use_glow && params.glow_mode != GLOW_MODE_MIX) {
- vec3 glow = gather_glow(source_glow, uv_interp) * params.glow_intensity;
+ vec3 glow = gather_glow(source_glow, uv_interp) * params.glow_intensity * params.luminance_multiplier;
// high dynamic range -> SRGB
glow = apply_tonemapping(glow, params.white);
@@ -371,6 +435,7 @@ void main() {
color = apply_glow(color, glow);
}
+#endif
// Additional effects
diff --git a/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl b/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl
index c793b6ebe1..181d3b272f 100644
--- a/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl
+++ b/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl
@@ -4,219 +4,103 @@
#VERSION_DEFINES
-/* Do not use subgroups here, seems there is not much advantage and causes glitches
-#if defined(has_GL_KHR_shader_subgroup_ballot) && defined(has_GL_KHR_shader_subgroup_arithmetic)
-#extension GL_KHR_shader_subgroup_ballot: enable
-#extension GL_KHR_shader_subgroup_arithmetic: enable
-
-#define USE_SUBGROUPS
-#endif
-*/
-
-#if defined(MODE_FOG) || defined(MODE_FILTER)
-
-layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
-
-#endif
-
-#if defined(MODE_DENSITY)
-
layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;
-#endif
+#define SAMPLER_NEAREST_CLAMP 0
+#define SAMPLER_LINEAR_CLAMP 1
+#define SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP 2
+#define SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP 3
+#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_CLAMP 4
+#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_CLAMP 5
+#define SAMPLER_NEAREST_REPEAT 6
+#define SAMPLER_LINEAR_REPEAT 7
+#define SAMPLER_NEAREST_WITH_MIPMAPS_REPEAT 8
+#define SAMPLER_LINEAR_WITH_MIPMAPS_REPEAT 9
+#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10
+#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11
+
+#define DENSITY_SCALE 1024.0
#include "cluster_data_inc.glsl"
#include "light_data_inc.glsl"
#define M_PI 3.14159265359
-layout(set = 0, binding = 1) uniform texture2D shadow_atlas;
-layout(set = 0, binding = 2) uniform texture2D directional_shadow_atlas;
-
-layout(set = 0, binding = 3, std430) restrict readonly buffer OmniLights {
- LightData data[];
-}
-omni_lights;
-
-layout(set = 0, binding = 4, std430) restrict readonly buffer SpotLights {
- LightData data[];
-}
-spot_lights;
+layout(set = 0, binding = 1) uniform sampler material_samplers[12];
-layout(set = 0, binding = 5, std140) uniform DirectionalLights {
- DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
+layout(set = 0, binding = 2, std430) restrict readonly buffer GlobalVariableData {
+ vec4 data[];
}
-directional_lights;
-
-layout(set = 0, binding = 6, std430) buffer restrict readonly ClusterBuffer {
- uint data[];
-}
-cluster_buffer;
-
-layout(set = 0, binding = 7) uniform sampler linear_sampler;
-
-#ifdef MODE_DENSITY
-layout(rgba16f, set = 0, binding = 8) uniform restrict writeonly image3D density_map;
-layout(rgba16f, set = 0, binding = 9) uniform restrict readonly image3D fog_map; //unused
-#endif
-
-#ifdef MODE_FOG
-layout(rgba16f, set = 0, binding = 8) uniform restrict readonly image3D density_map;
-layout(rgba16f, set = 0, binding = 9) uniform restrict writeonly image3D fog_map;
-#endif
-
-#ifdef MODE_FILTER
-layout(rgba16f, set = 0, binding = 8) uniform restrict readonly image3D source_map;
-layout(rgba16f, set = 0, binding = 9) uniform restrict writeonly image3D dest_map;
-#endif
-
-layout(set = 0, binding = 10) uniform sampler shadow_sampler;
-
-#define MAX_GI_PROBES 8
-
-struct GIProbeData {
- mat4 xform;
- vec3 bounds;
- float dynamic_range;
+global_variables;
- float bias;
- float normal_bias;
- bool blend_ambient;
- uint texture_slot;
-
- float anisotropy_strength;
- float ambient_occlusion;
- float ambient_occlusion_size;
- uint mipmaps;
-};
-
-layout(set = 0, binding = 11, std140) uniform GIProbes {
- GIProbeData data[MAX_GI_PROBES];
-}
-gi_probes;
-
-layout(set = 0, binding = 12) uniform texture3D gi_probe_textures[MAX_GI_PROBES];
-
-layout(set = 0, binding = 13) uniform sampler linear_sampler_with_mipmaps;
-
-#ifdef ENABLE_SDFGI
-
-// SDFGI Integration on set 1
-#define SDFGI_MAX_CASCADES 8
-
-struct SDFGIProbeCascadeData {
+layout(push_constant, binding = 0, std430) uniform Params {
vec3 position;
- float to_probe;
- ivec3 probe_world_offset;
- float to_cell; // 1/bounds * grid_size
-};
-
-layout(set = 1, binding = 0, std140) uniform SDFGI {
- vec3 grid_size;
- uint max_cascades;
-
- bool use_occlusion;
- int probe_axis_size;
- float probe_to_uvw;
- float normal_bias;
+ float pad;
- vec3 lightprobe_tex_pixel_size;
- float energy;
+ vec3 extents;
+ float pad2;
- vec3 lightprobe_uv_offset;
- float y_mult;
+ ivec3 corner;
+ uint shape;
- vec3 occlusion_clamp;
- uint pad3;
-
- vec3 occlusion_renormalize;
- uint pad4;
-
- vec3 cascade_probe_size;
- uint pad5;
-
- SDFGIProbeCascadeData cascades[SDFGI_MAX_CASCADES];
+ mat4 transform;
}
-sdfgi;
-
-layout(set = 1, binding = 1) uniform texture2DArray sdfgi_ambient_texture;
-
-layout(set = 1, binding = 2) uniform texture3D sdfgi_occlusion_texture;
+params;
-#endif //SDFGI
+#ifdef MOLTENVK_USED
+layout(set = 1, binding = 1) volatile buffer emissive_only_map_buffer {
+ uint emissive_only_map[];
+};
+#else
+layout(r32ui, set = 1, binding = 1) uniform volatile uimage3D emissive_only_map;
+#endif
-layout(set = 0, binding = 14, std140) uniform Params {
+layout(set = 1, binding = 2, std140) uniform SceneParams {
vec2 fog_frustum_size_begin;
vec2 fog_frustum_size_end;
float fog_frustum_end;
- float z_near;
- float z_far;
- int filter_axis;
+ float z_near; //
+ float z_far; //
+ float time;
ivec3 fog_volume_size;
- uint directional_light_count;
-
- vec3 light_color;
- float base_density;
-
- float detail_spread;
- float gi_inject;
- uint max_gi_probes;
- uint cluster_type_size;
+ uint directional_light_count; //
- vec2 screen_size;
- uint cluster_shift;
- uint cluster_width;
-
- uint max_cluster_element_count_div_32;
bool use_temporal_reprojection;
uint temporal_frame;
+ float detail_spread;
float temporal_blend;
- mat3x4 cam_rotation;
mat4 to_prev_view;
+ mat4 transform;
}
-params;
-
-layout(set = 0, binding = 15) uniform texture3D prev_density_texture;
+scene_params;
-float get_depth_at_pos(float cell_depth_size, int z) {
- float d = float(z) * cell_depth_size + cell_depth_size * 0.5; //center of voxels
- d = pow(d, params.detail_spread);
- return params.fog_frustum_end * d;
-}
-
-vec3 hash3f(uvec3 x) {
- x = ((x >> 16) ^ x) * 0x45d9f3b;
- x = ((x >> 16) ^ x) * 0x45d9f3b;
- x = (x >> 16) ^ x;
- return vec3(x & 0xFFFFF) / vec3(float(0xFFFFF));
-}
-
-float get_omni_attenuation(float distance, float inv_range, float decay) {
- float nd = distance * inv_range;
- nd *= nd;
- nd *= nd; // nd^4
- nd = max(1.0 - nd, 0.0);
- nd *= nd; // nd^2
- return nd * pow(max(distance, 0.0001), -decay);
-}
+#ifdef MOLTENVK_USED
+layout(set = 1, binding = 3) volatile buffer density_only_map_buffer {
+ uint density_only_map[];
+};
+layout(set = 1, binding = 4) volatile buffer light_only_map_buffer {
+ uint light_only_map[];
+};
+#else
+layout(r32ui, set = 1, binding = 3) uniform volatile uimage3D density_only_map;
+layout(r32ui, set = 1, binding = 4) uniform volatile uimage3D light_only_map;
+#endif
-void cluster_get_item_range(uint p_offset, out uint item_min, out uint item_max, out uint item_from, out uint item_to) {
- uint item_min_max = cluster_buffer.data[p_offset];
- item_min = item_min_max & 0xFFFF;
- item_max = item_min_max >> 16;
- ;
+#ifdef MATERIAL_UNIFORMS_USED
+layout(set = 2, binding = 0, std140) uniform MaterialUniforms{
+#MATERIAL_UNIFORMS
+} material;
+#endif
- item_from = item_min >> 5;
- item_to = (item_max == 0) ? 0 : ((item_max - 1) >> 5) + 1; //side effect of how it is stored, as item_max 0 means no elements
-}
+#GLOBALS
-uint cluster_get_range_clip_mask(uint i, uint z_min, uint z_max) {
- int local_min = clamp(int(z_min) - int(i) * 32, 0, 31);
- int mask_width = min(int(z_max) - int(z_min), 32 - local_min);
- return bitfieldInsert(uint(0), uint(0xFFFFFFFF), local_min, mask_width);
+float get_depth_at_pos(float cell_depth_size, int z) {
+ float d = float(z) * cell_depth_size + cell_depth_size * 0.5; //center of voxels
+ d = pow(d, scene_params.detail_spread);
+ return scene_params.fog_frustum_end * d;
}
#define TEMPORAL_FRAMES 16
@@ -240,464 +124,167 @@ const vec3 halton_map[TEMPORAL_FRAMES] = vec3[](
vec3(0.03125, 0.59259259, 0.32));
void main() {
- vec3 fog_cell_size = 1.0 / vec3(params.fog_volume_size);
+ vec3 fog_cell_size = 1.0 / vec3(scene_params.fog_volume_size);
-#ifdef MODE_DENSITY
-
- ivec3 pos = ivec3(gl_GlobalInvocationID.xyz);
- if (any(greaterThanEqual(pos, params.fog_volume_size))) {
+ ivec3 pos = ivec3(gl_GlobalInvocationID.xyz) + params.corner;
+ if (any(greaterThanEqual(pos, scene_params.fog_volume_size))) {
return; //do not compute
}
+#ifdef MOLTENVK_USED
+ uint lpos = pos.z * scene_params.fog_volume_size.x * scene_params.fog_volume_size.y + pos.y * scene_params.fog_volume_size.x + pos.x;
+#endif
vec3 posf = vec3(pos);
- //posf += mix(vec3(0.0),vec3(1.0),0.3) * hash3f(uvec3(pos)) * 2.0 - 1.0;
-
vec3 fog_unit_pos = posf * fog_cell_size + fog_cell_size * 0.5; //center of voxels
-
- uvec2 screen_pos = uvec2(fog_unit_pos.xy * params.screen_size);
- uvec2 cluster_pos = screen_pos >> params.cluster_shift;
- uint cluster_offset = (params.cluster_width * cluster_pos.y + cluster_pos.x) * (params.max_cluster_element_count_div_32 + 32);
- //positions in screen are too spread apart, no hopes for optimizing with subgroups
-
- fog_unit_pos.z = pow(fog_unit_pos.z, params.detail_spread);
+ fog_unit_pos.z = pow(fog_unit_pos.z, scene_params.detail_spread);
vec3 view_pos;
- view_pos.xy = (fog_unit_pos.xy * 2.0 - 1.0) * mix(params.fog_frustum_size_begin, params.fog_frustum_size_end, vec2(fog_unit_pos.z));
- view_pos.z = -params.fog_frustum_end * fog_unit_pos.z;
+ view_pos.xy = (fog_unit_pos.xy * 2.0 - 1.0) * mix(scene_params.fog_frustum_size_begin, scene_params.fog_frustum_size_end, vec2(fog_unit_pos.z));
+ view_pos.z = -scene_params.fog_frustum_end * fog_unit_pos.z;
view_pos.y = -view_pos.y;
- vec4 reprojected_density = vec4(0.0);
- float reproject_amount = 0.0;
-
- if (params.use_temporal_reprojection) {
- vec3 prev_view = (params.to_prev_view * vec4(view_pos, 1.0)).xyz;
+ if (scene_params.use_temporal_reprojection) {
+ vec3 prev_view = (scene_params.to_prev_view * vec4(view_pos, 1.0)).xyz;
//undo transform into prev view
prev_view.y = -prev_view.y;
//z back to unit size
- prev_view.z /= -params.fog_frustum_end;
+ prev_view.z /= -scene_params.fog_frustum_end;
//xy back to unit size
- prev_view.xy /= mix(params.fog_frustum_size_begin, params.fog_frustum_size_end, vec2(prev_view.z));
+ prev_view.xy /= mix(scene_params.fog_frustum_size_begin, scene_params.fog_frustum_size_end, vec2(prev_view.z));
prev_view.xy = prev_view.xy * 0.5 + 0.5;
//z back to unspread value
- prev_view.z = pow(prev_view.z, 1.0 / params.detail_spread);
+ prev_view.z = pow(prev_view.z, 1.0 / scene_params.detail_spread);
if (all(greaterThan(prev_view, vec3(0.0))) && all(lessThan(prev_view, vec3(1.0)))) {
//reprojectinon fits
-
- reprojected_density = textureLod(sampler3D(prev_density_texture, linear_sampler), prev_view, 0.0);
- reproject_amount = params.temporal_blend;
-
// Since we can reproject, now we must jitter the current view pos.
// This is done here because cells that can't reproject should not jitter.
- fog_unit_pos = posf * fog_cell_size + fog_cell_size * halton_map[params.temporal_frame]; //center of voxels, offset by halton table
-
- screen_pos = uvec2(fog_unit_pos.xy * params.screen_size);
- cluster_pos = screen_pos >> params.cluster_shift;
- cluster_offset = (params.cluster_width * cluster_pos.y + cluster_pos.x) * (params.max_cluster_element_count_div_32 + 32);
- //positions in screen are too spread apart, no hopes for optimizing with subgroups
+ fog_unit_pos = posf * fog_cell_size + fog_cell_size * halton_map[scene_params.temporal_frame]; //center of voxels, offset by halton table
+ fog_unit_pos.z = pow(fog_unit_pos.z, scene_params.detail_spread);
- fog_unit_pos.z = pow(fog_unit_pos.z, params.detail_spread);
-
- view_pos.xy = (fog_unit_pos.xy * 2.0 - 1.0) * mix(params.fog_frustum_size_begin, params.fog_frustum_size_end, vec2(fog_unit_pos.z));
- view_pos.z = -params.fog_frustum_end * fog_unit_pos.z;
+ view_pos.xy = (fog_unit_pos.xy * 2.0 - 1.0) * mix(scene_params.fog_frustum_size_begin, scene_params.fog_frustum_size_end, vec2(fog_unit_pos.z));
+ view_pos.z = -scene_params.fog_frustum_end * fog_unit_pos.z;
view_pos.y = -view_pos.y;
}
}
- uint cluster_z = uint(clamp((abs(view_pos.z) / params.z_far) * 32.0, 0.0, 31.0));
-
- vec3 total_light = params.light_color;
+ float density = 0.0;
+ vec3 emission = vec3(0.0);
+ vec3 albedo = vec3(0.0);
- float total_density = params.base_density;
float cell_depth_size = abs(view_pos.z - get_depth_at_pos(fog_cell_size.z, pos.z + 1));
- //compute directional lights
-
- for (uint i = 0; i < params.directional_light_count; i++) {
- vec3 shadow_attenuation = vec3(1.0);
-
- if (directional_lights.data[i].shadow_enabled) {
- float depth_z = -view_pos.z;
-
- vec4 pssm_coord;
- vec3 shadow_color = directional_lights.data[i].shadow_color1.rgb;
- vec3 light_dir = directional_lights.data[i].direction;
- vec4 v = vec4(view_pos, 1.0);
- float z_range;
-
- if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
- pssm_coord = (directional_lights.data[i].shadow_matrix1 * v);
- pssm_coord /= pssm_coord.w;
- z_range = directional_lights.data[i].shadow_z_range.x;
-
- } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
- pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
- pssm_coord /= pssm_coord.w;
- z_range = directional_lights.data[i].shadow_z_range.y;
-
- } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
- pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
- pssm_coord /= pssm_coord.w;
- z_range = directional_lights.data[i].shadow_z_range.z;
-
- } else {
- pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
- pssm_coord /= pssm_coord.w;
- z_range = directional_lights.data[i].shadow_z_range.w;
- }
-
- float depth = texture(sampler2D(directional_shadow_atlas, linear_sampler), pssm_coord.xy).r;
- float shadow = exp(min(0.0, (depth - pssm_coord.z)) * z_range * directional_lights.data[i].shadow_volumetric_fog_fade);
-
- /*
- //float shadow = textureProj(sampler2DShadow(directional_shadow_atlas,shadow_sampler),pssm_coord);
- float shadow = 0.0;
- for(float xi=-1;xi<=1;xi++) {
- for(float yi=-1;yi<=1;yi++) {
- vec2 ofs = vec2(xi,yi) * 1.5 * params.directional_shadow_pixel_size;
- shadow += textureProj(sampler2DShadow(directional_shadow_atlas,shadow_sampler),pssm_coord + vec4(ofs,0.0,0.0));
- }
-
- }
-
- shadow /= 3.0 * 3.0;
-*/
- 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
-
- shadow_attenuation = mix(shadow_color, vec3(1.0), shadow);
- }
-
- total_light += shadow_attenuation * directional_lights.data[i].color * directional_lights.data[i].energy / M_PI;
+ vec4 world = scene_params.transform * vec4(view_pos, 1.0);
+ world.xyz /= world.w;
+
+ vec3 uvw = fog_unit_pos;
+
+ vec4 local_pos = params.transform * world;
+ local_pos.xyz /= local_pos.w;
+
+ float sdf = -1.0;
+ if (params.shape == 0) {
+ //Ellipsoid
+ // https://www.shadertoy.com/view/tdS3DG
+ float k0 = length(local_pos.xyz / params.extents);
+ float k1 = length(local_pos.xyz / (params.extents * params.extents));
+ sdf = k0 * (k0 - 1.0) / k1;
+ } else if (params.shape == 1) {
+ // Box
+ // https://iquilezles.org/www/articles/distfunctions/distfunctions.htm
+ vec3 q = abs(local_pos.xyz) - params.extents;
+ sdf = length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0);
}
- //compute lights from cluster
-
- { //omni lights
-
- uint cluster_omni_offset = cluster_offset;
-
- uint item_min;
- uint item_max;
- uint item_from;
- uint item_to;
-
- cluster_get_item_range(cluster_omni_offset + params.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
-
-#ifdef USE_SUBGROUPS
- item_from = subgroupBroadcastFirst(subgroupMin(item_from));
- item_to = subgroupBroadcastFirst(subgroupMax(item_to));
+ float cull_mask = 1.0; //used to cull cells that do not contribute
+ if (params.shape <= 1) {
+#ifndef SDF_USED
+ cull_mask = 1.0 - smoothstep(-0.1, 0.0, sdf);
#endif
+ uvw = clamp((local_pos.xyz + params.extents) / (2.0 * params.extents), 0.0, 1.0);
+ }
- for (uint i = item_from; i < item_to; i++) {
- uint mask = cluster_buffer.data[cluster_omni_offset + i];
- mask &= cluster_get_range_clip_mask(i, item_min, item_max);
-#ifdef USE_SUBGROUPS
- uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask));
+ if (cull_mask > 0.0) {
+ {
+#CODE : FOG
+ }
+
+#ifdef DENSITY_USED
+ density *= cull_mask;
+ if (abs(density) > 0.001) {
+ int final_density = int(density * DENSITY_SCALE);
+#ifdef MOLTENVK_USED
+ atomicAdd(density_only_map[lpos], uint(final_density));
#else
- uint merged_mask = mask;
+ imageAtomicAdd(density_only_map, pos, uint(final_density));
#endif
- while (merged_mask != 0) {
- uint bit = findMSB(merged_mask);
- merged_mask &= ~(1 << bit);
-#ifdef USE_SUBGROUPS
- if (((1 << bit) & mask) == 0) { //do not process if not originally here
- continue;
- }
+#ifdef EMISSION_USED
+ {
+ emission *= clamp(density, 0.0, 1.0);
+ emission = clamp(emission, vec3(0.0), vec3(4.0));
+ // Scale to fit into R11G11B10 with a range of 0-4
+ uvec3 emission_u = uvec3(emission.r * 511.0, emission.g * 511.0, emission.b * 255.0);
+ // R and G have 11 bits each and B has 10. Then pack them into a 32 bit uint
+ uint final_emission = emission_u.r << 21 | emission_u.g << 10 | emission_u.b;
+#ifdef MOLTENVK_USED
+ uint prev_emission = atomicAdd(emissive_only_map[lpos], final_emission);
+#else
+ uint prev_emission = imageAtomicAdd(emissive_only_map, pos, final_emission);
#endif
- uint light_index = 32 * i + bit;
-
- //if (!bool(omni_omni_lights.data[light_index].mask & draw_call.layer_mask)) {
- // continue; //not masked
- //}
-
- vec3 light_pos = omni_lights.data[light_index].position;
- float d = distance(omni_lights.data[light_index].position, view_pos);
- float shadow_attenuation = 1.0;
-
- if (d * omni_lights.data[light_index].inv_radius < 1.0) {
- float attenuation = get_omni_attenuation(d, omni_lights.data[light_index].inv_radius, omni_lights.data[light_index].attenuation);
-
- vec3 light = omni_lights.data[light_index].color / M_PI;
-
- if (omni_lights.data[light_index].shadow_enabled) {
- //has shadow
- vec4 v = vec4(view_pos, 1.0);
-
- vec4 splane = (omni_lights.data[light_index].shadow_matrix * v);
- float shadow_len = length(splane.xyz); //need to remember shadow len from here
- splane.xyz = normalize(splane.xyz);
- vec4 clamp_rect = omni_lights.data[light_index].atlas_rect;
+ // Adding can lead to colors overflowing, so validate
+ uvec3 prev_emission_u = uvec3(prev_emission >> 21, (prev_emission << 11) >> 21, prev_emission % 1024);
+ uint add_emission = final_emission + prev_emission;
+ uvec3 add_emission_u = uvec3(add_emission >> 21, (add_emission << 11) >> 21, add_emission % 1024);
- if (splane.z >= 0.0) {
- splane.z += 1.0;
+ bvec3 overflowing = lessThan(add_emission_u, prev_emission_u + emission_u);
- clamp_rect.y += clamp_rect.w;
-
- } else {
- splane.z = 1.0 - splane.z;
- }
-
- splane.xy /= splane.z;
-
- splane.xy = splane.xy * 0.5 + 0.5;
- splane.z = shadow_len * omni_lights.data[light_index].inv_radius;
- splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw;
- splane.w = 1.0; //needed? i think it should be 1 already
-
- float depth = texture(sampler2D(shadow_atlas, linear_sampler), splane.xy).r;
-
- shadow_attenuation = exp(min(0.0, (depth - splane.z)) / omni_lights.data[light_index].inv_radius * omni_lights.data[light_index].shadow_volumetric_fog_fade);
- }
- total_light += light * attenuation * shadow_attenuation;
+ if (any(overflowing)) {
+ uvec3 overflow_factor = mix(uvec3(0), uvec3(2047 << 21, 2047 << 10, 1023), overflowing);
+ uint force_max = overflow_factor.r | overflow_factor.g | overflow_factor.b;
+#ifdef MOLTENVK_USED
+ atomicOr(emissive_only_map[lpos], force_max);
+#else
+ imageAtomicOr(emissive_only_map, pos, force_max);
+#endif
}
}
- }
- }
-
- { //spot lights
-
- uint cluster_spot_offset = cluster_offset + params.cluster_type_size;
-
- uint item_min;
- uint item_max;
- uint item_from;
- uint item_to;
-
- cluster_get_item_range(cluster_spot_offset + params.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
-
-#ifdef USE_SUBGROUPS
- item_from = subgroupBroadcastFirst(subgroupMin(item_from));
- item_to = subgroupBroadcastFirst(subgroupMax(item_to));
#endif
-
- for (uint i = item_from; i < item_to; i++) {
- uint mask = cluster_buffer.data[cluster_spot_offset + i];
- mask &= cluster_get_range_clip_mask(i, item_min, item_max);
-#ifdef USE_SUBGROUPS
- uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask));
+#ifdef ALBEDO_USED
+ {
+ vec3 scattering = albedo * clamp(density, 0.0, 1.0);
+ scattering = clamp(scattering, vec3(0.0), vec3(1.0));
+ uvec3 scattering_u = uvec3(scattering.r * 2047.0, scattering.g * 2047.0, scattering.b * 1023.0);
+ // R and G have 11 bits each and B has 10. Then pack them into a 32 bit uint
+ uint final_scattering = scattering_u.r << 21 | scattering_u.g << 10 | scattering_u.b;
+#ifdef MOLTENVK_USED
+ uint prev_scattering = atomicAdd(light_only_map[lpos], final_scattering);
#else
- uint merged_mask = mask;
-#endif
-
- while (merged_mask != 0) {
- uint bit = findMSB(merged_mask);
- merged_mask &= ~(1 << bit);
-#ifdef USE_SUBGROUPS
- if (((1 << bit) & mask) == 0) { //do not process if not originally here
- continue;
- }
+ uint prev_scattering = imageAtomicAdd(light_only_map, pos, final_scattering);
#endif
- //if (!bool(omni_lights.data[light_index].mask & draw_call.layer_mask)) {
- // continue; //not masked
- //}
-
- uint light_index = 32 * i + bit;
-
- vec3 light_pos = spot_lights.data[light_index].position;
- vec3 light_rel_vec = spot_lights.data[light_index].position - view_pos;
- float d = length(light_rel_vec);
- float shadow_attenuation = 1.0;
-
- if (d * spot_lights.data[light_index].inv_radius < 1.0) {
- float attenuation = get_omni_attenuation(d, spot_lights.data[light_index].inv_radius, spot_lights.data[light_index].attenuation);
-
- vec3 spot_dir = spot_lights.data[light_index].direction;
- float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_lights.data[light_index].cone_angle);
- float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_lights.data[light_index].cone_angle));
- attenuation *= 1.0 - pow(spot_rim, spot_lights.data[light_index].cone_attenuation);
-
- vec3 light = spot_lights.data[light_index].color / M_PI;
-
- if (spot_lights.data[light_index].shadow_enabled) {
- //has shadow
- vec4 v = vec4(view_pos, 1.0);
-
- vec4 splane = (spot_lights.data[light_index].shadow_matrix * v);
- splane /= splane.w;
-
- float depth = texture(sampler2D(shadow_atlas, linear_sampler), splane.xy).r;
-
- shadow_attenuation = exp(min(0.0, (depth - splane.z)) / spot_lights.data[light_index].inv_radius * spot_lights.data[light_index].shadow_volumetric_fog_fade);
- }
-
- total_light += light * attenuation * shadow_attenuation;
- }
- }
- }
- }
-
- vec3 world_pos = mat3(params.cam_rotation) * view_pos;
-
- for (uint i = 0; i < params.max_gi_probes; i++) {
- vec3 position = (gi_probes.data[i].xform * vec4(world_pos, 1.0)).xyz;
-
- //this causes corrupted pixels, i have no idea why..
- if (all(bvec2(all(greaterThanEqual(position, vec3(0.0))), all(lessThan(position, gi_probes.data[i].bounds))))) {
- position /= gi_probes.data[i].bounds;
-
- vec4 light = vec4(0.0);
- for (uint j = 0; j < gi_probes.data[i].mipmaps; j++) {
- vec4 slight = textureLod(sampler3D(gi_probe_textures[i], linear_sampler_with_mipmaps), position, float(j));
- float a = (1.0 - light.a);
- light += a * slight;
- }
-
- light.rgb *= gi_probes.data[i].dynamic_range * params.gi_inject;
-
- total_light += light.rgb;
- }
- }
-
- //sdfgi
-#ifdef ENABLE_SDFGI
+ // Adding can lead to colors overflowing, so validate
+ uvec3 prev_scattering_u = uvec3(prev_scattering >> 21, (prev_scattering << 11) >> 21, prev_scattering % 1024);
+ uint add_scattering = final_scattering + prev_scattering;
+ uvec3 add_scattering_u = uvec3(add_scattering >> 21, (add_scattering << 11) >> 21, add_scattering % 1024);
- {
- float blend = -1.0;
- vec3 ambient_total = vec3(0.0);
+ bvec3 overflowing = lessThan(add_scattering_u, prev_scattering_u + scattering_u);
- for (uint i = 0; i < sdfgi.max_cascades; i++) {
- vec3 cascade_pos = (world_pos - sdfgi.cascades[i].position) * sdfgi.cascades[i].to_probe;
-
- if (any(lessThan(cascade_pos, vec3(0.0))) || any(greaterThanEqual(cascade_pos, sdfgi.cascade_probe_size))) {
- continue; //skip cascade
- }
-
- vec3 base_pos = floor(cascade_pos);
- ivec3 probe_base_pos = ivec3(base_pos);
-
- vec4 ambient_accum = vec4(0.0);
-
- ivec3 tex_pos = ivec3(probe_base_pos.xy, int(i));
- tex_pos.x += probe_base_pos.z * sdfgi.probe_axis_size;
-
- for (uint j = 0; j < 8; j++) {
- ivec3 offset = (ivec3(j) >> ivec3(0, 1, 2)) & ivec3(1, 1, 1);
- ivec3 probe_posi = probe_base_pos;
- probe_posi += offset;
-
- // Compute weight
-
- vec3 probe_pos = vec3(probe_posi);
- vec3 probe_to_pos = cascade_pos - probe_pos;
-
- vec3 trilinear = vec3(1.0) - abs(probe_to_pos);
- float weight = trilinear.x * trilinear.y * trilinear.z;
-
- // Compute lightprobe occlusion
-
- if (sdfgi.use_occlusion) {
- ivec3 occ_indexv = abs((sdfgi.cascades[i].probe_world_offset + probe_posi) & ivec3(1, 1, 1)) * ivec3(1, 2, 4);
- vec4 occ_mask = mix(vec4(0.0), vec4(1.0), equal(ivec4(occ_indexv.x | occ_indexv.y), ivec4(0, 1, 2, 3)));
-
- vec3 occ_pos = clamp(cascade_pos, probe_pos - sdfgi.occlusion_clamp, probe_pos + sdfgi.occlusion_clamp) * sdfgi.probe_to_uvw;
- occ_pos.z += float(i);
- if (occ_indexv.z != 0) { //z bit is on, means index is >=4, so make it switch to the other half of textures
- occ_pos.x += 1.0;
- }
-
- occ_pos *= sdfgi.occlusion_renormalize;
- float occlusion = dot(textureLod(sampler3D(sdfgi_occlusion_texture, linear_sampler), occ_pos, 0.0), occ_mask);
-
- weight *= max(occlusion, 0.01);
+ if (any(overflowing)) {
+ uvec3 overflow_factor = mix(uvec3(0), uvec3(2047 << 21, 2047 << 10, 1023), overflowing);
+ uint force_max = overflow_factor.r | overflow_factor.g | overflow_factor.b;
+#ifdef MOLTENVK_USED
+ atomicOr(light_only_map[lpos], force_max);
+#else
+ imageAtomicOr(light_only_map, pos, force_max);
+#endif
}
-
- // Compute ambient texture position
-
- ivec3 uvw = tex_pos;
- uvw.xy += offset.xy;
- uvw.x += offset.z * sdfgi.probe_axis_size;
-
- vec3 ambient = texelFetch(sampler2DArray(sdfgi_ambient_texture, linear_sampler), uvw, 0).rgb;
-
- ambient_accum.rgb += ambient * weight;
- ambient_accum.a += weight;
- }
-
- if (ambient_accum.a > 0) {
- ambient_accum.rgb /= ambient_accum.a;
}
- ambient_total = ambient_accum.rgb;
- break;
+#endif // ALBEDO_USED
}
-
- total_light += ambient_total * params.gi_inject;
+#endif // DENSITY_USED
}
-
-#endif
-
- vec4 final_density = vec4(total_light, total_density);
-
- final_density = mix(final_density, reprojected_density, reproject_amount);
-
- imageStore(density_map, pos, final_density);
-#endif
-
-#ifdef MODE_FOG
-
- ivec3 pos = ivec3(gl_GlobalInvocationID.xy, 0);
-
- if (any(greaterThanEqual(pos, params.fog_volume_size))) {
- return; //do not compute
- }
-
- vec4 fog_accum = vec4(0.0);
- float prev_z = 0.0;
-
- float t = 1.0;
-
- for (int i = 0; i < params.fog_volume_size.z; i++) {
- //compute fog position
- ivec3 fog_pos = pos + ivec3(0, 0, i);
- //get fog value
- vec4 fog = imageLoad(density_map, fog_pos);
-
- //get depth at cell pos
- float z = get_depth_at_pos(fog_cell_size.z, i);
- //get distance from previous pos
- float d = abs(prev_z - z);
- //compute exinction based on beer's
- float extinction = t * exp(-d * fog.a);
- //compute alpha based on different of extinctions
- float alpha = t - extinction;
- //update extinction
- t = extinction;
-
- fog_accum += vec4(fog.rgb * alpha, alpha);
- prev_z = z;
-
- vec4 fog_value;
-
- if (fog_accum.a > 0.0) {
- fog_value = vec4(fog_accum.rgb / fog_accum.a, 1.0 - t);
- } else {
- fog_value = vec4(0.0);
- }
-
- imageStore(fog_map, fog_pos, fog_value);
- }
-
-#endif
-
-#ifdef MODE_FILTER
-
- ivec3 pos = ivec3(gl_GlobalInvocationID.xyz);
-
- const float gauss[7] = float[](0.071303, 0.131514, 0.189879, 0.214607, 0.189879, 0.131514, 0.071303);
-
- const ivec3 filter_dir[3] = ivec3[](ivec3(1, 0, 0), ivec3(0, 1, 0), ivec3(0, 0, 1));
- ivec3 offset = filter_dir[params.filter_axis];
-
- vec4 accum = vec4(0.0);
- for (int i = -3; i <= 3; i++) {
- accum += imageLoad(source_map, clamp(pos + offset * i, ivec3(0), params.fog_volume_size - ivec3(1))) * gauss[i + 3];
- }
-
- imageStore(dest_map, pos, accum);
-
-#endif
}
diff --git a/servers/rendering/renderer_rd/shaders/volumetric_fog_process.glsl b/servers/rendering/renderer_rd/shaders/volumetric_fog_process.glsl
new file mode 100644
index 0000000000..747f88960c
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/volumetric_fog_process.glsl
@@ -0,0 +1,776 @@
+#[compute]
+
+#version 450
+
+#VERSION_DEFINES
+
+/* Do not use subgroups here, seems there is not much advantage and causes glitches
+#if defined(has_GL_KHR_shader_subgroup_ballot) && defined(has_GL_KHR_shader_subgroup_arithmetic)
+#extension GL_KHR_shader_subgroup_ballot: enable
+#extension GL_KHR_shader_subgroup_arithmetic: enable
+
+#define USE_SUBGROUPS
+#endif
+*/
+
+#ifdef MODE_DENSITY
+layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;
+#else
+layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
+#endif
+
+#include "cluster_data_inc.glsl"
+#include "light_data_inc.glsl"
+
+#define M_PI 3.14159265359
+
+#define DENSITY_SCALE 1024.0
+
+layout(set = 0, binding = 1) uniform texture2D shadow_atlas;
+layout(set = 0, binding = 2) uniform texture2D directional_shadow_atlas;
+
+layout(set = 0, binding = 3, std430) restrict readonly buffer OmniLights {
+ LightData data[];
+}
+omni_lights;
+
+layout(set = 0, binding = 4, std430) restrict readonly buffer SpotLights {
+ LightData data[];
+}
+spot_lights;
+
+layout(set = 0, binding = 5, std140) uniform DirectionalLights {
+ DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
+}
+directional_lights;
+
+layout(set = 0, binding = 6, std430) buffer restrict readonly ClusterBuffer {
+ uint data[];
+}
+cluster_buffer;
+
+layout(set = 0, binding = 7) uniform sampler linear_sampler;
+
+#ifdef MODE_DENSITY
+layout(rgba16f, set = 0, binding = 8) uniform restrict writeonly image3D density_map;
+layout(rgba16f, set = 0, binding = 9) uniform restrict readonly image3D fog_map; //unused
+#endif
+
+#ifdef MODE_FOG
+layout(rgba16f, set = 0, binding = 8) uniform restrict readonly image3D density_map;
+layout(rgba16f, set = 0, binding = 9) uniform restrict writeonly image3D fog_map;
+#endif
+
+#ifdef MODE_COPY
+layout(rgba16f, set = 0, binding = 8) uniform restrict readonly image3D source_map;
+layout(rgba16f, set = 0, binding = 9) uniform restrict writeonly image3D dest_map;
+#endif
+
+#ifdef MODE_FILTER
+layout(rgba16f, set = 0, binding = 8) uniform restrict readonly image3D source_map;
+layout(rgba16f, set = 0, binding = 9) uniform restrict writeonly image3D dest_map;
+#endif
+
+layout(set = 0, binding = 10) uniform sampler shadow_sampler;
+
+#define MAX_VOXEL_GI_INSTANCES 8
+
+struct VoxelGIData {
+ mat4 xform;
+ vec3 bounds;
+ float dynamic_range;
+
+ float bias;
+ float normal_bias;
+ bool blend_ambient;
+ uint texture_slot;
+
+ float anisotropy_strength;
+ float ambient_occlusion;
+ float ambient_occlusion_size;
+ uint mipmaps;
+};
+
+layout(set = 0, binding = 11, std140) uniform VoxelGIs {
+ VoxelGIData data[MAX_VOXEL_GI_INSTANCES];
+}
+voxel_gi_instances;
+
+layout(set = 0, binding = 12) uniform texture3D voxel_gi_textures[MAX_VOXEL_GI_INSTANCES];
+
+layout(set = 0, binding = 13) uniform sampler linear_sampler_with_mipmaps;
+
+#ifdef ENABLE_SDFGI
+
+// SDFGI Integration on set 1
+#define SDFGI_MAX_CASCADES 8
+
+struct SDFVoxelGICascadeData {
+ vec3 position;
+ float to_probe;
+ ivec3 probe_world_offset;
+ float to_cell; // 1/bounds * grid_size
+};
+
+layout(set = 1, binding = 0, std140) uniform SDFGI {
+ vec3 grid_size;
+ uint max_cascades;
+
+ bool use_occlusion;
+ int probe_axis_size;
+ float probe_to_uvw;
+ float normal_bias;
+
+ vec3 lightprobe_tex_pixel_size;
+ float energy;
+
+ vec3 lightprobe_uv_offset;
+ float y_mult;
+
+ vec3 occlusion_clamp;
+ uint pad3;
+
+ vec3 occlusion_renormalize;
+ uint pad4;
+
+ vec3 cascade_probe_size;
+ uint pad5;
+
+ SDFVoxelGICascadeData cascades[SDFGI_MAX_CASCADES];
+}
+sdfgi;
+
+layout(set = 1, binding = 1) uniform texture2DArray sdfgi_ambient_texture;
+
+layout(set = 1, binding = 2) uniform texture3D sdfgi_occlusion_texture;
+
+#endif //SDFGI
+
+layout(set = 0, binding = 14, std140) uniform Params {
+ vec2 fog_frustum_size_begin;
+ vec2 fog_frustum_size_end;
+
+ float fog_frustum_end;
+ float ambient_inject;
+ float z_far;
+ int filter_axis;
+
+ vec3 ambient_color;
+ float sky_contribution;
+
+ ivec3 fog_volume_size;
+ uint directional_light_count;
+
+ vec3 base_emission;
+ float base_density;
+
+ vec3 base_scattering;
+ float phase_g;
+
+ float detail_spread;
+ float gi_inject;
+ uint max_voxel_gi_instances;
+ uint cluster_type_size;
+
+ vec2 screen_size;
+ uint cluster_shift;
+ uint cluster_width;
+
+ uint max_cluster_element_count_div_32;
+ bool use_temporal_reprojection;
+ uint temporal_frame;
+ float temporal_blend;
+
+ mat3x4 cam_rotation;
+ mat4 to_prev_view;
+
+ mat3 radiance_inverse_xform;
+}
+params;
+#ifndef MODE_COPY
+layout(set = 0, binding = 15) uniform texture3D prev_density_texture;
+
+#ifdef MOLTENVK_USED
+layout(set = 0, binding = 16) buffer density_only_map_buffer {
+ uint density_only_map[];
+};
+layout(set = 0, binding = 17) buffer light_only_map_buffer {
+ uint light_only_map[];
+};
+layout(set = 0, binding = 18) buffer emissive_only_map_buffer {
+ uint emissive_only_map[];
+};
+#else
+layout(r32ui, set = 0, binding = 16) uniform uimage3D density_only_map;
+layout(r32ui, set = 0, binding = 17) uniform uimage3D light_only_map;
+layout(r32ui, set = 0, binding = 18) uniform uimage3D emissive_only_map;
+#endif
+
+#ifdef USE_RADIANCE_CUBEMAP_ARRAY
+layout(set = 0, binding = 19) uniform textureCubeArray sky_texture;
+#else
+layout(set = 0, binding = 19) uniform textureCube sky_texture;
+#endif
+#endif // MODE_COPY
+
+float get_depth_at_pos(float cell_depth_size, int z) {
+ float d = float(z) * cell_depth_size + cell_depth_size * 0.5; //center of voxels
+ d = pow(d, params.detail_spread);
+ return params.fog_frustum_end * d;
+}
+
+vec3 hash3f(uvec3 x) {
+ x = ((x >> 16) ^ x) * 0x45d9f3b;
+ x = ((x >> 16) ^ x) * 0x45d9f3b;
+ x = (x >> 16) ^ x;
+ return vec3(x & 0xFFFFF) / vec3(float(0xFFFFF));
+}
+
+float get_omni_attenuation(float dist, float inv_range, float decay) {
+ float nd = dist * inv_range;
+ nd *= nd;
+ nd *= nd; // nd^4
+ nd = max(1.0 - nd, 0.0);
+ nd *= nd; // nd^2
+ return nd * pow(max(dist, 0.0001), -decay);
+}
+
+void cluster_get_item_range(uint p_offset, out uint item_min, out uint item_max, out uint item_from, out uint item_to) {
+ uint item_min_max = cluster_buffer.data[p_offset];
+ item_min = item_min_max & 0xFFFF;
+ item_max = item_min_max >> 16;
+ ;
+
+ item_from = item_min >> 5;
+ item_to = (item_max == 0) ? 0 : ((item_max - 1) >> 5) + 1; //side effect of how it is stored, as item_max 0 means no elements
+}
+
+uint cluster_get_range_clip_mask(uint i, uint z_min, uint z_max) {
+ int local_min = clamp(int(z_min) - int(i) * 32, 0, 31);
+ int mask_width = min(int(z_max) - int(z_min), 32 - local_min);
+ return bitfieldInsert(uint(0), uint(0xFFFFFFFF), local_min, mask_width);
+}
+
+float henyey_greenstein(float cos_theta, float g) {
+ const float k = 0.0795774715459; // 1 / (4 * PI)
+ return k * (1.0 - g * g) / (pow(1.0 + g * g - 2.0 * g * cos_theta, 1.5));
+}
+
+#define TEMPORAL_FRAMES 16
+
+const vec3 halton_map[TEMPORAL_FRAMES] = vec3[](
+ vec3(0.5, 0.33333333, 0.2),
+ vec3(0.25, 0.66666667, 0.4),
+ vec3(0.75, 0.11111111, 0.6),
+ vec3(0.125, 0.44444444, 0.8),
+ vec3(0.625, 0.77777778, 0.04),
+ vec3(0.375, 0.22222222, 0.24),
+ vec3(0.875, 0.55555556, 0.44),
+ vec3(0.0625, 0.88888889, 0.64),
+ vec3(0.5625, 0.03703704, 0.84),
+ vec3(0.3125, 0.37037037, 0.08),
+ vec3(0.8125, 0.7037037, 0.28),
+ vec3(0.1875, 0.14814815, 0.48),
+ vec3(0.6875, 0.48148148, 0.68),
+ vec3(0.4375, 0.81481481, 0.88),
+ vec3(0.9375, 0.25925926, 0.12),
+ vec3(0.03125, 0.59259259, 0.32));
+
+void main() {
+ vec3 fog_cell_size = 1.0 / vec3(params.fog_volume_size);
+
+#ifdef MODE_DENSITY
+
+ ivec3 pos = ivec3(gl_GlobalInvocationID.xyz);
+ if (any(greaterThanEqual(pos, params.fog_volume_size))) {
+ return; //do not compute
+ }
+#ifdef MOLTENVK_USED
+ uint lpos = pos.z * params.fog_volume_size.x * params.fog_volume_size.y + pos.y * params.fog_volume_size.x + pos.x;
+#endif
+
+ vec3 posf = vec3(pos);
+
+ //posf += mix(vec3(0.0),vec3(1.0),0.3) * hash3f(uvec3(pos)) * 2.0 - 1.0;
+
+ vec3 fog_unit_pos = posf * fog_cell_size + fog_cell_size * 0.5; //center of voxels
+
+ uvec2 screen_pos = uvec2(fog_unit_pos.xy * params.screen_size);
+ uvec2 cluster_pos = screen_pos >> params.cluster_shift;
+ uint cluster_offset = (params.cluster_width * cluster_pos.y + cluster_pos.x) * (params.max_cluster_element_count_div_32 + 32);
+ //positions in screen are too spread apart, no hopes for optimizing with subgroups
+
+ fog_unit_pos.z = pow(fog_unit_pos.z, params.detail_spread);
+
+ vec3 view_pos;
+ view_pos.xy = (fog_unit_pos.xy * 2.0 - 1.0) * mix(params.fog_frustum_size_begin, params.fog_frustum_size_end, vec2(fog_unit_pos.z));
+ view_pos.z = -params.fog_frustum_end * fog_unit_pos.z;
+ view_pos.y = -view_pos.y;
+
+ vec4 reprojected_density = vec4(0.0);
+ float reproject_amount = 0.0;
+
+ if (params.use_temporal_reprojection) {
+ vec3 prev_view = (params.to_prev_view * vec4(view_pos, 1.0)).xyz;
+ //undo transform into prev view
+ prev_view.y = -prev_view.y;
+ //z back to unit size
+ prev_view.z /= -params.fog_frustum_end;
+ //xy back to unit size
+ prev_view.xy /= mix(params.fog_frustum_size_begin, params.fog_frustum_size_end, vec2(prev_view.z));
+ prev_view.xy = prev_view.xy * 0.5 + 0.5;
+ //z back to unspread value
+ prev_view.z = pow(prev_view.z, 1.0 / params.detail_spread);
+
+ if (all(greaterThan(prev_view, vec3(0.0))) && all(lessThan(prev_view, vec3(1.0)))) {
+ //reprojectinon fits
+
+ reprojected_density = textureLod(sampler3D(prev_density_texture, linear_sampler), prev_view, 0.0);
+ reproject_amount = params.temporal_blend;
+
+ // Since we can reproject, now we must jitter the current view pos.
+ // This is done here because cells that can't reproject should not jitter.
+
+ fog_unit_pos = posf * fog_cell_size + fog_cell_size * halton_map[params.temporal_frame]; //center of voxels, offset by halton table
+
+ screen_pos = uvec2(fog_unit_pos.xy * params.screen_size);
+ cluster_pos = screen_pos >> params.cluster_shift;
+ cluster_offset = (params.cluster_width * cluster_pos.y + cluster_pos.x) * (params.max_cluster_element_count_div_32 + 32);
+ //positions in screen are too spread apart, no hopes for optimizing with subgroups
+
+ fog_unit_pos.z = pow(fog_unit_pos.z, params.detail_spread);
+
+ view_pos.xy = (fog_unit_pos.xy * 2.0 - 1.0) * mix(params.fog_frustum_size_begin, params.fog_frustum_size_end, vec2(fog_unit_pos.z));
+ view_pos.z = -params.fog_frustum_end * fog_unit_pos.z;
+ view_pos.y = -view_pos.y;
+ }
+ }
+
+ uint cluster_z = uint(clamp((abs(view_pos.z) / params.z_far) * 32.0, 0.0, 31.0));
+
+ vec3 total_light = vec3(0.0);
+
+ float total_density = params.base_density;
+#ifdef MOLTENVK_USED
+ uint local_density = density_only_map[lpos];
+#else
+ uint local_density = imageLoad(density_only_map, pos).x;
+#endif
+
+ total_density += float(int(local_density)) / DENSITY_SCALE;
+ total_density = max(0.0, total_density);
+
+#ifdef MOLTENVK_USED
+ uint scattering_u = light_only_map[lpos];
+#else
+ uint scattering_u = imageLoad(light_only_map, pos).x;
+#endif
+ vec3 scattering = vec3(scattering_u >> 21, (scattering_u << 11) >> 21, scattering_u % 1024) / vec3(2047.0, 2047.0, 1023.0);
+ scattering += params.base_scattering * params.base_density;
+
+#ifdef MOLTENVK_USED
+ uint emission_u = emissive_only_map[lpos];
+#else
+ uint emission_u = imageLoad(emissive_only_map, pos).x;
+#endif
+ vec3 emission = vec3(emission_u >> 21, (emission_u << 11) >> 21, emission_u % 1024) / vec3(511.0, 511.0, 255.0);
+ emission += params.base_emission * params.base_density;
+
+ float cell_depth_size = abs(view_pos.z - get_depth_at_pos(fog_cell_size.z, pos.z + 1));
+ //compute directional lights
+
+ if (total_density > 0.001) {
+ for (uint i = 0; i < params.directional_light_count; i++) {
+ vec3 shadow_attenuation = vec3(1.0);
+
+ if (directional_lights.data[i].shadow_enabled) {
+ float depth_z = -view_pos.z;
+
+ vec4 pssm_coord;
+ vec3 shadow_color = directional_lights.data[i].shadow_color1.rgb;
+ vec3 light_dir = directional_lights.data[i].direction;
+ vec4 v = vec4(view_pos, 1.0);
+ float z_range;
+
+ if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
+ pssm_coord = (directional_lights.data[i].shadow_matrix1 * v);
+ pssm_coord /= pssm_coord.w;
+ z_range = directional_lights.data[i].shadow_z_range.x;
+
+ } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
+ pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
+ pssm_coord /= pssm_coord.w;
+ z_range = directional_lights.data[i].shadow_z_range.y;
+
+ } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
+ pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
+ pssm_coord /= pssm_coord.w;
+ z_range = directional_lights.data[i].shadow_z_range.z;
+
+ } else {
+ pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
+ pssm_coord /= pssm_coord.w;
+ z_range = directional_lights.data[i].shadow_z_range.w;
+ }
+
+ float depth = texture(sampler2D(directional_shadow_atlas, linear_sampler), pssm_coord.xy).r;
+ float shadow = exp(min(0.0, (depth - pssm_coord.z)) * z_range * directional_lights.data[i].shadow_volumetric_fog_fade);
+
+ 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
+
+ shadow_attenuation = mix(shadow_color, vec3(1.0), shadow);
+ }
+
+ 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);
+ }
+
+ // Compute light from sky
+ if (params.ambient_inject > 0.0) {
+ vec3 isotropic = vec3(0.0);
+ vec3 anisotropic = vec3(0.0);
+ if (params.sky_contribution > 0.0) {
+ float mip_bias = 2.0 + total_density * (MAX_SKY_LOD - 2.0); // Not physically based, but looks nice
+ vec3 scatter_direction = (params.radiance_inverse_xform * normalize(view_pos)) * sign(params.phase_g);
+#ifdef USE_RADIANCE_CUBEMAP_ARRAY
+ isotropic = texture(samplerCubeArray(sky_texture, linear_sampler_with_mipmaps), vec4(0.0, 1.0, 0.0, mip_bias)).rgb;
+ anisotropic = texture(samplerCubeArray(sky_texture, linear_sampler_with_mipmaps), vec4(scatter_direction, mip_bias)).rgb;
+#else
+ isotropic = textureLod(samplerCube(sky_texture, linear_sampler_with_mipmaps), vec3(0.0, 1.0, 0.0), mip_bias).rgb;
+ anisotropic = textureLod(samplerCube(sky_texture, linear_sampler_with_mipmaps), vec3(scatter_direction), mip_bias).rgb;
+#endif //USE_RADIANCE_CUBEMAP_ARRAY
+ }
+
+ total_light += mix(params.ambient_color, mix(isotropic, anisotropic, abs(params.phase_g)), params.sky_contribution) * params.ambient_inject;
+ }
+
+ //compute lights from cluster
+
+ { //omni lights
+
+ uint cluster_omni_offset = cluster_offset;
+
+ uint item_min;
+ uint item_max;
+ uint item_from;
+ uint item_to;
+
+ cluster_get_item_range(cluster_omni_offset + params.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
+
+#ifdef USE_SUBGROUPS
+ item_from = subgroupBroadcastFirst(subgroupMin(item_from));
+ item_to = subgroupBroadcastFirst(subgroupMax(item_to));
+#endif
+
+ for (uint i = item_from; i < item_to; i++) {
+ uint mask = cluster_buffer.data[cluster_omni_offset + i];
+ mask &= cluster_get_range_clip_mask(i, item_min, item_max);
+#ifdef USE_SUBGROUPS
+ uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask));
+#else
+ uint merged_mask = mask;
+#endif
+
+ while (merged_mask != 0) {
+ uint bit = findMSB(merged_mask);
+ merged_mask &= ~(1 << bit);
+#ifdef USE_SUBGROUPS
+ if (((1 << bit) & mask) == 0) { //do not process if not originally here
+ continue;
+ }
+#endif
+ uint light_index = 32 * i + bit;
+
+ //if (!bool(omni_omni_lights.data[light_index].mask & draw_call.layer_mask)) {
+ // continue; //not masked
+ //}
+
+ vec3 light_pos = omni_lights.data[light_index].position;
+ float d = distance(omni_lights.data[light_index].position, view_pos);
+ float shadow_attenuation = 1.0;
+
+ if (d * omni_lights.data[light_index].inv_radius < 1.0) {
+ float attenuation = get_omni_attenuation(d, omni_lights.data[light_index].inv_radius, omni_lights.data[light_index].attenuation);
+
+ vec3 light = omni_lights.data[light_index].color;
+
+ if (omni_lights.data[light_index].shadow_enabled) {
+ //has shadow
+ vec4 uv_rect = omni_lights.data[light_index].atlas_rect;
+ vec2 flip_offset = omni_lights.data[light_index].direction.xy;
+
+ vec3 local_vert = (omni_lights.data[light_index].shadow_matrix * vec4(view_pos, 1.0)).xyz;
+
+ float shadow_len = length(local_vert); //need to remember shadow len from here
+ vec3 shadow_sample = normalize(local_vert);
+
+ if (shadow_sample.z >= 0.0) {
+ uv_rect.xy += flip_offset;
+ }
+
+ shadow_sample.z = 1.0 + abs(shadow_sample.z);
+ vec3 pos = vec3(shadow_sample.xy / shadow_sample.z, shadow_len - omni_lights.data[light_index].shadow_bias);
+ pos.z *= omni_lights.data[light_index].inv_radius;
+
+ pos.xy = pos.xy * 0.5 + 0.5;
+ pos.xy = uv_rect.xy + pos.xy * uv_rect.zw;
+
+ float depth = texture(sampler2D(shadow_atlas, linear_sampler), pos.xy).r;
+
+ shadow_attenuation = exp(min(0.0, (depth - pos.z)) / omni_lights.data[light_index].inv_radius * omni_lights.data[light_index].shadow_volumetric_fog_fade);
+ }
+ total_light += light * attenuation * shadow_attenuation * henyey_greenstein(dot(normalize(light_pos - view_pos), normalize(view_pos)), params.phase_g);
+ }
+ }
+ }
+ }
+
+ { //spot lights
+
+ uint cluster_spot_offset = cluster_offset + params.cluster_type_size;
+
+ uint item_min;
+ uint item_max;
+ uint item_from;
+ uint item_to;
+
+ cluster_get_item_range(cluster_spot_offset + params.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
+
+#ifdef USE_SUBGROUPS
+ item_from = subgroupBroadcastFirst(subgroupMin(item_from));
+ item_to = subgroupBroadcastFirst(subgroupMax(item_to));
+#endif
+
+ for (uint i = item_from; i < item_to; i++) {
+ uint mask = cluster_buffer.data[cluster_spot_offset + i];
+ mask &= cluster_get_range_clip_mask(i, item_min, item_max);
+#ifdef USE_SUBGROUPS
+ uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask));
+#else
+ uint merged_mask = mask;
+#endif
+
+ while (merged_mask != 0) {
+ uint bit = findMSB(merged_mask);
+ merged_mask &= ~(1 << bit);
+#ifdef USE_SUBGROUPS
+ if (((1 << bit) & mask) == 0) { //do not process if not originally here
+ continue;
+ }
+#endif
+
+ //if (!bool(omni_lights.data[light_index].mask & draw_call.layer_mask)) {
+ // continue; //not masked
+ //}
+
+ uint light_index = 32 * i + bit;
+
+ vec3 light_pos = spot_lights.data[light_index].position;
+ vec3 light_rel_vec = spot_lights.data[light_index].position - view_pos;
+ float d = length(light_rel_vec);
+ float shadow_attenuation = 1.0;
+
+ if (d * spot_lights.data[light_index].inv_radius < 1.0) {
+ float attenuation = get_omni_attenuation(d, spot_lights.data[light_index].inv_radius, spot_lights.data[light_index].attenuation);
+
+ vec3 spot_dir = spot_lights.data[light_index].direction;
+ float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_lights.data[light_index].cone_angle);
+ float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_lights.data[light_index].cone_angle));
+ attenuation *= 1.0 - pow(spot_rim, spot_lights.data[light_index].cone_attenuation);
+
+ vec3 light = spot_lights.data[light_index].color;
+
+ if (spot_lights.data[light_index].shadow_enabled) {
+ //has shadow
+ vec4 v = vec4(view_pos, 1.0);
+
+ vec4 splane = (spot_lights.data[light_index].shadow_matrix * v);
+ splane /= splane.w;
+
+ float depth = texture(sampler2D(shadow_atlas, linear_sampler), splane.xy).r;
+
+ shadow_attenuation = exp(min(0.0, (depth - splane.z)) / spot_lights.data[light_index].inv_radius * spot_lights.data[light_index].shadow_volumetric_fog_fade);
+ }
+
+ total_light += light * attenuation * shadow_attenuation * henyey_greenstein(dot(normalize(light_rel_vec), normalize(view_pos)), params.phase_g);
+ }
+ }
+ }
+ }
+
+ vec3 world_pos = mat3(params.cam_rotation) * view_pos;
+
+ for (uint i = 0; i < params.max_voxel_gi_instances; i++) {
+ vec3 position = (voxel_gi_instances.data[i].xform * vec4(world_pos, 1.0)).xyz;
+
+ //this causes corrupted pixels, i have no idea why..
+ if (all(bvec2(all(greaterThanEqual(position, vec3(0.0))), all(lessThan(position, voxel_gi_instances.data[i].bounds))))) {
+ position /= voxel_gi_instances.data[i].bounds;
+
+ vec4 light = vec4(0.0);
+ for (uint j = 0; j < voxel_gi_instances.data[i].mipmaps; j++) {
+ vec4 slight = textureLod(sampler3D(voxel_gi_textures[i], linear_sampler_with_mipmaps), position, float(j));
+ float a = (1.0 - light.a);
+ light += a * slight;
+ }
+
+ light.rgb *= voxel_gi_instances.data[i].dynamic_range * params.gi_inject;
+
+ total_light += light.rgb;
+ }
+ }
+
+ //sdfgi
+#ifdef ENABLE_SDFGI
+
+ {
+ float blend = -1.0;
+ vec3 ambient_total = vec3(0.0);
+
+ for (uint i = 0; i < sdfgi.max_cascades; i++) {
+ vec3 cascade_pos = (world_pos - sdfgi.cascades[i].position) * sdfgi.cascades[i].to_probe;
+
+ if (any(lessThan(cascade_pos, vec3(0.0))) || any(greaterThanEqual(cascade_pos, sdfgi.cascade_probe_size))) {
+ continue; //skip cascade
+ }
+
+ vec3 base_pos = floor(cascade_pos);
+ ivec3 probe_base_pos = ivec3(base_pos);
+
+ vec4 ambient_accum = vec4(0.0);
+
+ ivec3 tex_pos = ivec3(probe_base_pos.xy, int(i));
+ tex_pos.x += probe_base_pos.z * sdfgi.probe_axis_size;
+
+ for (uint j = 0; j < 8; j++) {
+ ivec3 offset = (ivec3(j) >> ivec3(0, 1, 2)) & ivec3(1, 1, 1);
+ ivec3 probe_posi = probe_base_pos;
+ probe_posi += offset;
+
+ // Compute weight
+
+ vec3 probe_pos = vec3(probe_posi);
+ vec3 probe_to_pos = cascade_pos - probe_pos;
+
+ vec3 trilinear = vec3(1.0) - abs(probe_to_pos);
+ float weight = trilinear.x * trilinear.y * trilinear.z;
+
+ // Compute lightprobe occlusion
+
+ if (sdfgi.use_occlusion) {
+ ivec3 occ_indexv = abs((sdfgi.cascades[i].probe_world_offset + probe_posi) & ivec3(1, 1, 1)) * ivec3(1, 2, 4);
+ vec4 occ_mask = mix(vec4(0.0), vec4(1.0), equal(ivec4(occ_indexv.x | occ_indexv.y), ivec4(0, 1, 2, 3)));
+
+ vec3 occ_pos = clamp(cascade_pos, probe_pos - sdfgi.occlusion_clamp, probe_pos + sdfgi.occlusion_clamp) * sdfgi.probe_to_uvw;
+ occ_pos.z += float(i);
+ if (occ_indexv.z != 0) { //z bit is on, means index is >=4, so make it switch to the other half of textures
+ occ_pos.x += 1.0;
+ }
+
+ occ_pos *= sdfgi.occlusion_renormalize;
+ float occlusion = dot(textureLod(sampler3D(sdfgi_occlusion_texture, linear_sampler), occ_pos, 0.0), occ_mask);
+
+ weight *= max(occlusion, 0.01);
+ }
+
+ // Compute ambient texture position
+
+ ivec3 uvw = tex_pos;
+ uvw.xy += offset.xy;
+ uvw.x += offset.z * sdfgi.probe_axis_size;
+
+ vec3 ambient = texelFetch(sampler2DArray(sdfgi_ambient_texture, linear_sampler), uvw, 0).rgb;
+
+ ambient_accum.rgb += ambient * weight;
+ ambient_accum.a += weight;
+ }
+
+ if (ambient_accum.a > 0) {
+ ambient_accum.rgb /= ambient_accum.a;
+ }
+ ambient_total = ambient_accum.rgb;
+ break;
+ }
+
+ total_light += ambient_total * params.gi_inject;
+ }
+
+#endif
+ }
+
+ vec4 final_density = vec4(total_light * scattering + emission, total_density);
+
+ final_density = mix(final_density, reprojected_density, reproject_amount);
+
+ imageStore(density_map, pos, final_density);
+#ifdef MOLTENVK_USED
+ density_only_map[lpos] = 0;
+ light_only_map[lpos] = 0;
+ emissive_only_map[lpos] = 0;
+#else
+ imageStore(density_only_map, pos, uvec4(0));
+ imageStore(light_only_map, pos, uvec4(0));
+ imageStore(emissive_only_map, pos, uvec4(0));
+#endif
+#endif
+
+#ifdef MODE_FOG
+
+ ivec3 pos = ivec3(gl_GlobalInvocationID.xy, 0);
+
+ if (any(greaterThanEqual(pos, params.fog_volume_size))) {
+ return; //do not compute
+ }
+
+ vec4 fog_accum = vec4(0.0, 0.0, 0.0, 1.0);
+ float prev_z = 0.0;
+
+ for (int i = 0; i < params.fog_volume_size.z; i++) {
+ //compute fog position
+ ivec3 fog_pos = pos + ivec3(0, 0, i);
+ //get fog value
+ vec4 fog = imageLoad(density_map, fog_pos);
+
+ //get depth at cell pos
+ float z = get_depth_at_pos(fog_cell_size.z, i);
+ //get distance from previous pos
+ float d = abs(prev_z - z);
+ //compute transmittance using beer's law
+ float transmittance = exp(-d * fog.a);
+
+ fog_accum.rgb += ((fog.rgb - fog.rgb * transmittance) / max(fog.a, 0.00001)) * fog_accum.a;
+ fog_accum.a *= transmittance;
+
+ prev_z = z;
+
+ imageStore(fog_map, fog_pos, vec4(fog_accum.rgb, 1.0 - fog_accum.a));
+ }
+
+#endif
+
+#ifdef MODE_FILTER
+
+ ivec3 pos = ivec3(gl_GlobalInvocationID.xyz);
+
+ const float gauss[7] = float[](0.071303, 0.131514, 0.189879, 0.214607, 0.189879, 0.131514, 0.071303);
+
+ const ivec3 filter_dir[3] = ivec3[](ivec3(1, 0, 0), ivec3(0, 1, 0), ivec3(0, 0, 1));
+ ivec3 offset = filter_dir[params.filter_axis];
+
+ vec4 accum = vec4(0.0);
+ for (int i = -3; i <= 3; i++) {
+ accum += imageLoad(source_map, clamp(pos + offset * i, ivec3(0), params.fog_volume_size - ivec3(1))) * gauss[i + 3];
+ }
+
+ imageStore(dest_map, pos, accum);
+
+#endif
+#ifdef MODE_COPY
+ ivec3 pos = ivec3(gl_GlobalInvocationID.xyz);
+ if (any(greaterThanEqual(pos, params.fog_volume_size))) {
+ return; //do not compute
+ }
+
+ imageStore(dest_map, pos, imageLoad(source_map, pos));
+
+#endif
+}
diff --git a/servers/rendering/renderer_rd/shaders/giprobe.glsl b/servers/rendering/renderer_rd/shaders/voxel_gi.glsl
index 49a493cdc7..779f04ed35 100644
--- a/servers/rendering/renderer_rd/shaders/giprobe.glsl
+++ b/servers/rendering/renderer_rd/shaders/voxel_gi.glsl
@@ -71,11 +71,6 @@ lights;
layout(set = 0, binding = 5) uniform texture3D color_texture;
-#ifdef MODE_ANISOTROPIC
-layout(set = 0, binding = 7) uniform texture3D aniso_pos_texture;
-layout(set = 0, binding = 8) uniform texture3D aniso_neg_texture;
-#endif // MODE ANISOTROPIC
-
#endif // MODE_SECOND_BOUNCE
#ifndef MODE_DYNAMIC
@@ -110,13 +105,6 @@ layout(set = 0, binding = 10) uniform sampler texture_sampler;
layout(rgba8, set = 0, binding = 5) uniform restrict writeonly image3D color_tex;
-#ifdef MODE_ANISOTROPIC
-
-layout(r16ui, set = 0, binding = 6) uniform restrict writeonly uimage3D aniso_pos_tex;
-layout(r16ui, set = 0, binding = 7) uniform restrict writeonly uimage3D aniso_neg_tex;
-
-#endif
-
#endif
#ifdef MODE_DYNAMIC
@@ -170,13 +158,6 @@ layout(r32f, set = 0, binding = 8) uniform restrict writeonly image2D depth;
layout(rgba8, set = 0, binding = 11) uniform restrict image3D color_texture;
-#ifdef MODE_ANISOTROPIC
-
-layout(r16ui, set = 0, binding = 12) uniform restrict writeonly uimage3D aniso_pos_texture;
-layout(r16ui, set = 0, binding = 13) uniform restrict writeonly uimage3D aniso_neg_texture;
-
-#endif // MODE ANISOTROPIC
-
#endif //MODE_DYNAMIC_SHRINK_PLOT
#endif // MODE_DYNAMIC_SHRINK
@@ -374,12 +355,7 @@ void main() {
vec3 emission = vec3(uvec3(cell_data.data[cell_index].emission & 0x1ff, (cell_data.data[cell_index].emission >> 9) & 0x1ff, (cell_data.data[cell_index].emission >> 18) & 0x1ff)) * pow(2.0, float(cell_data.data[cell_index].emission >> 27) - 15.0 - 9.0);
vec3 normal = unpackSnorm4x8(cell_data.data[cell_index].normal).xyz;
-#ifdef MODE_ANISOTROPIC
- vec3 accum[6] = vec3[](vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0));
- const vec3 accum_dirs[6] = vec3[](vec3(1.0, 0.0, 0.0), vec3(-1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(0.0, -1.0, 0.0), vec3(0.0, 0.0, 1.0), vec3(0.0, 0.0, -1.0));
-#else
vec3 accum = vec3(0.0);
-#endif
for (uint i = 0; i < params.light_count; i++) {
vec3 light;
@@ -390,38 +366,16 @@ void main() {
light *= albedo.rgb;
-#ifdef MODE_ANISOTROPIC
- for (uint j = 0; j < 6; j++) {
- accum[j] += max(0.0, dot(accum_dirs[j], -light_dir)) * light;
- }
-#else
if (length(normal) > 0.2) {
accum += max(0.0, dot(normal, -light_dir)) * light;
} else {
//all directions
accum += light;
}
-#endif
}
-#ifdef MODE_ANISOTROPIC
-
- for (uint i = 0; i < 6; i++) {
- vec3 light = accum[i];
- if (length(normal) > 0.2) {
- light += max(0.0, dot(accum_dirs[i], -normal)) * emission;
- } else {
- light += emission;
- }
-
- outputs.data[cell_index * 6 + i] = vec4(light, 0.0);
- }
-
-#else
outputs.data[cell_index] = vec4(accum + emission, 0.0);
-#endif
-
#endif //MODE_COMPUTE_LIGHT
/////////////////SECOND BOUNCE///////////////////////////////
@@ -431,32 +385,8 @@ void main() {
ivec3 ipos = ivec3(posu);
vec4 normal = unpackSnorm4x8(cell_data.data[cell_index].normal);
-#ifdef MODE_ANISOTROPIC
- vec3 accum[6];
- const vec3 accum_dirs[6] = vec3[](vec3(1.0, 0.0, 0.0), vec3(-1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(0.0, -1.0, 0.0), vec3(0.0, 0.0, 1.0), vec3(0.0, 0.0, -1.0));
-
- /*vec3 src_color = texelFetch(sampler3D(color_texture,texture_sampler),ipos,0).rgb * params.dynamic_range;
- vec3 src_aniso_pos = texelFetch(sampler3D(aniso_pos_texture,texture_sampler),ipos,0).rgb;
- vec3 src_anisp_neg = texelFetch(sampler3D(anisp_neg_texture,texture_sampler),ipos,0).rgb;
- accum[0]=src_col * src_aniso_pos.x;
- accum[1]=src_col * src_aniso_neg.x;
- accum[2]=src_col * src_aniso_pos.y;
- accum[3]=src_col * src_aniso_neg.y;
- accum[4]=src_col * src_aniso_pos.z;
- accum[5]=src_col * src_aniso_neg.z;*/
-
- accum[0] = outputs.data[cell_index * 6 + 0].rgb;
- accum[1] = outputs.data[cell_index * 6 + 1].rgb;
- accum[2] = outputs.data[cell_index * 6 + 2].rgb;
- accum[3] = outputs.data[cell_index * 6 + 3].rgb;
- accum[4] = outputs.data[cell_index * 6 + 4].rgb;
- accum[5] = outputs.data[cell_index * 6 + 5].rgb;
-
-#else
vec3 accum = outputs.data[cell_index].rgb;
-#endif
-
if (length(normal.xyz) > 0.2) {
vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);
vec3 tangent = normalize(cross(v0, normal.xyz));
@@ -484,9 +414,6 @@ void main() {
float max_distance = length(vec3(params.limits));
vec3 cell_size = 1.0 / vec3(params.limits);
-#ifdef MODE_ANISOTROPIC
- vec3 aniso_normal = mix(direction, normal.xyz, params.aniso_strength);
-#endif
while (dist < max_distance && color.a < 0.95) {
float diameter = max(1.0, 2.0 * tan_half_angle * dist);
vec3 uvw_pos = (pos + dist * direction) * cell_size;
@@ -498,42 +425,18 @@ void main() {
float log2_diameter = log2(diameter);
vec4 scolor = textureLod(sampler3D(color_texture, texture_sampler), uvw_pos, log2_diameter);
-#ifdef MODE_ANISOTROPIC
-
- vec3 aniso_neg = textureLod(sampler3D(aniso_neg_texture, texture_sampler), uvw_pos, log2_diameter).rgb;
- vec3 aniso_pos = textureLod(sampler3D(aniso_pos_texture, texture_sampler), uvw_pos, log2_diameter).rgb;
-
- scolor.rgb *= dot(max(vec3(0.0), (aniso_normal * aniso_pos)), vec3(1.0)) + dot(max(vec3(0.0), (-aniso_normal * aniso_neg)), vec3(1.0));
-#endif
float a = (1.0 - color.a);
color += a * scolor;
dist += half_diameter;
}
}
color *= cone_weights[i] * vec4(albedo.rgb, 1.0) * params.dynamic_range; //restore range
-#ifdef MODE_ANISOTROPIC
- for (uint j = 0; j < 6; j++) {
- accum[j] += max(0.0, dot(accum_dirs[j], direction)) * color.rgb;
- }
-#else
accum += color.rgb;
-#endif
}
}
-#ifdef MODE_ANISOTROPIC
-
- outputs.data[cell_index * 6 + 0] = vec4(accum[0], 0.0);
- outputs.data[cell_index * 6 + 1] = vec4(accum[1], 0.0);
- outputs.data[cell_index * 6 + 2] = vec4(accum[2], 0.0);
- outputs.data[cell_index * 6 + 3] = vec4(accum[3], 0.0);
- outputs.data[cell_index * 6 + 4] = vec4(accum[4], 0.0);
- outputs.data[cell_index * 6 + 5] = vec4(accum[5], 0.0);
-#else
outputs.data[cell_index] = vec4(accum, 0.0);
-#endif
-
#endif // MODE_SECOND_BOUNCE
/////////////////UPDATE MIPMAPS///////////////////////////////
@@ -541,45 +444,20 @@ void main() {
#ifdef MODE_UPDATE_MIPMAPS
{
-#ifdef MODE_ANISOTROPIC
- vec3 light_accum[6] = vec3[](vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0));
-#else
vec3 light_accum = vec3(0.0);
-#endif
float count = 0.0;
for (uint i = 0; i < 8; i++) {
uint child_index = cell_children.data[cell_index].children[i];
if (child_index == NO_CHILDREN) {
continue;
}
-#ifdef MODE_ANISOTROPIC
- light_accum[0] += outputs.data[child_index * 6 + 0].rgb;
- light_accum[1] += outputs.data[child_index * 6 + 1].rgb;
- light_accum[2] += outputs.data[child_index * 6 + 2].rgb;
- light_accum[3] += outputs.data[child_index * 6 + 3].rgb;
- light_accum[4] += outputs.data[child_index * 6 + 4].rgb;
- light_accum[5] += outputs.data[child_index * 6 + 5].rgb;
-
-#else
light_accum += outputs.data[child_index].rgb;
-#endif
-
count += 1.0;
}
float divisor = mix(8.0, count, params.propagation);
-#ifdef MODE_ANISOTROPIC
- outputs.data[cell_index * 6 + 0] = vec4(light_accum[0] / divisor, 0.0);
- outputs.data[cell_index * 6 + 1] = vec4(light_accum[1] / divisor, 0.0);
- outputs.data[cell_index * 6 + 2] = vec4(light_accum[2] / divisor, 0.0);
- outputs.data[cell_index * 6 + 3] = vec4(light_accum[3] / divisor, 0.0);
- outputs.data[cell_index * 6 + 4] = vec4(light_accum[4] / divisor, 0.0);
- outputs.data[cell_index * 6 + 5] = vec4(light_accum[5] / divisor, 0.0);
-
-#else
outputs.data[cell_index] = vec4(light_accum / divisor, 0.0);
-#endif
}
#endif
@@ -587,40 +465,7 @@ void main() {
#ifdef MODE_WRITE_TEXTURE
{
-#ifdef MODE_ANISOTROPIC
- vec3 accum_total = vec3(0.0);
- accum_total += outputs.data[cell_index * 6 + 0].rgb;
- accum_total += outputs.data[cell_index * 6 + 1].rgb;
- accum_total += outputs.data[cell_index * 6 + 2].rgb;
- accum_total += outputs.data[cell_index * 6 + 3].rgb;
- accum_total += outputs.data[cell_index * 6 + 4].rgb;
- accum_total += outputs.data[cell_index * 6 + 5].rgb;
-
- float accum_total_energy = max(dot(accum_total, GREY_VEC), 0.00001);
- vec3 iso_positive = vec3(dot(outputs.data[cell_index * 6 + 0].rgb, GREY_VEC), dot(outputs.data[cell_index * 6 + 2].rgb, GREY_VEC), dot(outputs.data[cell_index * 6 + 4].rgb, GREY_VEC)) / vec3(accum_total_energy);
- vec3 iso_negative = vec3(dot(outputs.data[cell_index * 6 + 1].rgb, GREY_VEC), dot(outputs.data[cell_index * 6 + 3].rgb, GREY_VEC), dot(outputs.data[cell_index * 6 + 5].rgb, GREY_VEC)) / vec3(accum_total_energy);
-
- {
- uint aniso_pos = uint(clamp(iso_positive.b * 31.0, 0.0, 31.0));
- aniso_pos |= uint(clamp(iso_positive.g * 63.0, 0.0, 63.0)) << 5;
- aniso_pos |= uint(clamp(iso_positive.r * 31.0, 0.0, 31.0)) << 11;
- imageStore(aniso_pos_tex, ivec3(posu), uvec4(aniso_pos));
- }
-
- {
- uint aniso_neg = uint(clamp(iso_negative.b * 31.0, 0.0, 31.0));
- aniso_neg |= uint(clamp(iso_negative.g * 63.0, 0.0, 63.0)) << 5;
- aniso_neg |= uint(clamp(iso_negative.r * 31.0, 0.0, 31.0)) << 11;
- imageStore(aniso_neg_tex, ivec3(posu), uvec4(aniso_neg));
- }
-
- imageStore(color_tex, ivec3(posu), vec4(accum_total / params.dynamic_range, albedo.a));
-
-#else
-
imageStore(color_tex, ivec3(posu), vec4(outputs.data[cell_index].rgb / params.dynamic_range, albedo.a));
-
-#endif
}
#endif
@@ -763,13 +608,6 @@ void main() {
color.rgb /= params.dynamic_range;
imageStore(color_texture, pos3d, color);
//imageStore(color_texture,pos3d,vec4(1,1,1,1));
-
-#ifdef MODE_ANISOTROPIC
- //do not care about anisotropy for dynamic objects, just store full lit in all directions
- imageStore(aniso_pos_texture, pos3d, uvec4(0xFFFF));
- imageStore(aniso_neg_texture, pos3d, uvec4(0xFFFF));
-
-#endif // ANISOTROPIC
}
#endif // MODE_DYNAMIC_SHRINK_PLOT
}
diff --git a/servers/rendering/renderer_rd/shaders/giprobe_debug.glsl b/servers/rendering/renderer_rd/shaders/voxel_gi_debug.glsl
index 7d4d72967a..281c496df3 100644
--- a/servers/rendering/renderer_rd/shaders/giprobe_debug.glsl
+++ b/servers/rendering/renderer_rd/shaders/voxel_gi_debug.glsl
@@ -20,11 +20,6 @@ layout(set = 0, binding = 2) uniform texture3D color_tex;
layout(set = 0, binding = 3) uniform sampler tex_sampler;
-#ifdef USE_ANISOTROPY
-layout(set = 0, binding = 4) uniform texture3D aniso_pos_tex;
-layout(set = 0, binding = 5) uniform texture3D aniso_neg_tex;
-#endif
-
layout(push_constant, binding = 0, std430) uniform Params {
mat4 projection;
uint cell_offset;
diff --git a/servers/rendering/renderer_rd/shaders/giprobe_sdf.glsl b/servers/rendering/renderer_rd/shaders/voxel_gi_sdf.glsl
index e20b3f680d..e20b3f680d 100644
--- a/servers/rendering/renderer_rd/shaders/giprobe_sdf.glsl
+++ b/servers/rendering/renderer_rd/shaders/voxel_gi_sdf.glsl