mirror of
https://github.com/godotengine/godot.git
synced 2024-12-27 11:24:59 +08:00
2ec234ff67
This is an initial implementation based on the current RD implementation Performance will improve later
206 lines
4.0 KiB
GLSL
206 lines
4.0 KiB
GLSL
/* clang-format off */
|
|
#[modes]
|
|
|
|
mode_load = #define MODE_LOAD
|
|
mode_load_shrink = #define MODE_LOAD_SHRINK
|
|
mode_process = #define MODE_PROCESS
|
|
mode_store = #define MODE_STORE
|
|
mode_store_shrink = #define MODE_STORE_SHRINK
|
|
|
|
#[specializations]
|
|
|
|
#[vertex]
|
|
|
|
layout(location = 0) in vec2 vertex_attrib;
|
|
|
|
/* clang-format on */
|
|
|
|
uniform ivec2 size;
|
|
uniform int stride;
|
|
uniform int shift;
|
|
uniform ivec2 base_size;
|
|
|
|
void main() {
|
|
gl_Position = vec4(vertex_attrib, 1.0, 1.0);
|
|
}
|
|
|
|
/* clang-format off */
|
|
#[fragment]
|
|
|
|
#define SDF_MAX_LENGTH 16384.0
|
|
|
|
#if defined(MODE_LOAD) || defined(MODE_LOAD_SHRINK)
|
|
uniform lowp sampler2D src_pixels;//texunit:0
|
|
#else
|
|
uniform highp isampler2D src_process;//texunit:0
|
|
#endif
|
|
|
|
uniform ivec2 size;
|
|
uniform int stride;
|
|
uniform int shift;
|
|
uniform ivec2 base_size;
|
|
|
|
#if defined(MODE_LOAD) || defined(MODE_LOAD_SHRINK) || defined(MODE_PROCESS)
|
|
layout(location = 0) out ivec4 distance_field;
|
|
#else
|
|
layout(location = 0) out vec4 distance_field;
|
|
#endif
|
|
|
|
vec4 float_to_vec4(float p_float) {
|
|
highp vec4 comp = fract(p_float * vec4(255.0 * 255.0 * 255.0, 255.0 * 255.0, 255.0, 1.0));
|
|
comp -= comp.xxyz * vec4(0.0, 1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0);
|
|
return comp;
|
|
}
|
|
|
|
void main() {
|
|
ivec2 pos = ivec2(gl_FragCoord.xy);
|
|
|
|
#ifdef MODE_LOAD
|
|
|
|
bool solid = texelFetch(src_pixels, pos, 0).r > 0.5;
|
|
distance_field = solid ? ivec4(ivec2(-32767), 0, 0) : ivec4(ivec2(32767), 0, 0);
|
|
#endif
|
|
|
|
#ifdef MODE_LOAD_SHRINK
|
|
|
|
int s = 1 << shift;
|
|
ivec2 base = pos << shift;
|
|
ivec2 center = base + ivec2(shift);
|
|
|
|
ivec2 rel = ivec2(32767);
|
|
float d = 1e20;
|
|
int found = 0;
|
|
int solid_found = 0;
|
|
for (int i = 0; i < s; i++) {
|
|
for (int j = 0; j < s; j++) {
|
|
ivec2 src_pos = base + ivec2(i, j);
|
|
if (any(greaterThanEqual(src_pos, base_size))) {
|
|
continue;
|
|
}
|
|
bool solid = texelFetch(src_pixels, src_pos, 0).r > 0.5;
|
|
if (solid) {
|
|
float dist = length(vec2(src_pos - center));
|
|
if (dist < d) {
|
|
d = dist;
|
|
rel = src_pos;
|
|
}
|
|
solid_found++;
|
|
}
|
|
found++;
|
|
}
|
|
}
|
|
|
|
if (solid_found == found) {
|
|
//mark solid only if all are solid
|
|
rel = ivec2(-32767);
|
|
}
|
|
|
|
distance_field = ivec4(rel, 0, 0);
|
|
#endif
|
|
|
|
#ifdef MODE_PROCESS
|
|
|
|
ivec2 base = pos << shift;
|
|
ivec2 center = base + ivec2(shift);
|
|
|
|
ivec2 rel = texelFetch(src_process, pos, 0).xy;
|
|
|
|
bool solid = rel.x < 0;
|
|
|
|
if (solid) {
|
|
rel = -rel - ivec2(1);
|
|
}
|
|
|
|
if (center != rel) {
|
|
//only process if it does not point to itself
|
|
const int ofs_table_size = 8;
|
|
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] * stride;
|
|
if (any(lessThan(src_pos, ivec2(0))) || any(greaterThanEqual(src_pos, size))) {
|
|
continue;
|
|
}
|
|
ivec2 src_rel = texelFetch(src_process, src_pos, 0).xy;
|
|
bool src_solid = src_rel.x < 0;
|
|
if (src_solid) {
|
|
src_rel = -src_rel - ivec2(1);
|
|
}
|
|
|
|
if (src_solid != solid) {
|
|
src_rel = ivec2(src_pos << shift); //point to itself if of different type
|
|
}
|
|
|
|
float src_dist = length(vec2(src_rel - center));
|
|
if (src_dist < dist) {
|
|
dist = src_dist;
|
|
rel = src_rel;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (solid) {
|
|
rel = -rel - ivec2(1);
|
|
}
|
|
|
|
distance_field = ivec4(rel, 0, 0);
|
|
#endif
|
|
|
|
#ifdef MODE_STORE
|
|
|
|
ivec2 rel = texelFetch(src_process, pos, 0).xy;
|
|
|
|
bool solid = rel.x < 0;
|
|
|
|
if (solid) {
|
|
rel = -rel - ivec2(1);
|
|
}
|
|
|
|
float d = length(vec2(rel - pos));
|
|
|
|
if (solid) {
|
|
d = -d;
|
|
}
|
|
|
|
d /= SDF_MAX_LENGTH;
|
|
d = clamp(d, -1.0, 1.0);
|
|
distance_field = float_to_vec4(d*0.5+0.5);
|
|
|
|
#endif
|
|
|
|
#ifdef MODE_STORE_SHRINK
|
|
|
|
ivec2 base = pos << shift;
|
|
ivec2 center = base + ivec2(shift);
|
|
|
|
ivec2 rel = texelFetch(src_process, pos, 0).xy;
|
|
|
|
bool solid = rel.x < 0;
|
|
|
|
if (solid) {
|
|
rel = -rel - ivec2(1);
|
|
}
|
|
|
|
float d = length(vec2(rel - center));
|
|
|
|
if (solid) {
|
|
d = -d;
|
|
}
|
|
d /= SDF_MAX_LENGTH;
|
|
d = clamp(d, -1.0, 1.0);
|
|
distance_field = float_to_vec4(d*0.5+0.5);
|
|
|
|
#endif
|
|
}
|