Last active
July 1, 2025 21:16
-
-
Save MrPowerGamerBR/3f38b3f540e43efedb1d5838e553d93b to your computer and use it in GitHub Desktop.
SDF (Signed Distance Field) compute shader
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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