Skip to content

Instantly share code, notes, and snippets.

@MrPowerGamerBR
Last active July 1, 2025 21:16
Show Gist options
  • Save MrPowerGamerBR/3f38b3f540e43efedb1d5838e553d93b to your computer and use it in GitHub Desktop.
Save MrPowerGamerBR/3f38b3f540e43efedb1d5838e553d93b to your computer and use it in GitHub Desktop.
SDF (Signed Distance Field) compute shader
#version 430 core
layout(local_size_x = 16, local_size_y = 16) in;
layout(rgba8, binding = 0) uniform image2D inputImage;
layout(rgba8, binding = 1) uniform image2D outputTexture;
uniform int searchRadius = 32;
void main() {
ivec2 pixelCoords = ivec2(gl_GlobalInvocationID.xy);
ivec2 imageSize = imageSize(inputImage);
// Read a pixel from the image
vec4 inputPixel = imageLoad(inputImage, pixelCoords);
// The input is BLACK (inside the glyph) and TRANSPARENT (outside the glyph)!
// We need to calculate BOTH, and values 0.5 SHOULD be at the glyph's edge!
bool isInsideGlyph = inputPixel.a == 1.0;
float alphaToBeChecked = 1.0;
if (isInsideGlyph)
alphaToBeChecked = 0.0;
// Search around us...
float squaredDistance = 32 * 32;
int startX = max(0, pixelCoords.x - searchRadius);
int startY = max(0, pixelCoords.y - searchRadius);
int endX = min(imageSize.x, pixelCoords.x + searchRadius + 1);
int endY = min(imageSize.y, pixelCoords.y + searchRadius + 1);
int ix = startX;
int iy = startY;
while (true) {
// The second check is "No need to check self"
if (ix == endX || (ix == pixelCoords.x && iy == pixelCoords.y)) {
ix = startX;
iy++;
if (iy == endY)
break;
}
vec4 distancePixel = imageLoad(inputImage, ivec2(ix, iy));
if (distancePixel.a == alphaToBeChecked) {
// We are inside the glyph!
// But how far are we from the glyph?
float dx = (ix - pixelCoords.x);
float dy = (iy - pixelCoords.y);
float thisSquaredDistance = (dx * dx) + (dy * dy);
squaredDistance = min(squaredDistance, thisSquaredDistance);
}
ix++;
}
float distanceToEdge = sqrt(squaredDistance);
// Value from 0.5 to 1.0
float sdfValueAsRange = clamp(0.5 - (distanceToEdge / (2.0 * float(searchRadius))), 0.0, 1.0);
if (isInsideGlyph) {
// Don't ask me why do we need to use 0.98 instead of 1.0
// I did it like this because there was a visible "jump" on the edges of the SDF
imageStore(outputTexture, pixelCoords, vec4(0.98 - sdfValueAsRange, 0.98 - sdfValueAsRange, 0.98 - sdfValueAsRange, 1.0));
} else {
imageStore(outputTexture, pixelCoords, vec4(sdfValueAsRange, sdfValueAsRange, sdfValueAsRange, 1.0));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment