Skip to content

Instantly share code, notes, and snippets.

@Enichan
Last active January 21, 2026 17:49
Show Gist options
  • Select an option

  • Save Enichan/4077aa05cc558402491d7b9ce6576910 to your computer and use it in GitHub Desktop.

Select an option

Save Enichan/4077aa05cc558402491d7b9ce6576910 to your computer and use it in GitHub Desktop.
HLSL Spherize shader function identical to Photoshop's spherize distortion filter
#ifndef PI
#define PI 3.14159265359
#endif
// adapted from https://www.shadertoy.com/view/WstfzH
float2 SpherizeOriginal(float2 uv, float2 center, float radius) {
float2 delta = uv - center;
if (delta.x == 0 && delta.y == 0) return uv;
float dist = length(delta);
if (dist > radius) return uv;
float theta = atan2(delta.y, delta.x);
float convexRad = asin(dist / radius) / (PI / 2) * radius;
return center + float2(convexRad * cos(theta), convexRad * sin(theta));
}
// almost identical to asin https://www.desmos.com/calculator/xxovxrssyc
float FastApproxAsin(float x) {
// c is from circle ease formula sqrt(1-x*x)
float c = 1.0 - sqrt(1.0 - x * x);
// using pow(c, 1.9296) is even more accurate than c*c, but pow is slower
// using sign(x)*PI/2 makes this work for -1 to 1 instead of only 0 to 1
// (thanks Greg Egan @gregeganSF@mathstodon.xyz for the sign suggestion)
return lerp(x, PI/2, c * c);
}
// optimized version of SpherizeOriginal without atan2
float2 Spherize(float2 uv, float2 center, float radius, float strength) {
float2 delta = uv - center;
if (delta.x == 0 && delta.y == 0) return uv;
float dist = length(delta);
if (dist > radius) return uv;
// originally before simplification:
// percent = dist / radius
// convexRad = FastApproxAsin(percent) / (PI / 2) * radius
// center + (delta / dist) * convexRad
//
// convexRad is the same term as in the original code
// delta / dist just normalizes the delta vector to turn
// convexRad into a 2D offset
//
// move radius:
// convexPct = FastApproxAsin(percent) / (PI / 2)
// center + (delta / dist) * convexPct * radius
//
// rearrange to:
// center + delta * radius / dist * convexPct
//
// radius / dist is the inverse of percent's dist / radius
// so that term can be replaced with 1/percent:
// center + delta * 1/percent * convexPct
//
// simplifies to center + delta * convexPct / percent
float percent = dist / radius;
float convexPct = FastApproxAsin(percent) / (PI / 2);
return center + delta * (convexPct / percent) * strength;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment