2D SDF距离函数(三)

Number of views 148

Moon

image1739099433698.png

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

image1739099526809.png

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

image1739099765405.png

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

image1739099874036.png

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

image1739100062849.png

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

image1739100168758.png

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

image1739100283595.png

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

image1739100411527.png

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

image1739100477339.png

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

image1739100601342.png

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

image1739100706561.png

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

image1739100838505.png

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:

image1739100908686.png

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

image1739101005431.png

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

image1739101133037.png

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

image1739101238183.png

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

image1739101296152.png

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

image1739101385330.png

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;
}

这些是一些例子:圆润的线条、圆润的三角形、圆润的盒子和一个圆润的五边形:

image1739101665535.png

使形状呈环状

类似地,形状可以被做成环状(就像戒指或洋葱的分层状),方法是取它们的绝对值然后从其场中减去一个常数。因此,对于任何由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;
}

以下是一些例子:环形圆线,环形三角形,环形方框和环形五边形。

image1739101819147.png

0 Answers