summaryrefslogtreecommitdiff
path: root/servers/rendering/rasterizer_rd/shaders
diff options
context:
space:
mode:
Diffstat (limited to 'servers/rendering/rasterizer_rd/shaders')
-rw-r--r--servers/rendering/rasterizer_rd/shaders/SCsub1
-rw-r--r--servers/rendering/rasterizer_rd/shaders/canvas.glsl255
-rw-r--r--servers/rendering/rasterizer_rd/shaders/canvas_occlusion.glsl18
-rw-r--r--servers/rendering/rasterizer_rd/shaders/canvas_sdf.glsl135
-rw-r--r--servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl29
-rw-r--r--servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl112
6 files changed, 451 insertions, 99 deletions
diff --git a/servers/rendering/rasterizer_rd/shaders/SCsub b/servers/rendering/rasterizer_rd/shaders/SCsub
index 9d531d63ad..4cddf0f685 100644
--- a/servers/rendering/rasterizer_rd/shaders/SCsub
+++ b/servers/rendering/rasterizer_rd/shaders/SCsub
@@ -5,6 +5,7 @@ Import("env")
if "RD_GLSL" in env["BUILDERS"]:
env.RD_GLSL("canvas.glsl")
env.RD_GLSL("canvas_occlusion.glsl")
+ env.RD_GLSL("canvas_sdf.glsl")
env.RD_GLSL("copy.glsl")
env.RD_GLSL("copy_to_fb.glsl")
env.RD_GLSL("cubemap_roughness.glsl")
diff --git a/servers/rendering/rasterizer_rd/shaders/canvas.glsl b/servers/rendering/rasterizer_rd/shaders/canvas.glsl
index b382c0d85f..51d7193a03 100644
--- a/servers/rendering/rasterizer_rd/shaders/canvas.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/canvas.glsl
@@ -233,6 +233,30 @@ MATERIAL_UNIFORMS
} material;
#endif
+vec2 screen_uv_to_sdf(vec2 p_uv) {
+ return canvas_data.screen_to_sdf * p_uv;
+}
+
+float texture_sdf(vec2 p_sdf) {
+ vec2 uv = p_sdf * canvas_data.sdf_to_tex.xy + canvas_data.sdf_to_tex.zw;
+ float d = texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv).r;
+ d = d * SDF_MAX_LENGTH - 1.0;
+ return d * canvas_data.tex_to_sdf;
+}
+
+vec2 texture_sdf_normal(vec2 p_sdf) {
+ vec2 uv = p_sdf * canvas_data.sdf_to_tex.xy + canvas_data.sdf_to_tex.zw;
+
+ const float EPSILON = 0.001;
+ return normalize(vec2(
+ texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv + vec2(EPSILON, 0.0)).r - texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv - vec2(EPSILON, 0.0)).r,
+ texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv + vec2(0.0, EPSILON)).r - texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv - vec2(0.0, EPSILON)).r));
+}
+
+vec2 sdf_to_screen_uv(vec2 p_sdf) {
+ return p_sdf * canvas_data.sdf_to_screen;
+}
+
/* clang-format off */
FRAGMENT_SHADER_GLOBALS
/* clang-format on */
@@ -249,7 +273,7 @@ vec4 light_compute(
inout vec4 shadow_modulate,
vec2 screen_uv,
vec2 uv,
- vec4 color) {
+ vec4 color, bool is_directional) {
vec4 light = vec4(0.0);
/* clang-format off */
LIGHT_SHADER_CODE
@@ -302,6 +326,99 @@ float map_ninepatch_axis(float pixel, float draw_size, float tex_pixel_size, flo
#endif
+#ifdef USE_LIGHTING
+
+vec3 light_normal_compute(vec3 light_vec, vec3 normal, vec3 base_color, vec3 light_color, vec4 specular_shininess, bool specular_shininess_used) {
+ float cNdotL = max(0.0, dot(normal, light_vec));
+
+ if (specular_shininess_used) {
+ //blinn
+ vec3 view = vec3(0.0, 0.0, 1.0); // not great but good enough
+ vec3 half_vec = normalize(view + light_vec);
+
+ float cNdotV = max(dot(normal, view), 0.0);
+ float cNdotH = max(dot(normal, half_vec), 0.0);
+ float cVdotH = max(dot(view, half_vec), 0.0);
+ float cLdotH = max(dot(light_vec, half_vec), 0.0);
+ float shininess = exp2(15.0 * specular_shininess.a + 1.0) * 0.25;
+ float blinn = pow(cNdotH, shininess);
+ blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI));
+ float s = (blinn) / max(4.0 * cNdotV * cNdotL, 0.75);
+
+ return specular_shininess.rgb * light_color * s + light_color * base_color * cNdotL;
+ } else {
+ return light_color * base_color * cNdotL;
+ }
+}
+
+//float distance = length(shadow_pos);
+vec4 light_shadow_compute(uint light_base, vec4 light_color, vec4 shadow_uv
+#ifdef LIGHT_SHADER_CODE_USED
+ ,
+ vec3 shadow_modulate
+#endif
+) {
+ float shadow;
+ uint shadow_mode = light_array.data[light_base].flags & LIGHT_FLAGS_FILTER_MASK;
+
+ if (shadow_mode == LIGHT_FLAGS_SHADOW_NEAREST) {
+ shadow = textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv, 0.0).x;
+ } else if (shadow_mode == LIGHT_FLAGS_SHADOW_PCF5) {
+ vec4 shadow_pixel_size = vec4(light_array.data[light_base].shadow_pixel_size, 0.0, 0.0, 0.0);
+ shadow = 0.0;
+ shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 2.0, 0.0).x;
+ shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size, 0.0).x;
+ shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv, 0.0).x;
+ shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size, 0.0).x;
+ shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 2.0, 0.0).x;
+ shadow /= 5.0;
+ } else { //PCF13
+ vec4 shadow_pixel_size = vec4(light_array.data[light_base].shadow_pixel_size, 0.0, 0.0, 0.0);
+ shadow = 0.0;
+ shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 6.0, 0.0).x;
+ shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 5.0, 0.0).x;
+ shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 4.0, 0.0).x;
+ shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 3.0, 0.0).x;
+ shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 2.0, 0.0).x;
+ shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size, 0.0).x;
+ shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv, 0.0).x;
+ shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size, 0.0).x;
+ shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 2.0, 0.0).x;
+ shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 3.0, 0.0).x;
+ shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 4.0, 0.0).x;
+ shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 5.0, 0.0).x;
+ shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 6.0, 0.0).x;
+ shadow /= 13.0;
+ }
+
+ vec4 shadow_color = unpackUnorm4x8(light_array.data[light_base].shadow_color);
+#ifdef LIGHT_SHADER_CODE_USED
+ shadow_color *= shadow_modulate;
+#endif
+
+ shadow_color.a *= light_color.a; //respect light alpha
+
+ return mix(light_color, shadow_color, shadow);
+}
+
+void light_blend_compute(uint light_base, vec4 light_color, inout vec3 color) {
+ uint blend_mode = light_array.data[light_base].flags & LIGHT_FLAGS_BLEND_MASK;
+
+ switch (blend_mode) {
+ case LIGHT_FLAGS_BLEND_MODE_ADD: {
+ color.rgb += light_color.rgb * light_color.a;
+ } break;
+ case LIGHT_FLAGS_BLEND_MODE_SUB: {
+ color.rgb -= light_color.rgb * light_color.a;
+ } break;
+ case LIGHT_FLAGS_BLEND_MODE_MIX: {
+ color.rgb = mix(color.rgb, light_color.rgb, light_color.a);
+ } break;
+ }
+}
+
+#endif
+
void main() {
vec4 color = color_interp;
vec2 uv = uv_interp;
@@ -332,6 +449,7 @@ void main() {
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;
vec3 normal;
@@ -341,7 +459,7 @@ void main() {
bool normal_used = false;
#endif
- if (normal_used || (light_count > 0 && bool(draw_data.flags & FLAGS_DEFAULT_NORMAL_MAP_USED))) {
+ if (normal_used || (using_light && bool(draw_data.flags & FLAGS_DEFAULT_NORMAL_MAP_USED))) {
normal.xy = texture(sampler2D(normal_texture, texture_sampler), uv).xy * vec2(2.0, -2.0) - vec2(1.0, -1.0);
normal.z = sqrt(1.0 - dot(normal.xy, normal.xy));
normal_used = true;
@@ -358,7 +476,7 @@ void main() {
bool specular_shininess_used = false;
#endif
- if (specular_shininess_used || (light_count > 0 && normal_used && bool(draw_data.flags & FLAGS_DEFAULT_SPECULAR_MAP_USED))) {
+ if (specular_shininess_used || (using_light && normal_used && bool(draw_data.flags & FLAGS_DEFAULT_SPECULAR_MAP_USED))) {
specular_shininess = texture(sampler2D(specular_texture, texture_sampler), uv);
specular_shininess *= unpackUnorm4x8(draw_data.specular_shininess);
specular_shininess_used = true;
@@ -401,13 +519,57 @@ FRAGMENT_SHADER_CODE
normal = normalize((canvas_data.canvas_normal_transform * vec4(normal, 0.0)).xyz);
}
- vec4 base_color = color;
+ vec3 base_color = color.rgb;
if (bool(draw_data.flags & FLAGS_USING_LIGHT_MASK)) {
color = vec4(0.0); //invisible by default due to using light mask
}
+#ifdef MODE_LIGHT_ONLY
+ color = vec4(0.0);
+#else
color *= canvas_data.canvas_modulation;
-#ifdef USE_LIGHTING
+#endif
+
+#if defined(USE_LIGHTING) && !defined(MODE_UNSHADED)
+
+ // Directional Lights
+
+ for (uint i = 0; i < canvas_data.directional_light_count; i++) {
+ uint light_base = i;
+
+ vec2 direction = light_array.data[light_base].position;
+ vec4 light_color = light_array.data[light_base].color;
+
+#ifdef LIGHT_SHADER_CODE_USED
+
+ vec4 shadow_modulate = vec4(1.0);
+ light_color = light_compute(light_vertex, direction, normal, light_color, light_color.a, specular_shininess, shadow_modulate, screen_uv, color, uv, true);
+#else
+
+ if (normal_used) {
+ vec3 light_vec = normalize(mix(vec3(direction, 0.0), vec3(0, 0, 1), light_array.data[light_base].height));
+ light_color.rgb = light_normal_compute(light_vec, normal, base_color, light_color.rgb, specular_shininess, specular_shininess_used);
+ }
+#endif
+
+ if (bool(light_array.data[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) {
+ vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_array.data[light_base].shadow_matrix[0], light_array.data[light_base].shadow_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
+
+ vec4 shadow_uv = vec4(shadow_pos.x, light_array.data[light_base].shadow_y_ofs, shadow_pos.y * light_array.data[light_base].shadow_zfar_inv, 1.0);
+
+ light_color = light_shadow_compute(light_base, light_color, shadow_uv
+#ifdef LIGHT_SHADER_CODE_USED
+ ,
+ shadow_modulate
+#endif
+ );
+ }
+
+ light_blend_compute(light_base, light_color, color.rgb);
+ }
+
+ // Positional Lights
+
for (uint i = 0; i < MAX_LIGHTS_PER_ITEM; i++) {
if (i >= light_count) {
break;
@@ -440,7 +602,7 @@ FRAGMENT_SHADER_CODE
vec3 light_position = vec3(light_array.data[light_base].position, light_array.data[light_base].height);
light_color.rgb *= light_base_color.rgb;
- light_color = light_compute(light_vertex, light_position, normal, light_color, light_base_color.a, specular_shininess, shadow_modulate, screen_uv, color, uv);
+ light_color = light_compute(light_vertex, light_position, normal, light_color, light_base_color.a, specular_shininess, shadow_modulate, screen_uv, color, uv, false);
#else
light_color.rgb *= light_base_color.rgb * light_base_color.a;
@@ -451,24 +613,7 @@ FRAGMENT_SHADER_CODE
vec3 light_vec = normalize(light_pos - pos);
float cNdotL = max(0.0, dot(normal, light_vec));
- if (specular_shininess_used) {
- //blinn
- vec3 view = vec3(0.0, 0.0, 1.0); // not great but good enough
- vec3 half_vec = normalize(view + light_vec);
-
- float cNdotV = max(dot(normal, view), 0.0);
- float cNdotH = max(dot(normal, half_vec), 0.0);
- float cVdotH = max(dot(view, half_vec), 0.0);
- float cLdotH = max(dot(light_vec, half_vec), 0.0);
- float shininess = exp2(15.0 * specular_shininess.a + 1.0) * 0.25;
- float blinn = pow(cNdotH, shininess);
- blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI));
- float s = (blinn) / max(4.0 * cNdotV * cNdotL, 0.75);
-
- light_color.rgb = specular_shininess.rgb * light_base_color.rgb * s + light_color.rgb * cNdotL;
- } else {
- light_color.rgb *= cNdotL;
- }
+ light_color.rgb = light_normal_compute(light_vec, normal, base_color, light_color.rgb, specular_shininess, specular_shininess_used);
}
#endif
if (any(lessThan(tex_uv, vec2(0.0, 0.0))) || any(greaterThanEqual(tex_uv, vec2(1.0, 1.0)))) {
@@ -506,69 +651,17 @@ FRAGMENT_SHADER_CODE
distance *= light_array.data[light_base].shadow_zfar_inv;
//float distance = length(shadow_pos);
- float shadow;
- uint shadow_mode = light_array.data[light_base].flags & LIGHT_FLAGS_FILTER_MASK;
-
vec4 shadow_uv = vec4(tex_ofs, light_array.data[light_base].shadow_y_ofs, distance, 1.0);
- if (shadow_mode == LIGHT_FLAGS_SHADOW_NEAREST) {
- shadow = textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv, 0.0).x;
- } else if (shadow_mode == LIGHT_FLAGS_SHADOW_PCF5) {
- vec4 shadow_pixel_size = vec4(light_array.data[light_base].shadow_pixel_size, 0.0, 0.0, 0.0);
- shadow = 0.0;
- shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 2.0, 0.0).x;
- shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size, 0.0).x;
- shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv, 0.0).x;
- shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size, 0.0).x;
- shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 2.0, 0.0).x;
- shadow /= 5.0;
- } else { //PCF13
- vec4 shadow_pixel_size = vec4(light_array.data[light_base].shadow_pixel_size, 0.0, 0.0, 0.0);
- shadow = 0.0;
- shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 6.0, 0.0).x;
- shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 5.0, 0.0).x;
- shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 4.0, 0.0).x;
- shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 3.0, 0.0).x;
- shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 2.0, 0.0).x;
- shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size, 0.0).x;
- shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv, 0.0).x;
- shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size, 0.0).x;
- shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 2.0, 0.0).x;
- shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 3.0, 0.0).x;
- shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 4.0, 0.0).x;
- shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 5.0, 0.0).x;
- shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 6.0, 0.0).x;
- shadow /= 13.0;
- }
-
- vec4 shadow_color = unpackUnorm4x8(light_array.data[light_base].shadow_color);
+ light_color = light_shadow_compute(light_base, light_color, shadow_uv
#ifdef LIGHT_SHADER_CODE_USED
- shadow_color *= shadow_modulate;
+ ,
+ shadow_modulate
#endif
-
- shadow_color.a *= light_color.a; //respect light alpha
-
- light_color = mix(light_color, shadow_color, shadow);
- //light_color = mix(light_color, shadow_color, shadow);
+ );
}
- uint blend_mode = light_array.data[light_base].flags & LIGHT_FLAGS_BLEND_MASK;
-
- switch (blend_mode) {
- case LIGHT_FLAGS_BLEND_MODE_ADD: {
- color.rgb += light_color.rgb * light_color.a;
- } break;
- case LIGHT_FLAGS_BLEND_MODE_SUB: {
- color.rgb -= light_color.rgb * light_color.a;
- } break;
- case LIGHT_FLAGS_BLEND_MODE_MIX: {
- color.rgb = mix(color.rgb, light_color.rgb, light_color.a);
- } break;
- case LIGHT_FLAGS_BLEND_MODE_MASK: {
- light_color.a *= base_color.a;
- color.rgb = mix(color.rgb, light_color.rgb, light_color.a);
- } break;
- }
+ light_blend_compute(light_base, light_color, color.rgb);
}
#endif
diff --git a/servers/rendering/rasterizer_rd/shaders/canvas_occlusion.glsl b/servers/rendering/rasterizer_rd/shaders/canvas_occlusion.glsl
index 421282cd4d..5c25235c58 100644
--- a/servers/rendering/rasterizer_rd/shaders/canvas_occlusion.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/canvas_occlusion.glsl
@@ -2,6 +2,8 @@
#version 450
+VERSION_DEFINES
+
layout(location = 0) in highp vec3 vertex;
layout(push_constant, binding = 0, std430) uniform Constants {
@@ -13,12 +15,16 @@ layout(push_constant, binding = 0, std430) uniform Constants {
}
constants;
+#ifdef MODE_SHADOW
layout(location = 0) out highp float depth;
+#endif
void main() {
highp vec4 vtx = vec4(vertex, 1.0) * mat4(constants.modelview[0], constants.modelview[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));
- depth = dot(constants.direction, vtx.xy);
+#ifdef MODE_SHADOW
+ depth = dot(constants.direction, vtx.xy);
+#endif
gl_Position = constants.projection * vtx;
}
@@ -26,6 +32,8 @@ void main() {
#version 450
+VERSION_DEFINES
+
layout(push_constant, binding = 0, std430) uniform Constants {
mat4 projection;
mat2x4 modelview;
@@ -35,9 +43,17 @@ layout(push_constant, binding = 0, std430) uniform Constants {
}
constants;
+#ifdef MODE_SHADOW
layout(location = 0) in highp float depth;
layout(location = 0) out highp float distance_buf;
+#else
+layout(location = 0) out highp float sdf_buf;
+#endif
void main() {
+#ifdef MODE_SHADOW
distance_buf = depth / constants.z_far;
+#else
+ sdf_buf = 1.0;
+#endif
}
diff --git a/servers/rendering/rasterizer_rd/shaders/canvas_sdf.glsl b/servers/rendering/rasterizer_rd/shaders/canvas_sdf.glsl
new file mode 100644
index 0000000000..302ad03b41
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/shaders/canvas_sdf.glsl
@@ -0,0 +1,135 @@
+#[compute]
+
+#version 450
+
+VERSION_DEFINES
+
+layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
+
+layout(r8, set = 0, binding = 1) uniform restrict readonly image2D src_pixels;
+layout(r16, set = 0, binding = 2) uniform restrict writeonly image2D dst_sdf;
+
+layout(rg16i, set = 0, binding = 3) uniform restrict readonly iimage2D src_process;
+layout(rg16i, set = 0, binding = 4) uniform restrict writeonly iimage2D dst_process;
+
+layout(push_constant, binding = 0, std430) uniform Params {
+ ivec2 size;
+ int stride;
+ int shift;
+ ivec2 base_size;
+ uvec2 pad;
+}
+params;
+
+#define SDF_MAX_LENGTH 16384.0
+
+void main() {
+ ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
+ if (any(greaterThanEqual(pos, params.size))) { //too large, do nothing
+ return;
+ }
+
+#ifdef MODE_LOAD
+
+ bool solid = imageLoad(src_pixels, pos).r > 0.5;
+ imageStore(dst_process, pos, solid ? ivec4(pos, 0, 0) : ivec4(ivec2(32767), 0, 0));
+#endif
+
+#ifdef MODE_LOAD_SHRINK
+
+ int s = 1 << params.shift;
+ ivec2 base = pos << params.shift;
+ ivec2 center = base + ivec2(params.shift);
+
+ ivec2 rel = ivec2(32767);
+ float d = 1e20;
+ for (int i = 0; i < s; i++) {
+ for (int j = 0; j < s; j++) {
+ ivec2 src_pos = base + ivec2(i, j);
+ if (any(greaterThanEqual(src_pos, params.base_size))) {
+ continue;
+ }
+ bool solid = imageLoad(src_pixels, src_pos).r > 0.5;
+ if (solid) {
+ float dist = length(vec2(src_pos - center));
+ if (dist < d) {
+ d = dist;
+ rel = src_pos;
+ }
+ }
+ }
+ }
+
+ imageStore(dst_process, pos, ivec4(rel, 0, 0));
+#endif
+
+#ifdef MODE_PROCESS
+
+ ivec2 base = pos << params.shift;
+ ivec2 center = base + ivec2(params.shift);
+
+ ivec2 rel = imageLoad(src_process, pos).xy;
+
+ if (center != rel) {
+ //only process if it does not point to itself
+ const int ofs_table_size = 8;
+ const ivec2 ofs_table[ofs_table_size] = ivec2[](
+ ivec2(-1, -1),
+ ivec2(0, -1),
+ ivec2(+1, -1),
+
+ ivec2(-1, 0),
+ ivec2(+1, 0),
+
+ ivec2(-1, +1),
+ ivec2(0, +1),
+ ivec2(+1, +1));
+
+ float dist = length(vec2(rel - center));
+ for (int i = 0; i < ofs_table_size; i++) {
+ ivec2 src_pos = pos + ofs_table[i] * params.stride;
+ if (any(lessThan(src_pos, ivec2(0))) || any(greaterThanEqual(src_pos, params.size))) {
+ continue;
+ }
+ ivec2 src_rel = imageLoad(src_process, src_pos).xy;
+ float src_dist = length(vec2(src_rel - center));
+ if (src_dist < dist) {
+ dist = src_dist;
+ rel = src_rel;
+ }
+ }
+ }
+
+ imageStore(dst_process, pos, ivec4(rel, 0, 0));
+#endif
+
+#ifdef MODE_STORE
+
+ ivec2 rel = imageLoad(src_process, pos).xy;
+ float d = length(vec2(rel - pos));
+ if (d > 0.01) {
+ d += 1.0; //make it signed
+ }
+ d /= SDF_MAX_LENGTH;
+ d = clamp(d, 0.0, 1.0);
+ imageStore(dst_sdf, pos, vec4(d));
+
+#endif
+
+#ifdef MODE_STORE_SHRINK
+
+ ivec2 base = pos << params.shift;
+ ivec2 center = base + ivec2(params.shift);
+
+ ivec2 rel = imageLoad(src_process, pos).xy;
+ float d = length(vec2(rel - center));
+
+ if (d > 0.01) {
+ d += 1.0; //make it signed
+ }
+ d /= SDF_MAX_LENGTH;
+ d = clamp(d, 0.0, 1.0);
+ imageStore(dst_sdf, pos, vec4(d));
+
+#endif
+}
diff --git a/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl b/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl
index 1a226a87d3..cf7678ea31 100644
--- a/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl
@@ -3,6 +3,8 @@
#define M_PI 3.14159265359
+#define SDF_MAX_LENGTH 16384.0
+
#define FLAGS_INSTANCING_STRIDE_MASK 0xF
#define FLAGS_INSTANCING_ENABLED (1 << 4)
#define FLAGS_INSTANCING_HAS_COLORS (1 << 5)
@@ -24,6 +26,19 @@
#define FLAGS_DEFAULT_NORMAL_MAP_USED (1 << 26)
#define FLAGS_DEFAULT_SPECULAR_MAP_USED (1 << 27)
+#define SAMPLER_NEAREST_CLAMP 0
+#define SAMPLER_LINEAR_CLAMP 1
+#define SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP 2
+#define SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP 3
+#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_CLAMP 4
+#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_CLAMP 5
+#define SAMPLER_NEAREST_REPEAT 6
+#define SAMPLER_LINEAR_REPEAT 7
+#define SAMPLER_NEAREST_WITH_MIPMAPS_REPEAT 8
+#define SAMPLER_LINEAR_WITH_MIPMAPS_REPEAT 9
+#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10
+#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11
+
// Push Constant
layout(push_constant, binding = 0, std430) uniform DrawData {
@@ -68,7 +83,14 @@ layout(set = 0, binding = 1, std140) uniform CanvasData {
float time;
bool use_pixel_snap;
- //uint light_count;
+ vec4 sdf_to_tex;
+ vec2 screen_to_sdf;
+ vec2 sdf_to_screen;
+
+ uint directional_light_count;
+ float tex_to_sdf;
+ uint pad1;
+ uint pad2;
}
canvas_data;
@@ -112,10 +134,11 @@ layout(set = 0, binding = 4) uniform texture2D shadow_atlas_texture;
layout(set = 0, binding = 5) uniform sampler shadow_sampler;
layout(set = 0, binding = 6) uniform texture2D screen_texture;
+layout(set = 0, binding = 7) uniform texture2D sdf_texture;
-layout(set = 0, binding = 7) uniform sampler material_samplers[12];
+layout(set = 0, binding = 8) uniform sampler material_samplers[12];
-layout(set = 0, binding = 8, std430) restrict readonly buffer GlobalVariableData {
+layout(set = 0, binding = 9, std430) restrict readonly buffer GlobalVariableData {
vec4 data[];
}
global_variables;
diff --git a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl
index 455a3d4a3a..285698f060 100644
--- a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl
@@ -361,6 +361,65 @@ layout(location = 0) out vec4 frag_color;
#endif // RENDER DEPTH
+#ifdef ALPHA_HASH_USED
+
+float hash_2d(vec2 p) {
+ return fract(1.0e4 * sin(17.0 * p.x + 0.1 * p.y) *
+ (0.1 + abs(sin(13.0 * p.y + p.x))));
+}
+
+float hash_3d(vec3 p) {
+ return hash_2d(vec2(hash_2d(p.xy), p.z));
+}
+
+float compute_alpha_hash_threshold(vec3 pos, float hash_scale) {
+ vec3 dx = dFdx(pos);
+ vec3 dy = dFdx(pos);
+ float delta_max_sqr = max(length(dx), length(dy));
+ float pix_scale = 1.0 / (hash_scale * delta_max_sqr);
+
+ vec2 pix_scales =
+ vec2(exp2(floor(log2(pix_scale))), exp2(ceil(log2(pix_scale))));
+
+ vec2 a_thresh = vec2(hash_3d(floor(pix_scales.x * pos.xyz)),
+ hash_3d(floor(pix_scales.y * pos.xyz)));
+
+ float lerp_factor = fract(log2(pix_scale));
+
+ float a_interp = (1.0 - lerp_factor) * a_thresh.x + lerp_factor * a_thresh.y;
+
+ float min_lerp = min(lerp_factor, 1.0 - lerp_factor);
+
+ vec3 cases = vec3(a_interp * a_interp / (2.0 * min_lerp * (1.0 - min_lerp)),
+ (a_interp - 0.5 * min_lerp) / (1.0 - min_lerp),
+ 1.0 - ((1.0 - a_interp) * (1.0 - a_interp) /
+ (2.0 * min_lerp * (1.0 - min_lerp))));
+
+ float alpha_hash_threshold =
+ (lerp_factor < (1.0 - min_lerp)) ? ((lerp_factor < min_lerp) ? cases.x : cases.y) : cases.z;
+
+ return clamp(alpha_hash_threshold, 0.0, 1.0);
+}
+
+#endif // ALPHA_HASH_USED
+
+#ifdef ALPHA_ANTIALIASING_EDGE_USED
+
+float calc_mip_level(vec2 texture_coord) {
+ vec2 dx = dFdx(texture_coord);
+ vec2 dy = dFdy(texture_coord);
+ float delta_max_sqr = max(dot(dx, dx), dot(dy, dy));
+ return max(0.0, 0.5 * log2(delta_max_sqr));
+}
+
+float compute_alpha_antialiasing_edge(float input_alpha, vec2 texture_coord, float alpha_edge) {
+ input_alpha *= 1.0 + max(0, calc_mip_level(texture_coord)) * 0.25; // 0.25 mip scale, magic number
+ input_alpha = (input_alpha - alpha_edge) / max(fwidth(input_alpha), 0.0001) + 0.5;
+ return clamp(input_alpha, 0.0, 1.0);
+}
+
+#endif // ALPHA_ANTIALIASING_USED
+
// This returns the G_GGX function divided by 2 cos_theta_m, where in practice cos_theta_m is either N.L or N.V.
// We're dividing this factor off because the overall term we'll end up looks like
// (see, for example, the first unnumbered equation in B. Burley, "Physically Based Shading at Disney", SIGGRAPH 2012):
@@ -809,7 +868,6 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
inout float alpha,
#endif
inout vec3 diffuse_light, inout vec3 specular_light) {
-
vec3 light_rel_vec = lights.data[idx].position - vertex;
float light_length = length(light_rel_vec);
float normalized_distance = light_length * lights.data[idx].inv_radius;
@@ -1099,7 +1157,6 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
#endif
inout vec3 diffuse_light,
inout vec3 specular_light) {
-
vec3 light_rel_vec = lights.data[idx].position - vertex;
float light_length = length(light_rel_vec);
float normalized_distance = light_length * lights.data[idx].inv_radius;
@@ -1709,10 +1766,6 @@ void main() {
float alpha = 1.0;
-#if defined(ALPHA_SCISSOR_USED)
- float alpha_scissor = 0.5;
-#endif
-
#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED)
vec3 binormal = normalize(binormal_interp);
vec3 tangent = normalize(tangent_interp);
@@ -1749,6 +1802,19 @@ void main() {
float sss_strength = 0.0;
+#ifdef ALPHA_SCISSOR_USED
+ float alpha_scissor_threshold = 1.0;
+#endif // ALPHA_SCISSOR_USED
+
+#ifdef ALPHA_HASH_USED
+ float alpha_hash_scale = 1.0;
+#endif // ALPHA_HASH_USED
+
+#ifdef ALPHA_ANTIALIASING_EDGE_USED
+ float alpha_antialiasing_edge = 0.0;
+ vec2 alpha_texture_coordinate = vec2(0.0, 0.0);
+#endif // ALPHA_ANTIALIASING_EDGE_USED
+
{
/* clang-format off */
@@ -1757,7 +1823,7 @@ FRAGMENT_SHADER_CODE
/* clang-format on */
}
-#if defined(LIGHT_TRANSMITTANCE_USED)
+#ifdef LIGHT_TRANSMITTANCE_USED
#ifdef SSS_MODE_SKIN
transmittance_color.a = sss_strength;
#else
@@ -1765,25 +1831,43 @@ FRAGMENT_SHADER_CODE
#endif
#endif
-#if !defined(USE_SHADOW_TO_OPACITY)
+#ifndef USE_SHADOW_TO_OPACITY
-#if defined(ALPHA_SCISSOR_USED)
- if (alpha < alpha_scissor) {
+#ifdef ALPHA_SCISSOR_USED
+ if (alpha < alpha_scissor_threshold) {
discard;
}
#endif // ALPHA_SCISSOR_USED
-#ifdef USE_OPAQUE_PREPASS
+// alpha hash can be used in unison with alpha antialiasing
+#ifdef ALPHA_HASH_USED
+ if (alpha < compute_alpha_hash_threshold(vertex, alpha_hash_scale)) {
+ discard;
+ }
+#endif // ALPHA_HASH_USED
+
+// If we are not edge antialiasing, we need to remove the output alpha channel from scissor and hash
+#if (defined(ALPHA_SCISSOR_USED) || defined(ALPHA_HASH_USED)) && !defined(ALPHA_ANTIALIASING_EDGE_USED)
+ alpha = 1.0;
+#endif
+
+#ifdef ALPHA_ANTIALIASING_EDGE_USED
+// If alpha scissor is used, we must further the edge threshold, otherwise we wont get any edge feather
+#ifdef ALPHA_SCISSOR_USED
+ alpha_antialiasing_edge = clamp(alpha_scissor_threshold + alpha_antialiasing_edge, 0.0, 1.0);
+#endif
+ alpha = compute_alpha_antialiasing_edge(alpha, alpha_texture_coordinate, alpha_antialiasing_edge);
+#endif // ALPHA_ANTIALIASING_EDGE_USED
+#ifdef USE_OPAQUE_PREPASS
if (alpha < opaque_prepass_threshold) {
discard;
}
-
#endif // USE_OPAQUE_PREPASS
#endif // !USE_SHADOW_TO_OPACITY
-#if defined(NORMALMAP_USED)
+#ifdef NORMALMAP_USED
normalmap.xy = normalmap.xy * 2.0 - 1.0;
normalmap.z = sqrt(max(0.0, 1.0 - dot(normalmap.xy, normalmap.xy))); //always ignore Z, as it can be RG packed, Z may be pos/neg, etc.
@@ -1792,7 +1876,7 @@ FRAGMENT_SHADER_CODE
#endif
-#if defined(LIGHT_ANISOTROPY_USED)
+#ifdef LIGHT_ANISOTROPY_USED
if (anisotropy > 0.01) {
//rotation matrix