Moon:
float sdMoon(vec2 p, float d, float ra, float rb )
{
p.y = abs(p.y);
float a = (ra*ra - rb*rb + d*d)/(2.0*d);
float b = sqrt(max(ra*ra-a*a,0.0));
if( d*(p.x*b-p.y*a) > d*d*max(b-p.y,0.0) )
return length(p-vec2(a,b));
return max( (length(p )-ra),
-(length(p-vec2(d,0))-rb));
}
float sdMoon(vec2 p, float d, float ra, float rb )
{
p.y = abs(p.y);
float a = (ra*ra - rb*rb + d*d)/(2.0*d);
float b = sqrt(max(ra*ra-a*a,0.0));
if( d*(p.x*b-p.y*a) > d*d*max(b-p.y,0.0) )
{
return length(p-vec2(a,b));
}
return max( (length(p )-ra),
-(length(p-vec2(d,0))-rb));
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 p = (2.0*fragCoord-iResolution.xy)/iResolution.y;
vec2 m = (2.0*iMouse.xy-iResolution.xy)/iResolution.y;
p *= 1.3;
m *= 1.3;
float ra = 1.0;
float rb = 0.8;
float di = 1.2*cos(iTime+3.9);
float d = sdMoon( p, di, ra, rb );
vec3 col = vec3(1.0) - sign(d)*vec3(0.1,0.4,0.7);
col *= 1.0 - exp(-4.0*abs(d));
col *= 0.8 + 0.2*cos(100.0*d);
col = mix( col, vec3(1.0), 1.0-smoothstep(0.0,0.015,abs(d)) );
if( iMouse.z>0.001 )
{
d = sdMoon(m, di, ra, rb );
col = mix(col, vec3(1.0,1.0,0.0), 1.0-smoothstep(0.0, 0.005, abs(length(p-m)-abs(d))-0.0025));
col = mix(col, vec3(1.0,1.0,0.0), 1.0-smoothstep(0.0, 0.005, length(p-m)-0.015));
}
fragColor = vec4(col,1.0);
}
Circle Cross:
float sdRoundedCross( in vec2 p, in float h )
{
float k = 0.5*(h+1.0/h);
p = abs(p);
return ( p.x<1.0 && p.y<p.x*(k-h)+h ) ?
k-sqrt(dot2(p-vec2(1,k))) :
sqrt(min(dot2(p-vec2(0,h)),
dot2(p-vec2(1,0))));
}
float dot2( in vec2 v ) { return dot(v,v); }
float sdRoundedCross( in vec2 p, in float h )
{
float k = 0.5*(h+1.0/h); // k should be const/precomputed at modeling time
p = abs(p);
return ( p.x<1.0 && p.y<p.x*(k-h)+h ) ?
k-sqrt(dot2(p-vec2(1,k))) : // circular arc
sqrt(min(dot2(p-vec2(0,h)), // top corner
dot2(p-vec2(1,0)))); // right corner
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 p = (2.0*fragCoord-iResolution.xy)/iResolution.y;
vec2 m = (2.0*iMouse.xy-iResolution.xy)/iResolution.y;
p *= 1.35;
m *= 1.35;
// animate
float he = 0.501-0.499*cos(iTime*1.1+0.0);
float ra = 0.100+0.100*sin(iTime*1.7+2.0);
// compute
float d = sdRoundedCross( p, he ) - ra;
// colorize
vec3 col = vec3(1.0) - sign(d)*vec3(0.1,0.4,0.7);
col *= 1.0 - exp(-3.0*abs(d));
col *= 0.8 + 0.2*cos(100.0*d);
col = mix( col, vec3(1.0), 1.0-smoothstep(0.0,0.01,abs(d)) );
if( iMouse.z>0.001 )
{
d = sdRoundedCross(m, he) - ra;
col = mix(col, vec3(1.0,1.0,0.0), 1.0-smoothstep(0.0, 0.005, abs(length(p-m)-abs(d))-0.0025));
col = mix(col, vec3(1.0,1.0,0.0), 1.0-smoothstep(0.0, 0.005, length(p-m)-0.015));
}
fragColor = vec4(col,1.0);
}
Simple Egg:
float sdEgg( in vec2 p, in float ra, in float rb )
{
const float k = sqrt(3.0);
p.x = abs(p.x);
float r = ra - rb;
return ((p.y<0.0) ? length(vec2(p.x, p.y )) - r :
(k*(p.x+r)<p.y) ? length(vec2(p.x, p.y-k*r)) :
length(vec2(p.x+r,p.y )) - 2.0*r) - rb;
}
float sdEgg( in vec2 p, in float he, in float ra, in float rb )
{
float ce = 0.5*(he*he-(ra-rb)*(ra-rb))/(ra-rb);
p.x = abs(p.x);
if( p.y<0.0 ) return length(p)-ra;
if( p.y*ce-p.x*he>he*ce ) return length(vec2(p.x,p.y-he))-rb;
return length(vec2(p.x+ce,p.y))-(ce+ra);
}
float sdLineV( in vec2 p, in float b ) { p.y -= clamp( p.y, 0.0, b ); return length( p ); }
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
// normalized pixel coordinates
vec2 p = (2.0*fragCoord-iResolution.xy)/iResolution.y;
vec2 m = (2.0*iMouse.xy-iResolution.xy)/iResolution.y;
float px = 2.0/iResolution.y;
p.y += 0.35;
m.y += 0.35;
// animation
vec2 cen = vec2(0.0,0.0);
float he = 0.7 + 0.3*cos(iTime*1.0+0.0);
float ra = 0.5;
float rb = 0.2;
float al = smoothstep( -0.5, 0.5,sin(iTime+0.1) );
// distance
float d = sdEgg(p-cen, he, ra, rb);
// coloring
vec3 col = (d>0.0) ? vec3(0.9,0.6,0.3) : vec3(0.65,0.85,1.0);
col *= 1.0 - exp(-7.0*abs(d));
col *= 0.8 + 0.2*cos(90.0*abs(d));
col = mix( col, vec3(1.0), 1.0-smoothstep(0.0,1.5*px,abs(d)-0.005) );
// draw primitive parameters
d = abs( sdLineV(p-cen,he));
d = min( d, abs(length(p)-ra) );
d = min( d, abs(length(p-vec2(0.0,he))-rb) );
d -= 0.003;
col = mix( col, vec3(0.0,1.0,1.0), al*(1.0-smoothstep(0.0,1.5*px,d)) );
if( iMouse.z>0.001 )
{
d = sdEgg(m-cen, he, ra, rb);
col = mix(col, vec3(1.0,1.0,0.0), 1.0-smoothstep(0.0, 0.005, abs(length(p-m)-abs(d))-0.0025));
col = mix(col, vec3(1.0,1.0,0.0), 1.0-smoothstep(0.0, 0.005, length(p-m)-0.015));
}
fragColor = vec4(col, 1.0);
}
Heart:
float sdHeart( in vec2 p )
{
p.x = abs(p.x);
if( p.y+p.x>1.0 )
return sqrt(dot2(p-vec2(0.25,0.75))) - sqrt(2.0)/4.0;
return sqrt(min(dot2(p-vec2(0.00,1.00)),
dot2(p-0.5*max(p.x+p.y,0.0)))) * sign(p.x-p.y);
}
float dot2( in vec2 v ) { return dot(v,v); }
float sdHeart( in vec2 p )
{
p.x = abs(p.x);
if( p.y+p.x>1.0 )
return sqrt(dot2(p-vec2(0.25,0.75))) - sqrt(2.0)/4.0;
return sqrt(min(dot2(p-vec2(0.00,1.00)),
dot2(p-0.5*max(p.x+p.y,0.0)))) * sign(p.x-p.y);
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
// normalized pixel coordinates
vec2 p = (fragCoord*2.0-iResolution.xy)/iResolution.y;
vec2 m = (2.0*iMouse.xy-iResolution.xy)/iResolution.y;
p.y += 0.5;
m.y += 0.5;
float d = sdHeart(p);
// coloring
vec3 col = (d>0.0) ? vec3(0.9,0.6,0.3) : vec3(0.65,0.85,1.0);
col *= 1.0 - exp(-6.0*abs(d));
col *= 1.0 + 0.2*cos(128.0*abs(d));
col = mix( col, vec3(1.0), 1.0-smoothstep(0.0,0.01,abs(d)) );
if( iMouse.z>0.001 )
{
d = sdHeart(m);
col = mix(col, vec3(1.0,1.0,0.0), 1.0-smoothstep(0.0, 0.005, abs(length(p-m)-abs(d))-0.0025));
col = mix(col, vec3(1.0,1.0,0.0), 1.0-smoothstep(0.0, 0.005, length(p-m)-0.015));
}
// output
fragColor = vec4(col, 1.0);
}
Cross:
float sdCross( in vec2 p, in vec2 b, float r )
{
p = abs(p); p = (p.y>p.x) ? p.yx : p.xy;
vec2 q = p - b;
float k = max(q.y,q.x);
vec2 w = (k>0.0) ? q : vec2(b.y-p.x,-k);
return sign(k)*length(max(w,0.0)) + r;
}
float sdCross( in vec2 p, in vec2 b, float r )
{
p = abs(p); p = (p.y>p.x) ? p.yx : p.xy;
vec2 q = p - b;
float k = max(q.y,q.x);
vec2 w = (k>0.0) ? q : vec2(b.y-p.x,-k);
float d = length(max(w,0.0));
return ((k>0.0)?d:-d) + r;
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 p = (2.0*fragCoord-iResolution.xy)/iResolution.y;
vec2 m = (2.0*iMouse.xy-iResolution.xy)/iResolution.y;
// animate size
vec2 si = 0.5 + 0.3*cos( iTime + vec2(0.0,1.57) ); if( si.x<si.y ) si=si.yx;
// animate corner radious
float ra = 0.1*sin(iTime*1.2);
// some failure cases (interior distance is broken)
// si = vec2(0.5,0.4); ra=0.0;
// si = vec2(0.5,0.2); ra=-0.1;
// distance
float d = sdCross( p, si, ra );
// color
vec3 col = (d>0.0) ? vec3(0.9,0.6,0.3) : vec3(0.65,0.85,1.0);
col *= 1.0 - exp(-6.0*abs(d));
col *= 0.8 + 0.2*cos(150.0*d);
col = mix( col, vec3(1.0), 1.0-smoothstep(0.0,0.01,abs(d)) );
// mouse SDF
if( iMouse.x>0.001 )
{
d = sdCross(m, si, ra );
col = mix(col, vec3(1.0,1.0,0.0), 1.0-smoothstep(0.0, 0.005, abs(length(p-m)-abs(d))-0.0015));
col = mix(col, vec3(1.0,1.0,0.0), 1.0-smoothstep(0.0, 0.005, length(p-m)-0.015));
}
fragColor = vec4(col,1.0);
}
Rounded X:
float sdRoundedX( in vec2 p, in float w, in float r )
{
p = abs(p);
return length(p-min(p.x+p.y,w)*0.5) - r;
}
float sdRoundedX( in vec2 p, in float w, in float r )
{
p = abs(p);
return length(p-min(p.x+p.y,w)*0.5) - r;
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 p = (2.0*fragCoord.xy-iResolution.xy)/iResolution.y;
vec2 m = (2.0*iMouse.xy-iResolution.xy)/iResolution.y;
// width
float wi = 0.5 + 0.3*cos( iTime + 2.0 );
// radious
float ra = 0.1 + 0.08*sin(iTime*1.2);
float d = sdRoundedX( p, wi, ra );
vec3 col = vec3(1.0) - sign(d)*vec3(0.1,0.4,0.7);
col *= 1.0 - exp(-3.0*abs(d));
col *= 0.8 + 0.2*cos(120.0*d);
col = mix( col, vec3(1.0), 1.0-smoothstep(0.0,0.015,abs(d)) );
if( iMouse.z>0.001 )
{
d = sdRoundedX(m, wi, ra );
col = mix(col, vec3(1.0,1.0,0.0), 1.0-smoothstep(0.0, 0.005, abs(length(p-m)-abs(d))-0.0025));
col = mix(col, vec3(1.0,1.0,0.0), 1.0-smoothstep(0.0, 0.005, length(p-m)-0.015));
}
fragColor = vec4(col,1.0);
}
Polygon:
float sdPolygon( in vec2[N] v, in vec2 p )
{
float d = dot(p-v[0],p-v[0]);
float s = 1.0;
for( int i=0, j=N-1; i<N; j=i, i++ )
{
vec2 e = v[j] - v[i];
vec2 w = p - v[i];
vec2 b = w - e*clamp( dot(w,e)/dot(e,e), 0.0, 1.0 );
d = min( d, dot(b,b) );
bvec3 c = bvec3(p.y>=v[i].y,p.y<v[j].y,e.x*w.y>e.y*w.x);
if( all(c) || all(not(c)) ) s*=-1.0;
}
return s*sqrt(d);
}
const int N = 5;
float sdPolygon( in vec2 p, in vec2[N] v )
{
const int num = v.length();
float d = dot(p-v[0],p-v[0]);
float s = 1.0;
for( int i=0, j=num-1; i<num; j=i, i++ )
{
// distance
vec2 e = v[j] - v[i];
vec2 w = p - v[i];
vec2 b = w - e*clamp( dot(w,e)/dot(e,e), 0.0, 1.0 );
d = min( d, dot(b,b) );
// winding number from http://geomalgorithms.com/a03-_inclusion.html
bvec3 cond = bvec3( p.y>=v[i].y,
p.y <v[j].y,
e.x*w.y>e.y*w.x );
if( all(cond) || all(not(cond)) ) s=-s;
}
return s*sqrt(d);
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 p = (2.0*fragCoord-iResolution.xy)/iResolution.y;
vec2 m = (2.0*iMouse.xy-iResolution.xy)/iResolution.y;
vec2 v0 = 0.8*cos( 0.40*iTime + vec2(0.0,2.00) + 0.0 );
vec2 v1 = 0.8*cos( 0.45*iTime + vec2(0.0,1.50) + 1.0 );
vec2 v2 = 0.8*cos( 0.50*iTime + vec2(0.0,3.00) + 2.0 );
vec2 v3 = 0.8*cos( 0.55*iTime + vec2(0.0,2.00) + 4.0 );
vec2 v4 = 0.8*cos( 0.60*iTime + vec2(0.0,1.00) + 5.0 );
// add more points
vec2[] polygon = vec2[](v0,v1,v2,v3,v4);
float d = sdPolygon(p, polygon);
vec3 col = (d>0.0) ? vec3(0.9,0.6,0.3) : vec3(0.65,0.85,1.0);
col *= 1.0 - exp(-6.0*abs(d));
col *= 0.8 + 0.2*cos(140.0*d);
col = mix( col, vec3(1.0), 1.0-smoothstep(0.0,0.015,abs(d)) );
if( iMouse.z>0.001 )
{
d = sdPolygon( m, polygon );
col = mix(col, vec3(1.0,1.0,0.0), 1.0-smoothstep(0.0, 0.005, abs(length(p-m)-abs(d))-0.0025));
col = mix(col, vec3(1.0,1.0,0.0), 1.0-smoothstep(0.0, 0.005, length(p-m)-0.015));
}
fragColor = vec4(col,1.0);
}
Ellipse:
float sdEllipse( in vec2 p, in vec2 ab )
{
p = abs(p); if( p.x > p.y ) {p=p.yx;ab=ab.yx;}
float l = ab.y*ab.y - ab.x*ab.x;
float m = ab.x*p.x/l; float m2 = m*m;
float n = ab.y*p.y/l; float n2 = n*n;
float c = (m2+n2-1.0)/3.0; float c3 = c*c*c;
float q = c3 + m2*n2*2.0;
float d = c3 + m2*n2;
float g = m + m*n2;
float co;
if( d<0.0 )
{
float h = acos(q/c3)/3.0;
float s = cos(h);
float t = sin(h)*sqrt(3.0);
float rx = sqrt( -c*(s + t + 2.0) + m2 );
float ry = sqrt( -c*(s - t + 2.0) + m2 );
co = (ry+sign(l)*rx+abs(g)/(rx*ry)- m)/2.0;
}
else
{
float h = 2.0*m*n*sqrt( d );
float s = sign(q+h)*pow(abs(q+h), 1.0/3.0);
float u = sign(q-h)*pow(abs(q-h), 1.0/3.0);
float rx = -s - u - c*4.0 + 2.0*m2;
float ry = (s - u)*sqrt(3.0);
float rm = sqrt( rx*rx + ry*ry );
co = (ry/sqrt(rm-rx)+2.0*g/rm-m)/2.0;
}
vec2 r = ab * vec2(co, sqrt(1.0-co*co));
return length(r-p) * sign(p.y-r.y);
}
Parabola:
float sdParabola( in vec2 pos, in float k )
{
pos.x = abs(pos.x);
float ik = 1.0/k;
float p = ik*(pos.y - 0.5*ik)/3.0;
float q = 0.25*ik*ik*pos.x;
float h = q*q - p*p*p;
float r = sqrt(abs(h));
float x = (h>0.0) ?
pow(q+r,1.0/3.0) - pow(abs(q-r),1.0/3.0)*sign(r-q) :
2.0*cos(atan(r,q)/3.0)*sqrt(p);
return length(pos-vec2(x,k*x*x)) * sign(pos.x-x);
}
Parabola Segment:
float sdParabola( in vec2 pos, in float wi, in float he )
{
pos.x = abs(pos.x);
float ik = wi*wi/he;
float p = ik*(he-pos.y-0.5*ik)/3.0;
float q = pos.x*ik*ik*0.25;
float h = q*q - p*p*p;
float r = sqrt(abs(h));
float x = (h>0.0) ?
pow(q+r,1.0/3.0) - pow(abs(q-r),1.0/3.0)*sign(r-q) :
2.0*cos(atan(r/q)/3.0)*sqrt(p);
x = min(x,wi);
return length(pos-vec2(x,he-x*x/ik)) *
sign(ik*(pos.y-he)+pos.x*pos.x);
}
float sdParabola( in vec2 pos, in float wi, in float he )
{
pos.x = abs(pos.x);
float ik = wi*wi/he;
float p = ik*(he-pos.y-0.5*ik)/3.0;
float q = pos.x*ik*ik*0.25;
float h = q*q - p*p*p;
float x;
if( h>0.0 ) // 1 root
{
float r = sqrt(h);
x = pow(q+r,1.0/3.0) + pow(abs(q-r),1.0/3.0)*sign(p);
}
else // 3 roots
{
float r = sqrt(p);
x = 2.0*r*cos(acos(q/(p*r))/3.0); // see https://www.shadertoy.com/view/WltSD7 for an implementation of cos(acos(x)/3) without trigonometrics
}
x = min(x,wi);
return length(pos-vec2(x,he-x*x/ik)) *
sign(ik*(pos.y-he)+pos.x*pos.x);
}
void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
vec2 p = (2.0*fragCoord-iResolution.xy)/iResolution.y;
vec2 m = (2.0*iMouse.xy-iResolution.xy)/iResolution.y;
// animate
float t = iTime/2.0;
float w = 0.7+0.69*sin(iTime*0.61+0.0);
float h = 0.4+0.35*sin(iTime*0.53+2.0);
// sdf
float d = sdParabola( p, w, h );
float ra = 0.2*(0.5+0.5*cos(1.4*iTime));
d = (cos(0.5*iTime)>0.0) ? abs(d) - ra : d;
// colorize
vec3 col = (d>0.0) ? vec3(0.9,0.6,0.3) : vec3(1.0,1.1,1.2);
col *= 1.0 - exp(-4.0*abs(d));
col *= 0.7 + 0.2*cos(110.0*d);
col = mix( col, vec3(1.0), 1.0-smoothstep(0.0,0.01,abs(d)) );
if( iMouse.z>0.001 )
{
d = sdParabola(m, w, h );
d = (cos(0.5*iTime)>0.0) ? abs(d) - ra : d;
col = mix(col, vec3(1.0,1.0,0.0), 1.0-smoothstep(0.0, 0.005, abs(length(p-m)-abs(d))-0.0025));
col = mix(col, vec3(1.0,1.0,0.0), 1.0-smoothstep(0.0, 0.005, length(p-m)-0.015));
}
// width and height
d = length(p-vec2(0.0,h))-0.02;
d = min(d, length(p-vec2(w,0.0))-0.02);
col = mix( col, vec3(1.0,1.0,0.0), 1.0-smoothstep(0.0,0.01,d) );
fragColor = vec4(col,1.0);
}
Quadratic Bezier:
float sdBezier( in vec2 pos, in vec2 A, in vec2 B, in vec2 C )
{
vec2 a = B - A;
vec2 b = A - 2.0*B + C;
vec2 c = a * 2.0;
vec2 d = A - pos;
float kk = 1.0/dot(b,b);
float kx = kk * dot(a,b);
float ky = kk * (2.0*dot(a,a)+dot(d,b)) / 3.0;
float kz = kk * dot(d,a);
float res = 0.0;
float p = ky - kx*kx;
float p3 = p*p*p;
float q = kx*(2.0*kx*kx-3.0*ky) + kz;
float h = q*q + 4.0*p3;
if( h >= 0.0)
{
h = sqrt(h);
vec2 x = (vec2(h,-h)-q)/2.0;
vec2 uv = sign(x)*pow(abs(x), vec2(1.0/3.0));
float t = clamp( uv.x+uv.y-kx, 0.0, 1.0 );
res = dot2(d + (c + b*t)*t);
}
else
{
float z = sqrt(-p);
float v = acos( q/(p*z*2.0) ) / 3.0;
float m = cos(v);
float n = sin(v)*1.732050808;
vec3 t = clamp(vec3(m+m,-n-m,n-m)*z-kx,0.0,1.0);
res = min( dot2(d+(c+b*t.x)*t.x),
dot2(d+(c+b*t.y)*t.y) );
// the third root cannot be the closest
// res = min(res,dot2(d+(c+b*t.z)*t.z));
}
return sqrt( res );
}
Bobbly Cross:
float sdBlobbyCross( in vec2 pos, float he )
{
pos = abs(pos);
pos = vec2(abs(pos.x-pos.y),1.0-pos.x-pos.y)/sqrt(2.0);
float p = (he-pos.y-0.25/he)/(6.0*he);
float q = pos.x/(he*he*16.0);
float h = q*q - p*p*p;
float x;
if( h>0.0 ) { float r = sqrt(h); x = pow(q+r,1.0/3.0)-pow(abs(q-r),1.0/3.0)*sign(r-q); }
else { float r = sqrt(p); x = 2.0*r*cos(acos(q/(p*r))/3.0); }
x = min(x,sqrt(2.0)/2.0);
vec2 z = vec2(x,he*(1.0-2.0*x*x)) - pos;
return length(z) * sign(z.y);
}
Tunnel:
float sdTunnel( in vec2 p, in vec2 wh )
{
p.x = abs(p.x); p.y = -p.y;
vec2 q = p - wh;
float d1 = dot2(vec2(max(q.x,0.0),q.y));
q.x = (p.y>0.0) ? q.x : length(p)-wh.x;
float d2 = dot2(vec2(q.x,max(q.y,0.0)));
float d = sqrt( min(d1,d2) );
return (max(q.x,q.y)<0.0) ? -d : d;
}
float dot2( vec2 v ) { return dot(v,v); }
float sdTunnel( in vec2 p, in vec2 wh )
{
p.x = abs(p.x); p.y = -p.y;
vec2 q = p - wh;
float d1 = dot2(vec2(max(q.x,0.0),q.y));
q.x = (p.y>0.0) ? q.x : length(p)-wh.x;
float d2 = dot2(vec2(q.x,max(q.y,0.0)));
float d = sqrt( min(d1,d2) );
return (max(q.x,q.y)<0.0) ? -d : d;
}
// alternative formulation
float sdTunnel2( in vec2 p, in vec2 wh )
{
vec2 q = abs(p);
q.x -= wh.x;
if( p.y>=0.0 )
{
q.x = max(q.x,0.0);
q.y += wh.y;
return -min( wh.x-length(p), length(q) );
}
else
{
q.y -= wh.y;
float f = max(q.x,q.y);
return (f<0.0) ? f : length(max(q,0.0));
}
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 p = (2.0*fragCoord-iResolution.xy)/iResolution.y;
vec2 m = (2.0*iMouse.xy-iResolution.xy)/iResolution.y;
vec2 wh = 0.4 + 0.4*sin(iTime*vec2(1.1,1.2)+vec2(3.0,1.0));
float d = sdTunnel( p, wh );
vec3 col = (d>0.0) ? vec3(0.9,0.6,0.3) : vec3(0.65,0.85,1.0);
col *= 1.0 - exp(-6.0*abs(d));
col *= 0.8 + 0.2*cos(150.0*d);
col = mix( col, vec3(1.0), 1.0-smoothstep(0.0,0.01,abs(d)) );
if( iMouse.z>0.001 )
{
d = sdTunnel( m, wh );
col = mix(col, vec3(1.0,1.0,0.0), 1.0-smoothstep(0.0, 0.005, abs(length(p-m)-abs(d))-0.0025));
col = mix(col, vec3(1.0,1.0,0.0), 1.0-smoothstep(0.0, 0.005, length(p-m)-0.015));
}
fragColor = vec4(col,1.0);
}
Stairs:
float sdStairs( in vec2 p, in vec2 wh, in float n )
{
vec2 ba = wh*n;
float d = min(dot2(p-vec2(clamp(p.x,0.0,ba.x),0.0)),
dot2(p-vec2(ba.x,clamp(p.y,0.0,ba.y))) );
float s = sign(max(-p.y,p.x-ba.x) );
float dia = length(wh);
p = mat2(wh.x,-wh.y, wh.y,wh.x)*p/dia;
float id = clamp(round(p.x/dia),0.0,n-1.0);
p.x = p.x - id*dia;
p = mat2(wh.x, wh.y,-wh.y,wh.x)*p/dia;
float hh = wh.y/2.0;
p.y -= hh;
if( p.y>hh*sign(p.x) ) s=1.0;
p = (id<0.5 || p.x>0.0) ? p : -p;
d = min( d, dot2(p-vec2(0.0,clamp(p.y,-hh,hh))) );
d = min( d, dot2(p-vec2(clamp(p.x,0.0,wh.x),hh)) );
return sqrt(d)*s;
}
float dot2( in vec2 v ) { return dot(v,v); }
float sdStairs( in vec2 p, in vec2 wh, in float n )
{
// base
vec2 ba = wh*n;
float d = min(dot2(p-vec2(clamp(p.x,0.0,ba.x),0.0)),
dot2(p-vec2(ba.x,clamp(p.y,0.0,ba.y))) );
float s = sign(max(-p.y,p.x-ba.x) );
// steps repetition
#if 1
float dia = length(wh);
p = mat2(wh.x,-wh.y, wh.y,wh.x)*p/dia;
float id = clamp(round(p.x/dia),0.0,n-1.0);
p.x = p.x - id*dia;
p = mat2(wh.x, wh.y,-wh.y,wh.x)*p/dia;
#else
float dia2 = dot2(wh);
p = mat2(wh.x,-wh.y,wh.y,wh.x)*p;
float id = clamp(round(p.x/dia2),0.0,n-1.0);
p.x = p.x - id*dia2;
p = mat2(wh.x,wh.y,-wh.y,wh.x)*p/dia2;
#endif
// single step
float hh = wh.y/2.0;
p.y -= hh;
if( p.y>hh*sign(p.x) ) s=1.0;
p = (id<0.5 || p.x>0.0) ? p : -p;
d = min( d, dot2(p-vec2(0.0,clamp(p.y,-hh,hh))) );
d = min( d, dot2(p-vec2(clamp(p.x,0.0,wh.x),hh)) );
return sqrt(d)*s;
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
// normalized pixel coordinates
vec2 p = (2.0*fragCoord-iResolution.xy)/iResolution.y;
vec2 m = (2.0*iMouse.xy-iResolution.xy)/iResolution.y;
p -= vec2(-0.9,-0.5);
m -= vec2(-0.9,-0.5);
// animate
float wi = 0.5 * (0.5+0.3*sin(iTime*1.1+0.0));
float he = wi * (0.5+0.3*sin(iTime*1.3+2.0));
float nu = 5.0;//1.0+floor( 4.95*(0.5 + 0.5*cos(3.0*iTime)) );
// distance
float d = sdStairs(p,vec2(wi,he),nu);
// coloring
vec3 col = (d>0.0) ? vec3(0.9,0.6,0.3) : vec3(0.65,0.85,1.0);
col *= 1.0 - exp(-7.0*abs(d));
col *= 0.8 + 0.2*cos(160.0*abs(d));
col = mix( col, vec3(1.0), 1.0-smoothstep(0.0,0.015,abs(d)) );
// interactivity
if( iMouse.z>0.001 )
{
d = sdStairs(m,vec2(wi,he),nu);
col = mix(col, vec3(1.0,1.0,0.0), 1.0-smoothstep(0.0, 0.005, abs(length(p-m)-abs(d))-0.0025));
col = mix(col, vec3(1.0,1.0,0.0), 1.0-smoothstep(0.0, 0.005, length(p-m)-0.015));
}
fragColor = vec4(col, 1.0);
}
Quadratic Circle:
float sdQuadraticCircle( in vec2 p )
{
p = abs(p); if( p.y>p.x ) p=p.yx;
float a = p.x-p.y;
float b = p.x+p.y;
float c = (2.0*b-1.0)/3.0;
float h = a*a + c*c*c;
float t;
if( h>=0.0 )
{
h = sqrt(h);
t = sign(h-a)*pow(abs(h-a),1.0/3.0) - pow(h+a,1.0/3.0);
}
else
{
float z = sqrt(-c);
float v = acos(a/(c*z))/3.0;
t = -z*(cos(v)+sin(v)*1.732050808);
}
t *= 0.5;
vec2 w = vec2(-t,t) + 0.75 - t*t - p;
return length(w) * sign( a*a*0.5+b-1.5 );
}
// Make this 1 to see the simpler but sometimes incorrect versin
#define USE_SIMPLIFICATION 0
#if USE_SIMPLIFICATION==0
float sdQuadraticCircle( in vec2 p )
{
p = abs(p); if( p.y>p.x ) p=p.yx; // symmetries
float a = p.x-p.y;
float b = p.x+p.y;
float c = (2.0*b-1.0)/3.0;
float h = a*a + c*c*c;
float t;
if( h>=0.0 )
{
h = sqrt(h);
t = sign(h-a)*pow(abs(h-a),1.0/3.0) - pow(h+a,1.0/3.0);
}
else
{
float z = sqrt(-c);
float v = acos(a/(c*z))/3.0;
t = -z*(cos(v)+sin(v)*1.732050808);
}
t *= 0.5;
vec2 w = vec2(-t,t) + 0.75 - t*t - p;
return length(w) * sign( a*a*0.5+b-1.5 );
}
#else
// This version is correct everywhere except at the center of the shape
float sdQuadraticCircle( in vec2 p )
{
p = abs(p); if( p.y>p.x ) p=p.yx; // symmetries
float a = p.x-p.y;
float b = p.x+p.y;
float c = (2.0*b-1.0)/3.0;
float h = sqrt(max(a*a+c*c*c,0.0));
float u = pow(max(h-a,0.0),1.0/3.0);
float v = pow( h+a, 1.0/3.0);
float t = (u-v)*0.5;
vec2 w = vec2(-t,t) + 0.75 - t*t - p;
return length(w)*sign( a*a*0.5+b-1.5 );
}
#endif
/*
// VERY BAD approximation, not usable
float sdQuadraticCircle( in vec2 pos )
{
pos = abs(pos); if( pos.y>pos.x ) pos=pos.yx;
float a = pos.x-pos.y; float a2 = a*a;
float b = pos.x+pos.y;
return (a2*0.5+b-1.5)/sqrt(a2+1.0)/sqrt(2.0);
}
*/
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
// normalized pixel coordinates
vec2 p = (2.0*fragCoord-iResolution.xy)/iResolution.y;
vec2 m = (2.0*iMouse.xy-iResolution.xy)/iResolution.y;
float px = 2.0/iResolution.y;
const float si = 0.8;
// distance
float d = sdQuadraticCircle(p/si)*si;
// coloring
vec3 col = (d>0.0) ? vec3(0.9,0.6,0.3) : vec3(0.65,0.85,1.0);
col *= 1.0 - exp(-9.0*abs(d));
col *= 0.6 + 0.4*smoothstep(-0.5,0.5,cos(130.0*abs(d)));
col = mix( col, vec3(1.0), 1.0-smoothstep(0.01-px,0.01+px,abs(d)) );
// mouse interaction
if( iMouse.z>0.001 )
{
d = sdQuadraticCircle(m/si)*si;
col = mix(col, vec3(1.0,1.0,0.0), 1.0-smoothstep(0.0, 0.005, abs(length(p-m)-abs(d))-0.0025));
col = mix(col, vec3(1.0,1.0,0.0), 1.0-smoothstep(0.0, 0.005, length(p-m)-0.015));
}
fragColor = vec4(col,1.0);
}
Hyperbola:
float sdHyberbola( in vec2 p, in float k, in float he ) // k in (0,inf)
{
p = abs(p);
p = vec2(p.x-p.y,p.x+p.y)/sqrt(2.0);
float x2 = p.x*p.x/16.0;
float y2 = p.y*p.y/16.0;
float r = k*(4.0*k - p.x*p.y)/12.0;
float q = (x2 - y2)*k*k;
float h = q*q + r*r*r;
float u;
if( h<0.0 )
{
float m = sqrt(-r);
u = m*cos( acos(q/(r*m))/3.0 );
}
else
{
float m = pow(sqrt(h)-q,1.0/3.0);
u = (m - r/m)/2.0;
}
float w = sqrt( u + x2 );
float b = k*p.y - x2*p.x*2.0;
float t = p.x/4.0 - w + sqrt( 2.0*x2 - u + b/w/4.0 );
t = max(t,sqrt(he*he*0.5+k)-he/sqrt(2.0));
float d = length( p-vec2(t,k/t) );
return p.x*p.y < k ? d : -d;
}
Cool S:
float sdfCoolS( in vec2 p )
{
float six = (p.y<0.0) ? -p.x : p.x;
p.x = abs(p.x);
p.y = abs(p.y) - 0.2;
float rex = p.x - min(round(p.x/0.4),0.4);
float aby = abs(p.y-0.2)-0.6;
float d = dot2(vec2(six,-p.y)-clamp(0.5*(six-p.y),0.0,0.2));
d = min(d,dot2(vec2(p.x,-aby)-clamp(0.5*(p.x-aby),0.0,0.4)));
d = min(d,dot2(vec2(rex,p.y -clamp(p.y ,0.0,0.4))));
float s = 2.0*p.x + aby + abs(aby+0.4) - 0.4;
return sqrt(d) * sign(s);
}
float dot2( vec2 v ) { return dot(v,v); }
float sdfCoolS( in vec2 p )
{
// symmetries
float six = (p.y<.0) ? -p.x : p.x;
p.x = abs(p.x);
p.y = abs(p.y) - .2;
float rex = p.x - min(round(p.x/.4),.4);
float aby = abs(p.y-.2)-.6;
// line segments
float d = dot2(vec2(six,-p.y)-clamp(.5*(six-p.y),.0,.2));
d = min(d,dot2(vec2(p.x,-aby)-clamp(.5*(p.x-aby),.0,.4)));
d = min(d,dot2(vec2(rex,p.y -clamp(p.y ,.0,.4))));
// interior vs exterior
float s = 2.*p.x+aby+abs(aby+.4)-.4;
return sqrt(d) * sign(s);
}
void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
const float scale = 1.25;
vec2 p = scale*(2.0*fragCoord-iResolution.xy)/iResolution.y;
vec2 m = scale*(2.0*iMouse.xy-iResolution.xy)/iResolution.y;
float px = scale*2.0/iResolution.y;
float d = sdfCoolS(p);
// colorize
vec3 col = (d>0.0) ? vec3(0.9,0.6,0.3) : vec3(0.65,0.85,1.0);
col *= 1.0 - exp2(-20.0*abs(d));
col *= 0.7 + 0.2*cos(120.0*d);
col = mix( col, vec3(1.0), 1.0-smoothstep(0.0,3.0*px,abs(d)) );
// mouse
if( iMouse.z>0.001 )
{
float d = sdfCoolS(m);
float l = length(p-m);
col = mix(col, vec3(1.0,1.0,0.0), 1.0-smoothstep(0.0, 2.0*px, abs(l-abs(d))));
col = mix(col, vec3(1.0,1.0,0.0), 1.0-smoothstep(0.0, 2.0*px, l-px*3.0));
}
fragColor = vec4(col,1.0);
}
Circle Wave:
float sdCircleWave( in vec2 p, in float tb, in float ra )
{
tb = 3.1415927*5.0/6.0*max(tb,0.0001);
vec2 co = ra*vec2(sin(tb),cos(tb));
p.x = abs(mod(p.x,co.x*4.0)-co.x*2.0);
vec2 p1 = p;
vec2 p2 = vec2(abs(p.x-2.0*co.x),-p.y+2.0*co.y);
float d1 = ((co.y*p1.x>co.x*p1.y) ? length(p1-co) : abs(length(p1)-ra));
float d2 = ((co.y*p2.x>co.x*p2.y) ? length(p2-co) : abs(length(p2)-ra));
return min(d1, d2);
}
float sdCircleWave( in vec2 p, in float tb, in float ra )
{
tb = 3.1415927*5.0/6.0 * max(tb,0.0001);
vec2 co = ra*vec2(sin(tb),cos(tb));
p.x = abs(mod(p.x,co.x*4.0)-co.x*2.0);
vec2 p1 = p;
vec2 p2 = vec2(abs(p.x-2.0*co.x),-p.y+2.0*co.y);
float d1 = ((co.y*p1.x>co.x*p1.y) ? length(p1-co) : abs(length(p1)-ra));
float d2 = ((co.y*p2.x>co.x*p2.y) ? length(p2-co) : abs(length(p2)-ra));
return min( d1, d2);
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
// normalized pixel coordinates
vec2 p = (2.0*fragCoord-iResolution.xy)/iResolution.y;
vec2 m = (2.0*iMouse.xy-iResolution.xy)/iResolution.y;
// animation
float tb = 0.5-0.5*cos(iTime/2.2);
// distance
float d = sdCircleWave(p,tb, 0.3);
// coloring
vec3 col = (d>0.0) ? vec3(0.9,0.6,0.3) : vec3(0.65,0.85,1.0);
col *= 1.0 - exp(-7.0*abs(d));
col *= 0.8 + 0.2*cos(128.0*abs(d));
col = mix( col, vec3(1.0), 1.0-smoothstep(0.0,0.015,abs(d)) );
if( iMouse.z>0.001 )
{
d = sdCircleWave(m,tb,0.3);
col = mix(col, vec3(1.0,1.0,0.0), 1.0-smoothstep(0.0, 0.005, abs(length(p-m)-abs(d))-0.0025));
col = mix(col, vec3(1.0,1.0,0.0), 1.0-smoothstep(0.0, 0.005, length(p-m)-0.015));
}
fragColor = vec4(col, 1.0);
}
使形状变圆润
所有上述形状都可以通过从它们的距离函数中减去一个常数而转换成圆润的形状。实际上,这会将等值面(我猜应该是等周面)从零级移动到其中一个外环,这些自然就是圆润的,正如在所有上述图像中的黄色区域所见。因此,基本上对于任何由d(x,y) = sdf(x,y)定义的形状,可以通过计算d(x,y) = sdf(x,y) - r来使其圆润。
float opRound( in vec2 p, in float r )
{
return sdShape(p) - r;
}
这些是一些例子:圆润的线条、圆润的三角形、圆润的盒子和一个圆润的五边形:
使形状呈环状
类似地,形状可以被做成环状(就像戒指或洋葱的分层状),方法是取它们的绝对值然后从其场中减去一个常数。因此,对于任何由d(x,y) = sdf(x,y)定义的形状,计算d(x,y) = |sdf(x,y)| - r:
float opOnion( in vec2 p, in float r )
{
return abs(sdShape(p)) - r;
}
以下是一些例子:环形圆线,环形三角形,环形方框和环形五边形。