You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-12-03 16:55:53 +00:00
Implement signed distance fields for 2D shaders
This commit is contained in:
@@ -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")
|
||||
|
||||
@@ -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 */
|
||||
@@ -500,8 +524,13 @@ FRAGMENT_SHADER_CODE
|
||||
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
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
135
servers/rendering/rasterizer_rd/shaders/canvas_sdf.glsl
Normal file
135
servers/rendering/rasterizer_rd/shaders/canvas_sdf.glsl
Normal file
@@ -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
|
||||
}
|
||||
@@ -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,8 +83,12 @@ layout(set = 0, binding = 1, std140) uniform CanvasData {
|
||||
float time;
|
||||
bool use_pixel_snap;
|
||||
|
||||
vec4 sdf_to_tex;
|
||||
vec2 screen_to_sdf;
|
||||
vec2 sdf_to_screen;
|
||||
|
||||
uint directional_light_count;
|
||||
uint pad0;
|
||||
float tex_to_sdf;
|
||||
uint pad1;
|
||||
uint pad2;
|
||||
}
|
||||
@@ -115,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;
|
||||
|
||||
Reference in New Issue
Block a user