diff options
Diffstat (limited to 'servers/rendering/renderer_rd/shaders')
30 files changed, 1371 insertions, 800 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 index b1d1c2365e..f8b4e3f610 100644 --- a/servers/rendering/renderer_rd/shaders/blur_raster.glsl +++ b/servers/rendering/renderer_rd/shaders/blur_raster.glsl @@ -37,33 +37,9 @@ layout(set = 1, binding = 0) uniform sampler2D source_auto_exposure; layout(location = 0) out vec4 frag_color; -//DOF -#ifdef MODE_DOF_BLUR - -layout(set = 1, binding = 0) uniform sampler2D dof_source_depth; - -#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() { + // 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; @@ -155,74 +131,8 @@ void main() { #endif -#ifdef MODE_DOF_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)); - } - - // mix near and far blur amount - float amount = 1.0; - if (bool(blur.flags & FLAG_DOF_FAR)) { - amount *= 1.0 - smoothstep(blur.dof_far_begin, blur.dof_far_end, depth); - } - if (bool(blur.flags & FLAG_DOF_NEAR)) { - amount *= smoothstep(blur.dof_near_end, blur.dof_near_begin, depth); - } - amount = 1.0 - amount; - - if (amount > 0.0) { - 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)); - } - - // mix near and far blur amount - float tap_amount = 1.0; - if (bool(blur.flags & FLAG_DOF_FAR)) { - tap_amount *= mix(1.0 - smoothstep(blur.dof_far_begin, blur.dof_far_end, tap_depth), 0.0, int_ofs == 0); - } - if (bool(blur.flags & FLAG_DOF_NEAR)) { - tap_amount *= mix(smoothstep(blur.dof_near_end, blur.dof_near_begin, tap_depth), 0.0, int_ofs == 0); - } - tap_amount = 1.0 - tap_amount; - - 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; - } else { - // we are in focus, don't waste time - frag_color = texture(source_color, uv_interp, 0.0); - } - +#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 index 6ea968e595..52bf2886b5 100644 --- a/servers/rendering/renderer_rd/shaders/blur_raster_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/blur_raster_inc.glsl @@ -1,8 +1,6 @@ #define FLAG_HORIZONTAL (1 << 0) #define FLAG_USE_ORTHOGONAL_PROJECTION (1 << 1) #define FLAG_GLOW_FIRST_PASS (1 << 2) -#define FLAG_DOF_FAR (1 << 3) -#define FLAG_DOF_NEAR (1 << 4) layout(push_constant, binding = 1, std430) uniform Blur { vec2 pixel_size; @@ -19,18 +17,5 @@ layout(push_constant, binding = 1, std430) uniform Blur { float glow_white; float glow_luminance_cap; float glow_auto_exposure_grey; - - // DOF. - float dof_far_begin; - float dof_far_end; - float dof_near_begin; - float dof_near_end; - - float dof_radius; - float dof_pad[3]; - - vec2 dof_dir; - float camera_z_far; - float camera_z_near; } 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 a443bcdcb8..2911e8b731 100644 --- a/servers/rendering/renderer_rd/shaders/canvas.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas.glsl @@ -458,6 +458,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; @@ -485,7 +493,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_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/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_inc.glsl b/servers/rendering/renderer_rd/shaders/luminance_reduce_raster_inc.glsl index ed389ffe56..3cde9923fa 100644 --- a/servers/rendering/renderer_rd/shaders/luminance_reduce_raster_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/luminance_reduce_raster_inc.glsl @@ -6,6 +6,6 @@ layout(push_constant, binding = 1, std430) uniform PushConstant { float exposure_adjust; float min_luminance; float max_luminance; - float pad; + uint pad1; } settings; diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl index b3a349c948..8cb56fbc83 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl @@ -118,7 +118,7 @@ void main() { 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); } @@ -374,6 +374,9 @@ 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 */ @@ -466,6 +469,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" #include "scene_forward_gi_inc.glsl" @@ -876,7 +884,7 @@ 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 = dFdy(normal); float variance = scene_data.roughness_limiter_amount * (dot(dndu, dndu) + dot(dndv, dndv)); @@ -895,6 +903,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 @@ -907,6 +916,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; } @@ -1594,7 +1604,7 @@ void main() { 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); @@ -1670,7 +1680,7 @@ void main() { 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); 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 7039ea2942..f3db4abe3b 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl @@ -208,11 +208,10 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte //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 * unpackUnorm4x8(orms).w; #elif defined(SPECULAR_PHONG) @@ -220,10 +219,9 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte 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 * unpackUnorm4x8(orms).w; #elif defined(SPECULAR_TOON) @@ -281,7 +279,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte } #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) @@ -290,7 +288,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte #ifndef USE_NO_SHADOWS // 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))); @@ -322,7 +320,7 @@ float sample_directional_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, ve 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; @@ -348,6 +346,49 @@ float sample_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) { 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 == 1) { + 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) { //find blocker float blocker_count = 0.0; @@ -405,21 +446,21 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) { #ifndef USE_NO_SHADOWS 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; @@ -439,10 +480,10 @@ 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; @@ -451,18 +492,17 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) { 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; @@ -487,18 +527,18 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) { shadow = 0.0; 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; @@ -513,25 +553,19 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) { shadow = 1.0; } } else { - 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); + 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); } return shadow; @@ -615,13 +649,11 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 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; @@ -701,30 +733,23 @@ float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) { 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; + 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))); - //adjust with bias - z_norm = dot(spot_dir, v.xyz - spot_lights.data[idx].position) * spot_lights.data[idx].inv_radius; - - 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; + 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; @@ -770,11 +795,9 @@ float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) { //no blockers found, so no shadow shadow = 1.0; } - } else { //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); } @@ -946,7 +969,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 70900a847c..c3c4139450 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl @@ -59,27 +59,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,7 +92,7 @@ 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 @@ -124,7 +124,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); } @@ -372,55 +372,68 @@ void main() { /* Specialization Constants */ -/* Specialization Constants (Toggles) */ +#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 = 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; +layout(constant_id = 5) const uint sc_directional_soft_shadow_samples = 4; +layout(constant_id = 6) const uint sc_directional_penumbra_shadow_samples = 4; -/* Specialization Constants (Values) */ +layout(constant_id = 8) const bool sc_projector_use_mipmaps = true; -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 = 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; -layout(constant_id = 8) const uint sc_directional_soft_shadow_samples = 4; -layout(constant_id = 9) const uint sc_directional_penumbra_shadow_samples = 4; +#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 = 10) const bool sc_decal_use_mipmaps = true; -layout(constant_id = 11) const bool sc_projector_use_mipmaps = true; +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 @@ -482,7 +495,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 @@ -491,6 +504,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) @@ -726,7 +744,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); } @@ -744,7 +762,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; @@ -765,25 +783,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 @@ -793,7 +821,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); @@ -802,7 +835,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 @@ -812,7 +849,7 @@ 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 = dFdy(normal); float variance = scene_data.roughness_limiter_amount * (dot(dndu, dndu) + dot(dndv, dndv)); @@ -831,6 +868,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 @@ -843,6 +881,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; } @@ -940,7 +979,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); @@ -1006,7 +1045,7 @@ void main() { // LIGHTING #if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) - { //directional light + if (!sc_disable_directional_lights) { //directional light // Do shadow and lighting in two passes to reduce register pressure uint shadow0 = 0; @@ -1336,7 +1375,7 @@ void main() { } } //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; @@ -1350,7 +1389,7 @@ 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); @@ -1383,7 +1422,7 @@ void main() { } } //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++) { @@ -1398,7 +1437,7 @@ 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); @@ -1514,12 +1553,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 d9682d7b23..dd8879acb4 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl @@ -16,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 @@ -93,7 +93,7 @@ directional_lights; #define LIGHTMAP_FLAG_USE_SPECULAR_DIRECTION 2 struct Lightmap { - mat3 normal_xform; + mediump mat3 normal_xform; }; layout(set = 0, binding = 9, std140) restrict readonly buffer Lightmaps { @@ -102,7 +102,7 @@ layout(set = 0, binding = 9, std140) restrict readonly buffer Lightmaps { lightmaps; struct LightmapCapture { - vec4 sh[9]; + mediump vec4 sh[9]; }; layout(set = 0, binding = 10, std140) restrict readonly buffer LightmapCaptures { @@ -110,8 +110,8 @@ layout(set = 0, binding = 10, std140) restrict readonly buffer LightmapCaptures } lightmap_captures; -layout(set = 0, binding = 11) uniform texture2D decal_atlas; -layout(set = 0, binding = 12) 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 = 13, std430) restrict readonly buffer Decals { DecalData data[]; @@ -119,72 +119,72 @@ layout(set = 0, binding = 13, std430) restrict readonly buffer Decals { decals; layout(set = 0, binding = 14, std430) restrict readonly buffer GlobalVariableData { - vec4 data[]; + 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; // only used for multiview - mat4 projection_matrix_view[MAX_VIEWS]; - mat4 inv_projection_matrix_view[MAX_VIEWS]; + highp mat4 projection_matrix_view[MAX_VIEWS]; + highp mat4 inv_projection_matrix_view[MAX_VIEWS]; - vec2 viewport_size; - vec2 screen_pixel_size; + highp vec2 viewport_size; + highp vec2 screen_pixel_size; // 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]; + 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; + mediump float roughness_limiter_amount; + mediump float roughness_limiter_limit; uvec2 roughness_limiter_pad; - vec4 ao_color; + mediump vec4 ao_color; 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; @@ -195,30 +195,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/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/sky.glsl b/servers/rendering/renderer_rd/shaders/sky.glsl index 41c6325bc5..d07a454ade 100644 --- a/servers/rendering/renderer_rd/shaders/sky.glsl +++ b/servers/rendering/renderer_rd/shaders/sky.glsl @@ -17,6 +17,8 @@ layout(push_constant, binding = 1, std430) uniform Params { vec4 projections[MAX_VIEWS]; vec4 position_multiplier; float time; + float luminance_multiplier; + float pad[2]; } params; @@ -55,6 +57,8 @@ layout(push_constant, binding = 1, std430) uniform Params { vec4 projections[MAX_VIEWS]; vec4 position_multiplier; float time; + float luminance_multiplier; + float pad[2]; } params; @@ -199,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 @@ -246,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 23f83b3b9c..1ce3e04421 100644 --- a/servers/rendering/renderer_rd/shaders/tonemap.glsl +++ b/servers/rendering/renderer_rd/shaders/tonemap.glsl @@ -35,13 +35,17 @@ void main() { layout(location = 0) in vec2 uv_interp; -#ifdef MULTIVIEW +#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 @@ -67,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; @@ -165,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); } @@ -200,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); } } @@ -291,21 +309,22 @@ 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; #ifdef MULTIVIEW - vec3 rgbNW = textureLod(source_color, vec3(uv_interp + vec2(-1.0, -1.0) * params.pixel_size, ViewIndex), 0.0).xyz * exposure; - vec3 rgbNE = textureLod(source_color, vec3(uv_interp + vec2(1.0, -1.0) * params.pixel_size, ViewIndex), 0.0).xyz * exposure; - vec3 rgbSW = textureLod(source_color, vec3(uv_interp + vec2(-1.0, 1.0) * params.pixel_size, ViewIndex), 0.0).xyz * exposure; - vec3 rgbSE = textureLod(source_color, vec3(uv_interp + vec2(1.0, 1.0) * params.pixel_size, ViewIndex), 0.0).xyz * exposure; + 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; - 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 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); @@ -332,11 +351,11 @@ vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) { params.pixel_size; #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); - 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); + 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); - 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); + 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); @@ -346,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) { @@ -360,45 +380,54 @@ vec3 screen_space_dither(vec2 frag_coord) { } void main() { -#ifdef MULTIVIEW - vec3 color = textureLod(source_color, vec3(uv_interp, ViewIndex), 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; + 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); @@ -406,6 +435,7 @@ void main() { color = apply_glow(color, glow); } +#endif // Additional effects diff --git a/servers/rendering/renderer_rd/shaders/voxel_gi.glsl b/servers/rendering/renderer_rd/shaders/voxel_gi.glsl index 49a493cdc7..779f04ed35 100644 --- a/servers/rendering/renderer_rd/shaders/voxel_gi.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/voxel_gi_debug.glsl b/servers/rendering/renderer_rd/shaders/voxel_gi_debug.glsl index 7d4d72967a..281c496df3 100644 --- a/servers/rendering/renderer_rd/shaders/voxel_gi_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; |