GodotShade/sdf_shader.glsl
2025-12-05 11:18:12 +01:00

95 lines
3.1 KiB
GLSL

#[compute]
#version 450
// Workgroup size
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
// Storage buffer
layout(set = 0, binding = 0, std430) buffer DataBuffer {
float sample_points[];
} voxels;
layout(set = 0, binding = 1) uniform Params {
int world_size;
float threshold;
} params;
layout(set = 0, binding = 2, std430) buffer SurfaceBuffer {
float surface_points[];
} surface;
uint index3(uint x, uint y, uint z) {
return x + y * params.world_size + z * params.world_size * params.world_size;
}
void store_surface_point(uint idx, vec3 pos) {
uint base = idx * 3u;
surface.surface_points[base + 0u] = pos.x;
surface.surface_points[base + 1u] = pos.y;
surface.surface_points[base + 2u] = pos.z;
}
void main() {
uvec3 id = gl_GlobalInvocationID;
if (id.x >= uint(params.world_size) ||
id.y >= uint(params.world_size) ||
id.z >= uint(params.world_size))
return;
const ivec3 SURFACE_AXIS[8] = ivec3[](
ivec3(1,0,0),
ivec3(0,1,0),
ivec3(0,0,1),
ivec3(1,0,1),
ivec3(0,1,1),
ivec3(1,1,0),
ivec3(1,1,1),
ivec3(0,0,0)
);
vec3 p = vec3(id) - params.world_size / 2 + 1;
float d = length(p) - params.threshold;
uint idx = index3(id.x, id.y, id.z);
voxels.sample_points[idx] = d;
int previous_sign = 0;
vec3 previous_sample_point_coords = vec3(id.x, id.y, id.z);
float previous_sample_point_distance = 0.0;
vec3 intersection_points_sum = vec3(0.0, 0.0, 0.0);
uint intersection_points_count = 0u;
for (int sample_point_to_check_index = 0; sample_point_to_check_index < 8; sample_point_to_check_index++){
ivec3 sample_point_to_check = ivec3(id) + SURFACE_AXIS[sample_point_to_check_index];
// bounds check
if (sample_point_to_check.x < 0 || sample_point_to_check.y < 0 || sample_point_to_check.z < 0) continue;
if (uint(sample_point_to_check.x) >= params.world_size || uint(sample_point_to_check.y) >= params.world_size || uint(sample_point_to_check.z) >= params.world_size) continue;
uint buffer_index = index3(uint(sample_point_to_check.x), uint(sample_point_to_check.y), uint(sample_point_to_check.z));
float sample_point_distance_from_sdf = voxels.sample_points[buffer_index];
int current_sign = (sample_point_distance_from_sdf >= 0.0 ? 1 : -1);
if (previous_sign != 0 && current_sign != previous_sign) {
float t = previous_sample_point_distance / (previous_sample_point_distance - sample_point_distance_from_sdf);
vec3 intersect = mix(vec3(previous_sample_point_coords), vec3(sample_point_to_check), t);
intersection_points_sum += intersect;
intersection_points_count++;
}
previous_sign = current_sign;
previous_sample_point_distance = sample_point_distance_from_sdf;
previous_sample_point_coords = sample_point_to_check;
}
if (intersection_points_count > 0u) {
vec3 avg = intersection_points_sum / float(intersection_points_count);
store_surface_point(idx, avg);
} else {
store_surface_point(idx, vec3(0.0)); // no surface
}
}