diff options
Diffstat (limited to 'servers/rendering/rasterizer_rd/shaders')
12 files changed, 1066 insertions, 498 deletions
diff --git a/servers/rendering/rasterizer_rd/shaders/SCsub b/servers/rendering/rasterizer_rd/shaders/SCsub index 04a43e3251..a454d144aa 100644 --- a/servers/rendering/rasterizer_rd/shaders/SCsub +++ b/servers/rendering/rasterizer_rd/shaders/SCsub @@ -5,14 +5,15 @@ Import("env") if "RD_GLSL" in env["BUILDERS"]: env.RD_GLSL("canvas.glsl") env.RD_GLSL("canvas_occlusion.glsl") - env.RD_GLSL("blur.glsl") + env.RD_GLSL("copy.glsl") + env.RD_GLSL("copy_to_fb.glsl") env.RD_GLSL("cubemap_roughness.glsl") env.RD_GLSL("cubemap_downsampler.glsl") env.RD_GLSL("cubemap_filter.glsl") env.RD_GLSL("scene_high_end.glsl") env.RD_GLSL("sky.glsl") env.RD_GLSL("tonemap.glsl") - env.RD_GLSL("copy.glsl") + env.RD_GLSL("cube_to_dp.glsl") env.RD_GLSL("giprobe.glsl") env.RD_GLSL("giprobe_debug.glsl") env.RD_GLSL("giprobe_sdf.glsl") diff --git a/servers/rendering/rasterizer_rd/shaders/blur.glsl b/servers/rendering/rasterizer_rd/shaders/blur.glsl deleted file mode 100644 index 5dfdc614a4..0000000000 --- a/servers/rendering/rasterizer_rd/shaders/blur.glsl +++ /dev/null @@ -1,301 +0,0 @@ -/* clang-format off */ -[vertex] - -#version 450 - -VERSION_DEFINES - -#include "blur_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]; - - if (bool(blur.flags & FLAG_USE_BLUR_SECTION)) { - uv_interp = blur.section.xy + uv_interp * blur.section.zw; - } - - gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0); - - if (bool(blur.flags & FLAG_FLIP_Y)) { - uv_interp.y = 1.0 - uv_interp.y; - } -} - -/* clang-format off */ -[fragment] - -#version 450 - -VERSION_DEFINES - -#include "blur_inc.glsl" - -layout(location = 0) in vec2 uv_interp; -/* clang-format on */ - -layout(set = 0, binding = 0) uniform sampler2D source_color; - -#ifdef MODE_SSAO_MERGE -layout(set = 1, binding = 0) uniform sampler2D source_ssao; -#endif - -#ifdef GLOW_USE_AUTO_EXPOSURE -layout(set = 1, binding = 0) uniform sampler2D source_auto_exposure; -#endif - -layout(location = 0) out vec4 frag_color; - -//DOF -#if defined(MODE_DOF_FAR_BLUR) || defined(MODE_DOF_NEAR_BLUR) - -layout(set = 1, binding = 0) uniform sampler2D dof_source_depth; - -#ifdef DOF_NEAR_BLUR_MERGE -layout(set = 2, binding = 0) uniform sampler2D source_dof_original; -#endif - -#ifdef DOF_QUALITY_LOW -const int dof_kernel_size = 5; -const int dof_kernel_from = 2; -const float dof_kernel[5] = float[](0.153388, 0.221461, 0.250301, 0.221461, 0.153388); -#endif - -#ifdef DOF_QUALITY_MEDIUM -const int dof_kernel_size = 11; -const int dof_kernel_from = 5; -const float dof_kernel[11] = float[](0.055037, 0.072806, 0.090506, 0.105726, 0.116061, 0.119726, 0.116061, 0.105726, 0.090506, 0.072806, 0.055037); - -#endif - -#ifdef DOF_QUALITY_HIGH -const int dof_kernel_size = 21; -const int dof_kernel_from = 10; -const float dof_kernel[21] = float[](0.028174, 0.032676, 0.037311, 0.041944, 0.046421, 0.050582, 0.054261, 0.057307, 0.059587, 0.060998, 0.061476, 0.060998, 0.059587, 0.057307, 0.054261, 0.050582, 0.046421, 0.041944, 0.037311, 0.032676, 0.028174); -#endif - -#endif - -void main() { - -#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_DOF_FAR_BLUR - - vec4 color_accum = vec4(0.0); - - float depth = texture(dof_source_depth, uv_interp, 0.0).r; - depth = depth * 2.0 - 1.0; - - if (bool(blur.flags & FLAG_USE_ORTHOGONAL_PROJECTION)) { - depth = ((depth + (blur.camera_z_far + blur.camera_z_near) / (blur.camera_z_far - blur.camera_z_near)) * (blur.camera_z_far - blur.camera_z_near)) / 2.0; - } else { - depth = 2.0 * blur.camera_z_near * blur.camera_z_far / (blur.camera_z_far + blur.camera_z_near - depth * (blur.camera_z_far - blur.camera_z_near)); - } - - float amount = smoothstep(blur.dof_begin, blur.dof_end, depth); - float k_accum = 0.0; - - for (int i = 0; i < dof_kernel_size; i++) { - - int int_ofs = i - dof_kernel_from; - vec2 tap_uv = uv_interp + blur.dof_dir * float(int_ofs) * amount * blur.dof_radius; - - float tap_k = dof_kernel[i]; - - float tap_depth = texture(dof_source_depth, tap_uv, 0.0).r; - tap_depth = tap_depth * 2.0 - 1.0; - - if (bool(blur.flags & FLAG_USE_ORTHOGONAL_PROJECTION)) { - - tap_depth = ((tap_depth + (blur.camera_z_far + blur.camera_z_near) / (blur.camera_z_far - blur.camera_z_near)) * (blur.camera_z_far - blur.camera_z_near)) / 2.0; - } else { - tap_depth = 2.0 * blur.camera_z_near * blur.camera_z_far / (blur.camera_z_far + blur.camera_z_near - tap_depth * (blur.camera_z_far - blur.camera_z_near)); - } - - float tap_amount = mix(smoothstep(blur.dof_begin, blur.dof_end, tap_depth), 1.0, int_ofs == 0); - tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect - - vec4 tap_color = texture(source_color, tap_uv, 0.0) * tap_k; - - k_accum += tap_k * tap_amount; - color_accum += tap_color * tap_amount; - } - - if (k_accum > 0.0) { - color_accum /= k_accum; - } - - frag_color = color_accum; ///k_accum; - -#endif - -#ifdef MODE_DOF_NEAR_BLUR - - vec4 color_accum = vec4(0.0); - - float max_accum = 0.0; - - for (int i = 0; i < dof_kernel_size; i++) { - - int int_ofs = i - dof_kernel_from; - vec2 tap_uv = uv_interp + blur.dof_dir * float(int_ofs) * blur.dof_radius; - float ofs_influence = max(0.0, 1.0 - float(abs(int_ofs)) / float(dof_kernel_from)); - - float tap_k = dof_kernel[i]; - - vec4 tap_color = texture(source_color, tap_uv, 0.0); - - float tap_depth = texture(dof_source_depth, tap_uv, 0.0).r; - tap_depth = tap_depth * 2.0 - 1.0; - if (bool(blur.flags & FLAG_USE_ORTHOGONAL_PROJECTION)) { - - tap_depth = ((tap_depth + (blur.camera_z_far + blur.camera_z_near) / (blur.camera_z_far - blur.camera_z_near)) * (blur.camera_z_far - blur.camera_z_near)) / 2.0; - } else { - tap_depth = 2.0 * blur.camera_z_near * blur.camera_z_far / (blur.camera_z_far + blur.camera_z_near - tap_depth * (blur.camera_z_far - blur.camera_z_near)); - } - float tap_amount = 1.0 - smoothstep(blur.dof_end, blur.dof_begin, tap_depth); - tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect - - if (bool(blur.flags & FLAG_DOF_NEAR_FIRST_TAP)) { - tap_color.a = 1.0 - smoothstep(blur.dof_end, blur.dof_begin, tap_depth); - } - - max_accum = max(max_accum, tap_amount * ofs_influence); - - color_accum += tap_color * tap_k; - } - - color_accum.a = max(color_accum.a, sqrt(max_accum)); - -#ifdef DOF_NEAR_BLUR_MERGE - { - vec4 original = texture(source_dof_original, uv_interp, 0.0); - color_accum = mix(original, color_accum, color_accum.a); - } -#endif - - if (bool(blur.flags & FLAG_DOF_NEAR_FIRST_TAP)) { - frag_color = color_accum; - } -#endif - -#ifdef MODE_SIMPLE_COPY - vec4 color = texture(source_color, uv_interp, 0.0); - if (bool(blur.flags & FLAG_COPY_FORCE_LUMINANCE)) { - color.rgb = vec3(max(max(color.r, color.g), color.b)); - } - frag_color = color; -#endif - -#ifdef MODE_LINEARIZE_DEPTH_COPY - float depth = texture(source_color, uv_interp, 0.0).r; - depth = depth * 2.0 - 1.0; - depth = 2.0 * blur.camera_z_near * blur.camera_z_far / (blur.camera_z_far + blur.camera_z_near - depth * (blur.camera_z_far - blur.camera_z_near)); - frag_color = vec4(depth / blur.camera_z_far); -#endif - -#ifdef MODE_SSAO_MERGE - vec4 color = texture(source_color, uv_interp, 0.0); - float ssao = texture(source_ssao, uv_interp, 0.0).r; - frag_color = vec4(mix(color.rgb, color.rgb * mix(blur.ssao_color.rgb, vec3(1.0), ssao), color.a), 1.0); - -#endif -} diff --git a/servers/rendering/rasterizer_rd/shaders/blur_inc.glsl b/servers/rendering/rasterizer_rd/shaders/blur_inc.glsl deleted file mode 100644 index 33ba9de7bb..0000000000 --- a/servers/rendering/rasterizer_rd/shaders/blur_inc.glsl +++ /dev/null @@ -1,35 +0,0 @@ -#define FLAG_HORIZONTAL (1 << 0) -#define FLAG_USE_BLUR_SECTION (1 << 1) -#define FLAG_USE_ORTHOGONAL_PROJECTION (1 << 2) -#define FLAG_DOF_NEAR_FIRST_TAP (1 << 3) -#define FLAG_GLOW_FIRST_PASS (1 << 4) -#define FLAG_FLIP_Y (1 << 5) -#define FLAG_COPY_FORCE_LUMINANCE (1 << 6) - -layout(push_constant, binding = 1, std430) uniform Blur { - vec4 section; - 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; - // DOF. - float dof_begin; - float dof_end; - float dof_radius; - float dof_pad; - - vec2 dof_dir; - float camera_z_far; - float camera_z_near; - - vec4 ssao_color; -} -blur; diff --git a/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl b/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl index 1ac43480cd..a39866004b 100644 --- a/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl +++ b/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl @@ -132,6 +132,11 @@ layout(set = 2, binding = 6) uniform sampler shadow_sampler; #endif +layout(set = 2, binding = 7, std430) restrict readonly buffer GlobalVariableData { + vec4 data[]; +} +global_variables; + /* SET3: Render Target Data */ #ifdef SCREEN_TEXTURE_USED diff --git a/servers/rendering/rasterizer_rd/shaders/copy.glsl b/servers/rendering/rasterizer_rd/shaders/copy.glsl index 2b541f2660..2d7661f65f 100644 --- a/servers/rendering/rasterizer_rd/shaders/copy.glsl +++ b/servers/rendering/rasterizer_rd/shaders/copy.glsl @@ -1,87 +1,220 @@ /* clang-format off */ -[vertex] +[compute] #version 450 VERSION_DEFINES -layout(location = 0) out vec2 uv_interp; +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; /* clang-format on */ -void main() { +#define FLAG_HORIZONTAL (1 << 0) +#define FLAG_USE_BLUR_SECTION (1 << 1) +#define FLAG_USE_ORTHOGONAL_PROJECTION (1 << 2) +#define FLAG_DOF_NEAR_FIRST_TAP (1 << 3) +#define FLAG_GLOW_FIRST_PASS (1 << 4) +#define FLAG_FLIP_Y (1 << 5) +#define FLAG_FORCE_LUMINANCE (1 << 6) +#define FLAG_COPY_ALL_SOURCE (1 << 7) + +layout(push_constant, binding = 1, std430) uniform Params { + ivec4 section; + ivec2 target; + 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; + // DOF. + float camera_z_far; + float camera_z_near; + uint pad2[2]; +} +params; - 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]; +layout(set = 0, binding = 0) uniform sampler2D source_color; - gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0); -} +#ifdef GLOW_USE_AUTO_EXPOSURE +layout(set = 1, binding = 0) uniform sampler2D source_auto_exposure; +#endif -/* clang-format off */ -[fragment] +#if defined(MODE_LINEARIZE_DEPTH_COPY) || defined(MODE_SIMPLE_COPY_DEPTH) +layout(r32f, set = 3, binding = 0) uniform restrict writeonly image2D dest_buffer; +#elif defined(DST_IMAGE_8BIT) +layout(rgba8, set = 3, binding = 0) uniform restrict writeonly image2D dest_buffer; +#else +layout(rgba32f, set = 3, binding = 0) uniform restrict writeonly image2D dest_buffer; +#endif -#version 450 +void main() { -VERSION_DEFINES + // Pixel being shaded + ivec2 pos = ivec2(gl_GlobalInvocationID.xy); + if (any(greaterThan(pos, params.section.zw))) { //too large, do nothing + return; + } -layout(location = 0) in vec2 uv_interp; -/* clang-format on */ +#ifdef MODE_MIPMAP -#ifdef MODE_CUBE_TO_DP + ivec2 base_pos = (pos + params.section.xy) << 1; + vec4 color = texelFetch(source_color, base_pos, 0); + color += texelFetch(source_color, base_pos + ivec2(0, 1), 0); + color += texelFetch(source_color, base_pos + ivec2(1, 0), 0); + color += texelFetch(source_color, base_pos + ivec2(1, 1), 0); + color /= 4.0; -layout(set = 0, binding = 0) uniform samplerCube source_cube; + imageStore(dest_buffer, pos + params.target, color); +#endif -layout(push_constant, binding = 0, std430) uniform Params { - float bias; - float z_far; - float z_near; - bool z_flip; -} -params; +#ifdef MODE_GAUSSIAN_BLUR + + //Simpler blur uses SIGMA2 for the gaussian kernel for a stronger effect -layout(location = 0) out float depth_buffer; + if (bool(params.flags & FLAG_HORIZONTAL)) { + + ivec2 base_pos = (pos + params.section.xy) << 1; + vec4 color = texelFetch(source_color, base_pos + ivec2(0, 0), 0) * 0.214607; + color += texelFetch(source_color, base_pos + ivec2(1, 0), 0) * 0.189879; + color += texelFetch(source_color, base_pos + ivec2(2, 0), 0) * 0.131514; + color += texelFetch(source_color, base_pos + ivec2(3, 0), 0) * 0.071303; + color += texelFetch(source_color, base_pos + ivec2(-1, 0), 0) * 0.189879; + color += texelFetch(source_color, base_pos + ivec2(-2, 0), 0) * 0.131514; + color += texelFetch(source_color, base_pos + ivec2(-3, 0), 0) * 0.071303; + imageStore(dest_buffer, pos + params.target, color); + } else { + ivec2 base_pos = (pos + params.section.xy); + vec4 color = texelFetch(source_color, base_pos + ivec2(0, 0), 0) * 0.38774; + color += texelFetch(source_color, base_pos + ivec2(0, 1), 0) * 0.24477; + color += texelFetch(source_color, base_pos + ivec2(0, 2), 0) * 0.06136; + color += texelFetch(source_color, base_pos + ivec2(0, -1), 0) * 0.24477; + color += texelFetch(source_color, base_pos + ivec2(0, -2), 0) * 0.06136; + imageStore(dest_buffer, pos + params.target, color); + } #endif -void main() { +#ifdef MODE_GAUSSIAN_GLOW -#ifdef MODE_CUBE_TO_DP + //Glow uses larger sigma 1 for a more rounded blur effect - vec3 normal = vec3(uv_interp * 2.0 - 1.0, 0.0); +#define GLOW_ADD(m_ofs, m_mult) \ + { \ + ivec2 ofs = base_pos + m_ofs; \ + if (all(greaterThanEqual(ofs, section_begin)) && all(lessThan(ofs, section_end))) { \ + color += texelFetch(source_color, ofs, 0) * m_mult; \ + } \ + } - normal.z = 0.5 - 0.5 * ((normal.x * normal.x) + (normal.y * normal.y)); - normal = normalize(normal); + vec4 color = vec4(0.0); - normal.y = -normal.y; //needs to be flipped to match projection matrix - if (!params.z_flip) { - normal.z = -normal.z; + if (bool(params.flags & FLAG_HORIZONTAL)) { + + ivec2 base_pos = (pos + params.section.xy) << 1; + ivec2 section_begin = params.section.xy << 1; + ivec2 section_end = section_begin + (params.section.zw << 1); + + GLOW_ADD(ivec2(0, 0), 0.174938); + GLOW_ADD(ivec2(1, 0), 0.165569); + GLOW_ADD(ivec2(2, 0), 0.140367); + GLOW_ADD(ivec2(3, 0), 0.106595); + GLOW_ADD(ivec2(-1, 0), 0.165569); + GLOW_ADD(ivec2(-2, 0), 0.140367); + GLOW_ADD(ivec2(-3, 0), 0.106595); + color *= params.glow_strength; + } else { + + ivec2 base_pos = pos + params.section.xy; + ivec2 section_begin = params.section.xy; + ivec2 section_end = section_begin + params.section.zw; + + GLOW_ADD(ivec2(0, 0), 0.288713); + GLOW_ADD(ivec2(0, 1), 0.233062); + GLOW_ADD(ivec2(0, 2), 0.122581); + GLOW_ADD(ivec2(0, -1), 0.233062); + GLOW_ADD(ivec2(0, -2), 0.122581); + color *= params.glow_strength; } - float depth = texture(source_cube, normal).r; - depth_buffer = depth; - - // absolute values for direction cosines, bigger value equals closer to basis axis - vec3 unorm = abs(normal); - - if ((unorm.x >= unorm.y) && (unorm.x >= unorm.z)) { - // x code - unorm = normal.x > 0.0 ? vec3(1.0, 0.0, 0.0) : vec3(-1.0, 0.0, 0.0); - } else if ((unorm.y > unorm.x) && (unorm.y >= unorm.z)) { - // y code - unorm = normal.y > 0.0 ? vec3(0.0, 1.0, 0.0) : vec3(0.0, -1.0, 0.0); - } else if ((unorm.z > unorm.x) && (unorm.z > unorm.y)) { - // z code - unorm = normal.z > 0.0 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 0.0, -1.0); +#undef GLOW_ADD + + if (bool(params.flags & FLAG_GLOW_FIRST_PASS)) { +#ifdef GLOW_USE_AUTO_EXPOSURE + + color /= texelFetch(source_auto_exposure, ivec2(0, 0), 0).r / params.glow_auto_exposure_grey; +#endif + color *= params.glow_exposure; + + float luminance = max(color.r, max(color.g, color.b)); + float feedback = max(smoothstep(params.glow_hdr_threshold, params.glow_hdr_threshold + params.glow_hdr_scale, luminance), params.glow_bloom); + + color = min(color * feedback, vec4(params.glow_luminance_cap)); + } + + imageStore(dest_buffer, pos + params.target, color); + +#endif + +#ifdef MODE_SIMPLE_COPY + + vec4 color; + if (bool(params.flags & FLAG_COPY_ALL_SOURCE)) { + vec2 uv = vec2(pos) / vec2(params.section.zw); + if (bool(params.flags & FLAG_FLIP_Y)) { + uv.y = 1.0 - uv.y; + } + color = textureLod(source_color, uv, 0.0); + + if (bool(params.flags & FLAG_FORCE_LUMINANCE)) { + color.rgb = vec3(max(max(color.r, color.g), color.b)); + } + imageStore(dest_buffer, pos + params.target, color); + } else { - // oh-no we messed up code - // has to be - unorm = vec3(1.0, 0.0, 0.0); + color = texelFetch(source_color, pos + params.section.xy, 0); + + if (bool(params.flags & FLAG_FORCE_LUMINANCE)) { + color.rgb = vec3(max(max(color.r, color.g), color.b)); + } + + if (bool(params.flags & FLAG_FLIP_Y)) { + pos.y = params.section.w - pos.y - 1; + } + + imageStore(dest_buffer, pos + params.target, color); } - float depth_fix = 1.0 / dot(normal, unorm); +#endif + +#ifdef MODE_SIMPLE_COPY_DEPTH + + vec4 color = texelFetch(source_color, pos + params.section.xy, 0); + + if (bool(params.flags & FLAG_FLIP_Y)) { + pos.y = params.section.w - pos.y - 1; + } - depth = 2.0 * depth - 1.0; - float linear_depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - depth * (params.z_far - params.z_near)); - depth_buffer = (linear_depth * depth_fix) / params.z_far; + imageStore(dest_buffer, pos + params.target, vec4(color.r)); + +#endif + +#ifdef MODE_LINEARIZE_DEPTH_COPY + + float depth = texelFetch(source_color, pos + params.section.xy, 0).r; + depth = depth * 2.0 - 1.0; + depth = 2.0 * params.camera_z_near * params.camera_z_far / (params.camera_z_far + params.camera_z_near - depth * (params.camera_z_far - params.camera_z_near)); + vec4 color = vec4(depth / params.camera_z_far); + + if (bool(params.flags & FLAG_FLIP_Y)) { + pos.y = params.section.w - pos.y - 1; + } + imageStore(dest_buffer, pos + params.target, color); #endif } diff --git a/servers/rendering/rasterizer_rd/shaders/copy_to_fb.glsl b/servers/rendering/rasterizer_rd/shaders/copy_to_fb.glsl new file mode 100644 index 0000000000..07f8d09743 --- /dev/null +++ b/servers/rendering/rasterizer_rd/shaders/copy_to_fb.glsl @@ -0,0 +1,104 @@ +/* clang-format off */ +[vertex] + +#version 450 + +VERSION_DEFINES + +layout(location = 0) out vec2 uv_interp; +/* clang-format on */ + +layout(push_constant, binding = 1, std430) uniform Params { + vec4 section; + vec2 pixel_size; + bool flip_y; + bool use_section; + + bool force_luminance; + uint pad[3]; +} +params; + +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]; + + vec2 vpos = uv_interp; + if (params.use_section) { + vpos = params.section.xy + vpos * params.section.zw; + } + + gl_Position = vec4(vpos * 2.0 - 1.0, 0.0, 1.0); + + if (params.flip_y) { + uv_interp.y = 1.0 - uv_interp.y; + } +} + +/* clang-format off */ +[fragment] + +#version 450 + +VERSION_DEFINES + +layout(push_constant, binding = 1, std430) uniform Params { + vec4 section; + vec2 pixel_size; + bool flip_y; + bool use_section; + + bool force_luminance; + bool alpha_to_zero; + uint pad[2]; +} params; + + +layout(location = 0) in vec2 uv_interp; +/* clang-format on */ + +layout(set = 0, binding = 0) uniform sampler2D source_color; + +layout(location = 0) out vec4 frag_color; + +void main() { + + vec2 uv = uv_interp; + +#ifdef MODE_PANORAMA_TO_DP + + //obtain normal from dual paraboloid uv +#define M_PI 3.14159265359 + + float side; + uv.y = modf(uv.y * 2.0, side); + side = side * 2.0 - 1.0; + vec3 normal = vec3(uv * 2.0 - 1.0, 0.0); + normal.z = 0.5 - 0.5 * ((normal.x * normal.x) + (normal.y * normal.y)); + normal *= -side; + normal = normalize(normal); + + //now convert normal to panorama uv + + vec2 st = vec2(atan(normal.x, normal.z), acos(normal.y)); + + if (st.x < 0.0) + st.x += M_PI * 2.0; + + uv = st / vec2(M_PI * 2.0, M_PI); + + if (side < 0.0) { + //uv.y = 1.0 - uv.y; + uv = 1.0 - uv; + } +#endif + vec4 color = textureLod(source_color, uv, 0.0); + if (params.force_luminance) { + color.rgb = vec3(max(max(color.r, color.g), color.b)); + } + if (params.alpha_to_zero) { + color.rgb *= color.a; + } + frag_color = color; +} diff --git a/servers/rendering/rasterizer_rd/shaders/cube_to_dp.glsl b/servers/rendering/rasterizer_rd/shaders/cube_to_dp.glsl new file mode 100644 index 0000000000..02ebe1a53b --- /dev/null +++ b/servers/rendering/rasterizer_rd/shaders/cube_to_dp.glsl @@ -0,0 +1,72 @@ +/* clang-format off */ +[compute] + +#version 450 + +VERSION_DEFINES + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; +/* clang-format on */ + +layout(set = 0, binding = 0) uniform samplerCube source_cube; + +layout(push_constant, binding = 1, std430) uniform Params { + ivec2 screen_size; + ivec2 offset; + float bias; + float z_far; + float z_near; + bool z_flip; +} +params; + +layout(r32f, set = 1, binding = 0) uniform restrict writeonly image2D depth_buffer; + +void main() { + + ivec2 pos = ivec2(gl_GlobalInvocationID.xy); + if (any(greaterThan(pos, params.screen_size))) { //too large, do nothing + return; + } + + vec2 pixel_size = 1.0 / vec2(params.screen_size); + vec2 uv = (vec2(pos) + 0.5) * pixel_size; + + vec3 normal = vec3(uv * 2.0 - 1.0, 0.0); + + normal.z = 0.5 - 0.5 * ((normal.x * normal.x) + (normal.y * normal.y)); + normal = normalize(normal); + + normal.y = -normal.y; //needs to be flipped to match projection matrix + if (!params.z_flip) { + normal.z = -normal.z; + } + + float depth = texture(source_cube, normal).r; + + // absolute values for direction cosines, bigger value equals closer to basis axis + vec3 unorm = abs(normal); + + if ((unorm.x >= unorm.y) && (unorm.x >= unorm.z)) { + // x code + unorm = normal.x > 0.0 ? vec3(1.0, 0.0, 0.0) : vec3(-1.0, 0.0, 0.0); + } else if ((unorm.y > unorm.x) && (unorm.y >= unorm.z)) { + // y code + unorm = normal.y > 0.0 ? vec3(0.0, 1.0, 0.0) : vec3(0.0, -1.0, 0.0); + } else if ((unorm.z > unorm.x) && (unorm.z > unorm.y)) { + // z code + unorm = normal.z > 0.0 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 0.0, -1.0); + } else { + // oh-no we messed up code + // has to be + unorm = vec3(1.0, 0.0, 0.0); + } + + float depth_fix = 1.0 / dot(normal, unorm); + + depth = 2.0 * depth - 1.0; + float linear_depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - depth * (params.z_far - params.z_near)); + depth = (linear_depth * depth_fix) / params.z_far; + + imageStore(depth_buffer, pos + params.offset, vec4(depth)); +} diff --git a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl index 62ab188ddc..ec47887036 100644 --- a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl +++ b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl @@ -20,9 +20,7 @@ layout(location = 2) in vec4 tangent_attrib; layout(location = 3) in vec4 color_attrib; #endif -#if defined(UV_USED) layout(location = 4) in vec2 uv_attrib; -#endif #if defined(UV2_USED) || defined(USE_LIGHTMAP) layout(location = 5) in vec2 uv2_attrib; @@ -39,9 +37,7 @@ layout(location = 1) out vec3 normal_interp; layout(location = 2) out vec4 color_interp; #endif -#if defined(UV_USED) layout(location = 3) out vec2 uv_interp; -#endif #if defined(UV2_USED) || defined(USE_LIGHTMAP) layout(location = 4) out vec2 uv2_interp; @@ -157,9 +153,7 @@ void main() { #endif } -#if defined(UV_USED) uv_interp = uv_attrib; -#endif #if defined(UV2_USED) || defined(USE_LIGHTMAP) uv2_interp = uv2_attrib; @@ -290,9 +284,7 @@ layout(location = 1) in vec3 normal_interp; layout(location = 2) in vec4 color_interp; #endif -#if defined(UV_USED) layout(location = 3) in vec2 uv_interp; -#endif #if defined(UV2_USED) || defined(USE_LIGHTMAP) layout(location = 4) in vec2 uv2_interp; @@ -441,7 +433,7 @@ 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 shadow_attenuation, vec3 diffuse_color, float roughness, float metallic, float specular, float specular_blob_intensity, +void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float attenuation, vec3 shadow_attenuation, vec3 diffuse_color, float roughness, float metallic, float specular, float specular_blob_intensity, #ifdef LIGHT_BACKLIGHT_USED vec3 backlight, #endif @@ -481,7 +473,7 @@ LIGHT_SHADER_CODE /* clang-format on */ #else - float NdotL = dot(N, L); + float NdotL = min(A + dot(N, L), 1.0); float cNdotL = max(NdotL, 0.0); // clamped NdotL float NdotV = dot(N, V); float cNdotV = max(NdotV, 0.0); @@ -491,11 +483,11 @@ LIGHT_SHADER_CODE #endif #if defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED) - float cNdotH = max(dot(N, H), 0.0); + float cNdotH = clamp(A + dot(N, H), 0.0, 1.0); #endif #if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED) - float cLdotH = max(dot(L, H), 0.0); + float cLdotH = clamp(A + dot(L, H), 0.0, 1.0); #endif if (metallic < 1.0) { @@ -613,7 +605,7 @@ LIGHT_SHADER_CODE #elif defined(SPECULAR_PHONG) vec3 R = normalize(-reflect(L, N)); - float cRdotV = max(0.0, dot(R, V)); + 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)); @@ -686,48 +678,113 @@ LIGHT_SHADER_CODE #ifndef USE_NO_SHADOWS -float sample_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) { +// Produces cheap but low-quality white noise, nothing special +float quick_hash(vec2 pos) { + return fract(sin(dot(pos * 19.19, vec2(49.5791, 97.413))) * 49831.189237); +} + +float sample_directional_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) { + + vec2 pos = coord.xy; + float depth = coord.z; + + //if only one sample is taken, take it from the center + if (scene_data.directional_soft_shadow_samples == 1) { + 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; + + for (uint i = 0; i < scene_data.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)); +} + +float sample_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) { vec2 pos = coord.xy; float depth = coord.z; - switch (scene_data.shadow_filter_mode) { - case SHADOW_MODE_NO_FILTER: { - return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0)); - }; - case SHADOW_MODE_PCF5: { - float avg = textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(shadow_pixel_size.x, 0.0), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(-shadow_pixel_size.x, 0.0), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(0.0, shadow_pixel_size.y), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(0.0, -shadow_pixel_size.y), depth, 1.0)); - return avg * (1.0 / 5.0); - }; - case SHADOW_MODE_PCF13: { - - float avg = textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(shadow_pixel_size.x, 0.0), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(-shadow_pixel_size.x, 0.0), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(0.0, shadow_pixel_size.y), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(0.0, -shadow_pixel_size.y), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(shadow_pixel_size.x, shadow_pixel_size.y), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(-shadow_pixel_size.x, shadow_pixel_size.y), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(shadow_pixel_size.x, -shadow_pixel_size.y), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(-shadow_pixel_size.x, -shadow_pixel_size.y), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(shadow_pixel_size.x * 2.0, 0.0), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(-shadow_pixel_size.x * 2.0, 0.0), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(0.0, shadow_pixel_size.y * 2.0), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(0.0, -shadow_pixel_size.y * 2.0), depth, 1.0)); - return avg * (1.0 / 13.0); - }; + //if only one sample is taken, take it from the center + if (scene_data.soft_shadow_samples == 1) { + 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)); } - return 0; + float avg = 0.0; + + for (uint i = 0; i < scene_data.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)); +} + +float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex_scale) { + + //find blocker + float blocker_count = 0.0; + float blocker_average = 0.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)); + } + + for (uint i = 0; i < scene_data.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) { + blocker_average += d; + blocker_count += 1.0; + } + } + + if (blocker_count > 0.0) { + + //blockers found, do soft shadow + blocker_average /= blocker_count; + float penumbra = (pssm_coord.z - blocker_average) / blocker_average; + tex_scale *= penumbra; + + float s = 0.0; + for (uint i = 0; i < scene_data.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); + + } else { + //no blockers found, so no shadow + return 1.0; + } } #endif //USE_NO_SHADOWS -void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 albedo, float roughness, float metallic, float specular, float p_blob_intensity, +void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 albedo, float roughness, float metallic, float specular, float p_blob_intensity, #ifdef LIGHT_BACKLIGHT_USED vec3 backlight, #endif @@ -760,6 +817,13 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a vec3 shadow_attenuation = vec3(1.0); vec4 color_specular = unpackUnorm4x8(lights.data[idx].color_specular); color_specular.rgb *= attenuation_energy.y; + float size_A = 0.0; + + if (lights.data[idx].size > 0.0) { + + float t = lights.data[idx].size / max(0.001, light_length); + size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t)); + } #ifdef LIGHT_TRANSMITTANCE_USED float transmittance_z = transmittance_depth; //no transmittance by default @@ -773,7 +837,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a vec4 v = vec4(vertex, 1.0); vec4 splane = (lights.data[idx].shadow_matrix * v); - float shadow_len = length(splane.xyz); + float shadow_len = length(splane.xyz); //need to remember shadow len from here { vec3 nofs = normal_interp * lights.data[idx].shadow_normal_bias / lights.data[idx].inv_radius; @@ -782,35 +846,138 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a splane = (lights.data[idx].shadow_matrix * v); } - splane.xyz = normalize(splane.xyz); - vec4 clamp_rect = lights.data[idx].atlas_rect; + float shadow; + + if (lights.data[idx].soft_shadow_size > 0.0) { + //soft shadow + + //find blocker + + float blocker_count = 0.0; + float blocker_average = 0.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)); + } + + 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)); + float z_norm = shadow_len * lights.data[idx].inv_radius; + + tangent *= lights.data[idx].soft_shadow_size * lights.data[idx].soft_shadow_scale; + bitangent *= lights.data[idx].soft_shadow_size * lights.data[idx].soft_shadow_scale; + + for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) { + + vec2 disk = disk_rotation * scene_data.penumbra_shadow_kernel[i].xy; - if (splane.z >= 0.0) { + vec3 pos = splane.xyz + tangent * disk.x + bitangent * disk.y; - splane.z += 1.0; + pos = normalize(pos); + vec4 uv_rect = lights.data[idx].atlas_rect; - clamp_rect.y += clamp_rect.w; + if (pos.z >= 0.0) { + pos.z += 1.0; + uv_rect.y += uv_rect.w; + } else { + + pos.z = 1.0 - pos.z; + } + + pos.xy /= pos.z; + + pos.xy = pos.xy * 0.5 + 0.5; + pos.xy = uv_rect.xy + pos.xy * uv_rect.zw; + + float d = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), pos.xy, 0.0).r; + if (d < z_norm) { + blocker_average += d; + blocker_count += 1.0; + } + } + + if (blocker_count > 0.0) { + + //blockers found, do soft shadow + blocker_average /= blocker_count; + float penumbra = (z_norm - blocker_average) / blocker_average; + tangent *= penumbra; + bitangent *= penumbra; + + z_norm -= lights.data[idx].inv_radius * lights.data[idx].shadow_bias; + + shadow = 0.0; + for (uint i = 0; i < scene_data.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; + + pos = normalize(pos); + vec4 uv_rect = lights.data[idx].atlas_rect; + + if (pos.z >= 0.0) { + + pos.z += 1.0; + uv_rect.y += uv_rect.w; + } else { + + pos.z = 1.0 - pos.z; + } + + pos.xy /= pos.z; + + pos.xy = pos.xy * 0.5 + 0.5; + pos.xy = uv_rect.xy + pos.xy * uv_rect.zw; + shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(pos.xy, z_norm, 1.0)); + } + + shadow /= float(scene_data.penumbra_shadow_samples); + + } else { + //no blockers found, so no shadow + shadow = 1.0; + } } else { - splane.z = 1.0 - splane.z; - } - splane.xy /= splane.z; + splane.xyz = normalize(splane.xyz); + vec4 clamp_rect = lights.data[idx].atlas_rect; + + 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.xy * 0.5 + 0.5; - splane.z = (shadow_len - lights.data[idx].shadow_bias) * 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 - float shadow = sample_shadow(shadow_atlas, scene_data.shadow_atlas_pixel_size, splane); + splane.xy /= splane.z; + + splane.xy = splane.xy * 0.5 + 0.5; + splane.z = (shadow_len - lights.data[idx].shadow_bias) * 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, lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, splane); + } #ifdef LIGHT_TRANSMITTANCE_USED { + vec4 clamp_rect = lights.data[idx].atlas_rect; + //redo shadowmapping, but shrink the model a bit to avoid arctifacts splane = (lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * lights.data[idx].transmittance_bias, 1.0)); - shadow_len = length(splane); - splane = normalize(splane); + shadow_len = length(splane.xyz); + splane = normalize(splane.xyz); if (splane.z >= 0.0) { @@ -832,11 +999,74 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a } #endif - shadow_attenuation = mix(shadow_color_enabled.rgb, vec3(1.0), shadow); + vec3 no_shadow = vec3(1.0); + + if (lights.data[idx].projector_rect != vec4(0.0)) { + + vec3 local_v = (lights.data[idx].shadow_matrix * vec4(vertex, 1.0)).xyz; + local_v = normalize(local_v); + + vec4 atlas_rect = 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.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 = (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; + } + + 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; + + vec3 local_v_ddy = (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; + } + + 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; + } + + 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); + } + + shadow_attenuation = mix(shadow_color_enabled.rgb, no_shadow, shadow); } #endif //USE_NO_SHADOWS - light_compute(normal, normalize(light_rel_vec), eye_vec, color_specular.rgb, light_attenuation, shadow_attenuation, albedo, roughness, metallic, specular, color_specular.a * p_blob_intensity, + light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color_specular.rgb, light_attenuation, shadow_attenuation, albedo, roughness, metallic, specular, color_specular.a * p_blob_intensity, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif @@ -863,7 +1093,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a specular_light); } -void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 albedo, float roughness, float metallic, float specular, float p_blob_intensity, +void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 albedo, float roughness, float metallic, float specular, float p_blob_intensity, #ifdef LIGHT_BACKLIGHT_USED vec3 backlight, #endif @@ -903,6 +1133,13 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a vec4 color_specular = unpackUnorm4x8(lights.data[idx].color_specular); color_specular.rgb *= attenuation_energy.y; + float size_A = 0.0; + + if (lights.data[idx].size > 0.0) { + + float t = lights.data[idx].size / max(0.001, light_length); + size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t)); + } /* if (lights.data[idx].atlas_rect!=vec4(0.0)) { //use projector texture @@ -920,23 +1157,110 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a v.xyz -= spot_dir * lights.data[idx].shadow_bias; - float depth_bias_scale = 1.0 / (max(0.0001, dot(spot_dir, -light_rel_vec) * lights.data[idx].inv_radius)); //the closer to the light origin, the more you have to offset to reach 1px in the map + float z_norm = dot(spot_dir, -light_rel_vec) * 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)))) * 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 - lights.data[idx].position) * lights.data[idx].inv_radius; + + float shadow; + vec4 splane = (lights.data[idx].shadow_matrix * v); splane /= splane.w; - splane.z = dot(spot_dir, v.xyz - lights.data[idx].position) * lights.data[idx].inv_radius; - float shadow = sample_shadow(shadow_atlas, scene_data.shadow_atlas_pixel_size, splane); - shadow_attenuation = mix(shadow_color_enabled.rgb, vec3(1.0), shadow); + if (lights.data[idx].soft_shadow_size > 0.0) { + //soft shadow + + //find blocker + + vec2 shadow_uv = splane.xy * lights.data[idx].atlas_rect.zw + lights.data[idx].atlas_rect.xy; + + float blocker_count = 0.0; + float blocker_average = 0.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 uv_size = lights.data[idx].soft_shadow_size * z_norm * lights.data[idx].soft_shadow_scale; + vec2 clamp_max = lights.data[idx].atlas_rect.xy + lights.data[idx].atlas_rect.zw; + for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) { + + vec2 suv = shadow_uv + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size; + suv = clamp(suv, 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) { + blocker_average += d; + blocker_count += 1.0; + } + } + + if (blocker_count > 0.0) { + + //blockers found, do soft shadow + blocker_average /= blocker_count; + float penumbra = (z_norm - blocker_average) / blocker_average; + uv_size *= penumbra; + + shadow = 0.0; + for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) { + vec2 suv = shadow_uv + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size; + suv = clamp(suv, lights.data[idx].atlas_rect.xy, clamp_max); + shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(suv, z_norm, 1.0)); + } + + shadow /= float(scene_data.penumbra_shadow_samples); + + } else { + //no blockers found, so no shadow + shadow = 1.0; + } + + } else { + //hard shadow + vec4 shadow_uv = vec4(splane.xy * lights.data[idx].atlas_rect.zw + lights.data[idx].atlas_rect.xy, z_norm, 1.0); + + shadow = sample_pcf_shadow(shadow_atlas, lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, shadow_uv); + } + + vec3 no_shadow = vec3(1.0); + + if (lights.data[idx].projector_rect != vec4(0.0)) { + + splane = (lights.data[idx].shadow_matrix * vec4(vertex, 1.0)); + splane /= splane.w; + + vec2 proj_uv = splane.xy * lights.data[idx].projector_rect.zw; + + //ensure we have proper mipmaps + vec4 splane_ddx = (lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddx, 1.0)); + splane_ddx /= splane_ddx.w; + vec2 proj_uv_ddx = splane_ddx.xy * lights.data[idx].projector_rect.zw - proj_uv; + + vec4 splane_ddy = (lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddy, 1.0)); + splane_ddy /= splane_ddy.w; + vec2 proj_uv_ddy = splane_ddy.xy * lights.data[idx].projector_rect.zw - proj_uv; + + vec4 proj = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), proj_uv + lights.data[idx].projector_rect.xy, proj_uv_ddx, proj_uv_ddy); + no_shadow = mix(no_shadow, proj.rgb, proj.a); + } + + shadow_attenuation = mix(shadow_color_enabled.rgb, no_shadow, shadow); #ifdef LIGHT_TRANSMITTANCE_USED { splane = (lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * lights.data[idx].transmittance_bias, 1.0)); splane /= splane.w; + splane.xy = splane.xy * lights.data[idx].atlas_rect.zw + 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 @@ -950,7 +1274,7 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a #endif //USE_NO_SHADOWS - light_compute(normal, normalize(light_rel_vec), eye_vec, color_specular.rgb, light_attenuation, shadow_attenuation, albedo, roughness, metallic, specular, color_specular.a * p_blob_intensity, + light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color_specular.rgb, light_attenuation, shadow_attenuation, albedo, roughness, metallic, specular, color_specular.a * p_blob_intensity, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif @@ -1370,9 +1694,7 @@ void main() { } #endif -#if defined(UV_USED) vec2 uv = uv_interp; -#endif #if defined(UV2_USED) || defined(USE_LIGHTMAP) vec2 uv2 = uv2_interp; @@ -1454,7 +1776,81 @@ FRAGMENT_SHADER_CODE discard; } #endif + /////////////////////// DECALS //////////////////////////////// + +#ifndef MODE_RENDER_DEPTH + + uvec4 cluster_cell = texture(usampler3D(cluster_texture, material_samplers[SAMPLER_NEAREST_CLAMP]), vec3(screen_uv, (abs(vertex.z) - scene_data.z_near) / (scene_data.z_far - scene_data.z_near))); + //used for interpolating anything cluster related + vec3 vertex_ddx = dFdx(vertex); + vec3 vertex_ddy = dFdy(vertex); + + { // process decals + + uint decal_count = cluster_cell.w >> CLUSTER_COUNTER_SHIFT; + uint decal_pointer = cluster_cell.w & CLUSTER_POINTER_MASK; + + //do outside for performance and avoiding arctifacts + + for (uint i = 0; i < decal_count; i++) { + + uint decal_index = cluster_data.indices[decal_pointer + i]; + if (!bool(decals.data[decal_index].mask & instances.data[instance_index].layer_mask)) { + continue; //not masked + } + + vec3 uv_local = (decals.data[decal_index].xform * vec4(vertex, 1.0)).xyz; + if (any(lessThan(uv_local, vec3(0.0, -1.0, 0.0))) || any(greaterThan(uv_local, vec3(1.0)))) { + 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); + } + + 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); + 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; + 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 + decal_normal = (decals.data[decal_index].normal_xform * decal_normal.xzy).xyz; + + normal = normalize(mix(normal, decal_normal, decal_albedo.a)); + } + + 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; +#if defined(AO_USED) + ao = mix(ao, decal_orm.r, decal_albedo.a); +#endif + roughness = mix(roughness, decal_orm.g, decal_albedo.a); + metallic = mix(metallic, decal_orm.b, decal_albedo.a); + } + } + 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; + } + } + } + +#endif //not render depth /////////////////////// LIGHTING ////////////////////////////// //apply energy conservation @@ -1559,8 +1955,6 @@ FRAGMENT_SHADER_CODE } #endif - uvec4 cluster_cell = texture(usampler3D(cluster_texture, material_samplers[SAMPLER_NEAREST_CLAMP]), vec3(screen_uv, (abs(vertex.z) - scene_data.z_near) / (scene_data.z_far - scene_data.z_near))); - { // process reflections vec4 reflection_accum = vec4(0.0, 0.0, 0.0, 0.0); @@ -1636,13 +2030,28 @@ FRAGMENT_SHADER_CODE normal_bias -= light_dir * dot(light_dir, normal_bias); \ m_var.xyz += normal_bias; + float shadow = 0.0; + 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); + 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); + } + shadow_color = directional_lights.data[i].shadow_color1.rgb; + #ifdef LIGHT_TRANSMITTANCE_USED { vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.x, 1.0); @@ -1663,6 +2072,18 @@ FRAGMENT_SHADER_CODE 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; + 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); + } + shadow_color = directional_lights.data[i].shadow_color2.rgb; #ifdef LIGHT_TRANSMITTANCE_USED { @@ -1684,6 +2105,18 @@ FRAGMENT_SHADER_CODE 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; + 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); + } + shadow_color = directional_lights.data[i].shadow_color3.rgb; #ifdef LIGHT_TRANSMITTANCE_USED { @@ -1706,7 +2139,20 @@ FRAGMENT_SHADER_CODE 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; + 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); + } + shadow_color = directional_lights.data[i].shadow_color4.rgb; + #ifdef LIGHT_TRANSMITTANCE_USED { vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.w, 1.0); @@ -1722,40 +2168,72 @@ FRAGMENT_SHADER_CODE #endif } - pssm_coord /= pssm_coord.w; - - float shadow = sample_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size, pssm_coord); - if (directional_lights.data[i].blend_splits) { vec3 shadow_color_blend = vec3(0.0); float pssm_blend; + float shadow2; 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); + } + 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; } 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); + shadow_color_blend = directional_lights.data[i].shadow_color3.rgb; } 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_coord /= pssm_coord.w; + pssm_blend = sqrt(pssm_blend); - float shadow2 = sample_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size, pssm_coord); shadow = mix(shadow, shadow2, pssm_blend); shadow_color = mix(shadow_color, shadow_color_blend, pssm_blend); } @@ -1767,7 +2245,7 @@ FRAGMENT_SHADER_CODE #undef BIAS_FUNC } - light_compute(normal, directional_lights.data[i].direction, normalize(view), directional_lights.data[i].color * directional_lights.data[i].energy, 1.0, shadow_attenuation, albedo, roughness, metallic, specular, directional_lights.data[i].specular * specular_blob_intensity, + light_compute(normal, directional_lights.data[i].direction, normalize(view), directional_lights.data[i].size, directional_lights.data[i].color * directional_lights.data[i].energy, 1.0, shadow_attenuation, albedo, roughness, metallic, specular, directional_lights.data[i].specular * specular_blob_intensity, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif @@ -1808,7 +2286,7 @@ FRAGMENT_SHADER_CODE continue; //not masked } - light_process_omni(light_index, vertex, view, normal, albedo, roughness, metallic, specular, specular_blob_intensity, + light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, albedo, roughness, metallic, specular, specular_blob_intensity, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif @@ -1847,7 +2325,7 @@ FRAGMENT_SHADER_CODE continue; //not masked } - light_process_spot(light_index, vertex, view, normal, albedo, roughness, metallic, specular, specular_blob_intensity, + light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, albedo, roughness, metallic, specular, specular_blob_intensity, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif diff --git a/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl b/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl index e3f1e650ed..ce4fabf9f2 100644 --- a/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl +++ b/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl @@ -22,10 +22,6 @@ draw_call; #define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10 #define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11 -#define SHADOW_MODE_NO_FILTER 0 -#define SHADOW_MODE_PCF5 1 -#define SHADOW_MODE_PCF13 2 - layout(set = 0, binding = 1) uniform sampler material_samplers[12]; layout(set = 0, binding = 2) uniform sampler shadow_sampler; @@ -45,7 +41,18 @@ layout(set = 0, binding = 3, std140) uniform SceneData { float reflection_multiplier; // one normally, zero when rendering reflections bool pancake_shadows; - uint shadow_filter_mode; + uint pad; + + //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]; + + uint directional_penumbra_shadow_samples; + uint directional_soft_shadow_samples; + uint penumbra_shadow_samples; + uint soft_shadow_samples; vec4 ambient_light_color_energy; @@ -127,12 +134,12 @@ struct InstanceData { mat4 transform; mat4 normal_transform; uint flags; - uint instance_ofs; //instance_offset in instancing/skeleton buffer + uint instance_uniforms_ofs; //base offset in global buffer for instance variables uint gi_offset; //GI information when using lightmapping (VCT or lightmap) uint layer_mask; }; -layout(set = 0, binding = 4, std430) buffer Instances { +layout(set = 0, binding = 4, std430) restrict readonly buffer Instances { InstanceData data[]; } instances; @@ -141,20 +148,24 @@ struct LightData { //this structure needs to be as packed as possible vec3 position; float inv_radius; vec3 direction; + float size; uint attenuation_energy; //attenuation uint color_specular; //rgb color, a specular (8 bit unorm) uint cone_attenuation_angle; // attenuation and angle, (16bit float) - uint mask; uint shadow_color_enabled; //shadow rgb color, a>0.5 enabled (8bit unorm) - vec4 atlas_rect; // used for spot + vec4 atlas_rect; // rect in the shadow atlas mat4 shadow_matrix; float shadow_bias; float shadow_normal_bias; float transmittance_bias; - uint pad; + 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 + uint mask; + uint pad[2]; + vec4 projector_rect; //projector rect in srgb decal atlas }; -layout(set = 0, binding = 5, std430) buffer Lights { +layout(set = 0, binding = 5, std430) restrict readonly buffer Lights { LightData data[]; } lights; @@ -180,11 +191,11 @@ struct DirectionalLightData { vec3 direction; float energy; vec3 color; + float size; float specular; uint mask; - uint pad0; - uint pad1; - uint pad2; + float softshadow_angle; + float soft_shadow_scale; bool blend_splits; bool shadow_enabled; float fade_from; @@ -193,6 +204,7 @@ struct DirectionalLightData { vec4 shadow_normal_bias; vec4 shadow_transmittance_bias; vec4 shadow_transmittance_z_scale; + vec4 shadow_range_begin; vec4 shadow_split_offsets; mat4 shadow_matrix1; mat4 shadow_matrix2; @@ -202,6 +214,10 @@ struct DirectionalLightData { vec4 shadow_color2; vec4 shadow_color3; vec4 shadow_color4; + vec2 uv_scale1; + vec2 uv_scale2; + vec2 uv_scale3; + vec2 uv_scale4; }; layout(set = 0, binding = 7, std140) uniform DirectionalLights { @@ -236,14 +252,45 @@ layout(set = 0, binding = 9) uniform texture3D gi_probe_textures[MAX_GI_PROBE_TE #define CLUSTER_POINTER_MASK ((1 << CLUSTER_COUNTER_SHIFT) - 1) #define CLUSTER_COUNTER_MASK 0xfff -layout(set = 0, binding = 10) uniform utexture3D cluster_texture; +layout(set = 0, binding = 10) uniform texture2D decal_atlas; +layout(set = 0, binding = 11) uniform texture2D decal_atlas_srgb; + +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; + uint mask; + float upper_fade; + float lower_fade; + mat3x4 normal_xform; + vec3 normal; + float normal_fade; +}; + +layout(set = 0, binding = 12, std430) restrict readonly buffer Decals { + DecalData data[]; +} +decals; -layout(set = 0, binding = 11, std430) buffer ClusterData { +layout(set = 0, binding = 13) uniform utexture3D cluster_texture; + +layout(set = 0, binding = 14, std430) restrict readonly buffer ClusterData { uint indices[]; } cluster_data; -layout(set = 0, binding = 12) uniform texture2D directional_shadow_atlas; +layout(set = 0, binding = 15) uniform texture2D directional_shadow_atlas; + +layout(set = 0, binding = 16, std430) restrict readonly buffer GlobalVariableData { + vec4 data[]; +} +global_variables; // decal atlas @@ -275,7 +322,7 @@ layout(set = 3, binding = 4) uniform texture2D ao_buffer; /* Set 4 Skeleton & Instancing (Multimesh) */ -layout(set = 4, binding = 0, std430) buffer Transforms { +layout(set = 4, binding = 0, std430) restrict readonly buffer Transforms { vec4 data[]; } transforms; diff --git a/servers/rendering/rasterizer_rd/shaders/sky.glsl b/servers/rendering/rasterizer_rd/shaders/sky.glsl index 469925839a..536077980d 100644 --- a/servers/rendering/rasterizer_rd/shaders/sky.glsl +++ b/servers/rendering/rasterizer_rd/shaders/sky.glsl @@ -58,6 +58,11 @@ params; layout(set = 0, binding = 0) uniform sampler material_samplers[12]; +layout(set = 0, binding = 1, std430) restrict readonly buffer GlobalVariableData { + vec4 data[]; +} +global_variables; + #ifdef USE_MATERIAL_UNIFORMS layout(set = 1, binding = 0, std140) uniform MaterialUniforms{ /* clang-format off */ @@ -96,9 +101,8 @@ layout(set = 2, binding = 2) uniform texture2D quarter_res; #endif struct DirectionalLightData { - vec3 direction; - float energy; - vec3 color; + vec4 direction_energy; + vec4 color_size; bool enabled; }; @@ -178,4 +182,10 @@ FRAGMENT_SHADER_CODE frag_color.rgb = color * params.position_multiplier.w; frag_color.a = alpha; + + // Blending is disabled for Sky, so alpha doesn't blend + // alpha is used for subsurface scattering so make sure it doesn't get applied to Sky + if (!AT_CUBEMAP_PASS && !AT_HALF_RES_PASS && !AT_QUARTER_RES_PASS) { + frag_color.a = 0.0; + } } diff --git a/servers/rendering/rasterizer_rd/shaders/specular_merge.glsl b/servers/rendering/rasterizer_rd/shaders/specular_merge.glsl index b28250318e..b24f7dccc7 100644 --- a/servers/rendering/rasterizer_rd/shaders/specular_merge.glsl +++ b/servers/rendering/rasterizer_rd/shaders/specular_merge.glsl @@ -48,8 +48,8 @@ void main() { frag_color.a = 0.0; #ifdef MODE_SSR - vec4 ssr = texture(ssr, uv_interp); - frag_color.rgb = mix(frag_color.rgb, ssr.rgb, ssr.a); + vec4 ssr_color = texture(ssr, uv_interp); + frag_color.rgb = mix(frag_color.rgb, ssr_color.rgb, ssr_color.a); #endif #ifdef MODE_MERGE diff --git a/servers/rendering/rasterizer_rd/shaders/tonemap.glsl b/servers/rendering/rasterizer_rd/shaders/tonemap.glsl index 524ca5e2ea..a142d263e2 100644 --- a/servers/rendering/rasterizer_rd/shaders/tonemap.glsl +++ b/servers/rendering/rasterizer_rd/shaders/tonemap.glsl @@ -48,6 +48,10 @@ layout(push_constant, binding = 1, std430) uniform Params { float exposure; float white; float auto_exposure_grey; + + vec2 pixel_size; + bool use_fxaa; + uint pad; } params; @@ -255,16 +259,63 @@ vec3 apply_color_correction(vec3 color, sampler3D correction_tex) { return texture(correction_tex, color).rgb; } +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; + vec3 rgbM = color; + vec3 luma = vec3(0.299, 0.587, 0.114); + float lumaNW = dot(rgbNW, luma); + float lumaNE = dot(rgbNE, luma); + float lumaSW = dot(rgbSW, luma); + float lumaSE = dot(rgbSE, luma); + float lumaM = dot(rgbM, luma); + float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); + float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); + + vec2 dir; + dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); + dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); + + float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * + (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; + + vec3 rgbA = 0.5 * (textureLod(source_color, uv_interp + dir * (1.0 / 3.0 - 0.5), 0.0).xyz * exposure + textureLod(source_color, uv_interp + dir * (2.0 / 3.0 - 0.5), 0.0).xyz) * exposure; + vec3 rgbB = rgbA * 0.5 + 0.25 * (textureLod(source_color, uv_interp + dir * -0.5, 0.0).xyz * exposure + + textureLod(source_color, uv_interp + dir * 0.5, 0.0).xyz * exposure); + + float lumaB = dot(rgbB, luma); + if ((lumaB < lumaMin) || (lumaB > lumaMax)) + return rgbA; + else + return rgbB; +} + void main() { vec3 color = textureLod(source_color, uv_interp, 0.0f).rgb; // Exposure + float exposure = params.exposure; + if (params.use_auto_exposure) { - color /= 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.auto_exposure_grey); } - color *= params.exposure; + color *= exposure; // Early Tonemap & SRGB Conversion @@ -274,6 +325,9 @@ void main() { color.rgb = mix(color.rgb, glow, params.glow_intensity); } + if (params.use_fxaa) { + color = do_fxaa(color, exposure, uv_interp); + } color = apply_tonemapping(color, params.white); color = linear_to_srgb(color); // regular linear -> SRGB conversion |