“PK creative Spring Festival, I am participating in the” Spring Festival Creative submission contest “, please see: Spring Festival Creative Submission Contest”

ShaderJoy — Shader effects are fun

Full rendering

Design ideas

I designed this “small scratching axe” shape is very simple, using only three basic graphics

  • circular
  • (round head) curved line
  • (round head) straight line

So how do we draw these three basic shapes in shader? The answer is through SDF! [For those who want to learn more, check out my ShaderJoy column.]

For the sake of space, I will directly list the three SDF functions used in this article

  • sdCircle
  • udSegment
  • sdArc

The use of sdCircle

SdCircle code is shown below

/ / / @ note circle
float sdCircle( in vec2 p, in float r )
{
    return length(p) - r;
}
Copy the code

Through the circle we can first draw the basic shape of the two ears (external auricle)

Then again, draw the inner ear

Then draw the big face plate

And the eyes and mouth

The use of udSegment

The udSegment codes are as follows

/// @note (round head
/// @param a starting point
/// @param b endpoint
float udSegment( in vec2 p, in vec2 a, in vec2 b )
{
    vec2 ba = b - a;
    vec2 pa = p - a;
    float h = clamp( dot(pa, ba) / dot(ba, ba), 0.0.1.0 );
    return length(pa - h * ba);
}
Copy the code

With this, we can draw a nose for the tickling Axe

Isn’t it a little cute? But it doesn’t work that way, because it looks like a little bear… After all, it is the “little scratching axe” and should be given a king’s mark! That’s going to work with our next SDF function.

The use of sdArc

The specific codes of sdArc are shown below

/// @note (round head) arc
// @param sc Angle, arc length
// @param ra arc length
/// @param rb
float sdArc( in vec2 p, in vec2 sc, in float ra, float rb )
{
    // sc is the sin/cos of the arc's aperture
    p.x = abs(p.x);
    return ((sc.y * p.x > sc.x * p.y) ? length(p - sc * ra) :
            abs(length(p) - ra)) - rb;
}
Copy the code

Since the structure of “King” is three horizontal lines and one vertical line (the three horizontal lines are slightly curved), I decided to use sdArc to draw the “three horizontal lines” and udSegment to draw the “one vertical line”.

Feel also almost meaning, enrich its stripes

And add a pair of spiritual paper to it

It’s done!

conclusion

With these three basic graphics after the drawing, in fact, only need to put them together reasonably, but in fact, it is also the most patient work, because there are many details of the parameters need to be adjusted… Ah bah! Set-up is!

Finally, the complete code is shown below

The complete code


// Copyright Notice: Please attach the original source and link.

#define YELLOW vec3(255., 214., 34.)/255.
#define ORANGE vec3(255., 80., 2.)/255.
#define BLACK vec3(29., 21., 22.)/255.
#define WHITE vec3(1.)
#define3.14159 Pi?

/// ---------------- SDF ----------------

/ / / @ note circle
float sdCircle( in vec2 p, in float r )
{
    return length(p) - r;
}

/// @note (round head) arc
// @param sc Angle, arc length
// @param ra arc length
/// @param rb
float sdArc( in vec2 p, in vec2 sc, in float ra, float rb )
{
    // sc is the sin/cos of the arc's aperture
    p.x = abs(p.x);
    return ((sc.y * p.x > sc.x * p.y) ? length(p - sc * ra) :
            abs(length(p) - ra)) - rb;
}

/// @note (round head
/// @param a starting point
/// @param b endpoint
float udSegment( in vec2 p, in vec2 a, in vec2 b )
{
    vec2 ba = b - a;
    vec2 pa = p - a;
    float h = clamp( dot(pa, ba) / dot(ba, ba), 0.0.1.0 );
    return length(pa - h * ba);
}

/// ---------------- SDF ----------------

// @note rotation at (0, 0)
vec2 rot(vec2 uv, float a)
{
    // [uv.x uv.y] * [cos(a), sin(a),
    // -sin(a), cos(a)]
    return vec2(uv.x * cos(a) - uv.y * sin(a), uv.y * cos(a) + uv.x * sin(a));
}

vec2 rotCenter(vec2 uv, float a, vec2 center)
{
    return rot(uv - center, a) + center;
}

/ / / @ note
float smin( float d1, float d2, float k )
{
    float h = clamp( 0.5 + 0.5 * (d2 - d1) / k, 0.0.1.0 );
    return mix( d2, d1, h ) - k * h * (1.0 - h);
}

void drawStripe(vec2 uv, vec2 offset, float tb, float ra, float rb, inout vec3 col)
{
    float arc_t = sdArc(uv - offset,                 vec2(sin(tb), cos(tb)), ra, rb);
    float arc_m = sdArc(uv - offset + vec2(. 0.13.), vec2(sin(tb), cos(tb)), ra, rb);
    float arc_b = sdArc(uv - offset + vec2(. 0.25.), vec2(sin(tb), cos(tb)), ra, rb);

    float arc_3 = min(1..min(sign(arc_t), min(sign(arc_m), sign(arc_b))));
    col = mix(BLACK, col, arc_3);
    col = mix( col, BLACK, 1.0 - smoothstep(0.0, AA, abs(arc_t)));///< edge smoothing anti-aliasing
    col = mix( col, BLACK, 1.0 - smoothstep(0.0, AA, abs(arc_m)) );
    col = mix( col, BLACK, 1.0 - smoothstep(0.0, AA, abs(arc_b)) );
}

const float AA = 0.007;
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    /// @note converts screen coordinates to [-1., 1.]
    /// Start at the center of the screen
    vec2 uv = (2.0 * fragCoord - iResolution.xy) / iResolution.y;

    /// @note builds the SDF for each component
    / / / @ note face
    float faceSDF = sdCircle(uv - vec2(0..- 83.), 1.02);

    / / / @ note the ear
    float leftOutterEarSDF = sdCircle(uv - vec2(- 61..-).), 31.);
    float rightOutterEarSDF = sdCircle(uv - vec2(+61..-).), 31.);
    float leftInnerEarSDF = sdCircle(uv - vec2(- 61..-).), 15.);
    float rightInnerEarSDF = sdCircle(uv - vec2(+61..-).), 15.);

    / / / @ note eyes
    float leftEyeSDF = sdCircle(uv - vec2(33. -.- 61.), .06);
    float rightEyeSDF = sdCircle(uv - vec2(+33..- 61.), .06);

    / / / @ note mouth
    float leftMouthSDF = sdCircle(uv - vec2(21. -.1.), 291.);
    float rightMouthSDF = sdCircle(uv - vec2(+21..1.), 291.);

    / / to draw
    vec3 col = WHITE; / / / < background

    / / / @ note the ear
    col = mix(YELLOW, col, smoothstep(0...01, leftOutterEarSDF));
    col = mix(YELLOW, col, smoothstep(0...01, rightOutterEarSDF));
    col = mix(ORANGE, col, smoothstep(0...01, leftInnerEarSDF));
    col = mix(ORANGE, col, smoothstep(0...01, rightInnerEarSDF));

    / / / @ note face
    col = mix(YELLOW, col, smoothstep(0...01, faceSDF));

    / / / @ note eyes
    col = mix(BLACK, col, smoothstep(0...01, leftEyeSDF));
    col = mix(BLACK, col, smoothstep(0...01, rightEyeSDF));

    / / / @ note mouth
    float mouth = smin(leftMouthSDF, rightMouthSDF, 0.05);
    col = mix(WHITE, col, smoothstep(0...01, mouth));

    / / / @ note nose
    float nose = udSegment( uv, vec2(- 038..0.73), vec2(038..- 73.)) -085.;
    col = mix(BLACK, col, smoothstep(0...01, nose));

    / / / @ note king
    float d = udSegment( uv, vec2(0..0.25), vec2(. 0.-.06)) -.03; ///< |
    col = mix( col, BLACK, 1.0 - smoothstep(0.0, AA, abs(d)) );

    float tb = Pi / 12.;
    float arc_t = sdArc(uv - vec2(0..0.9), vec2(sin(tb), cos(tb)), 84..0.03); / / / < 3
    float arc_m = sdArc(uv - vec2(0..1.0), vec2(sin(tb), cos(tb)), 84..0.03);
    float arc_b = sdArc(uv - vec2(0..1.1), vec2(sin(tb), cos(tb)), 84..0.03);

    float wang = min(1..min(sign(d), min(sign(arc_t), min(sign(arc_m), sign(arc_b)))));
    col = mix(BLACK, col, wang);

    col = mix( col, BLACK, 1.0 - smoothstep(0.0, AA, abs(arc_t)));///< edge smoothing anti-aliasing
    col = mix( col, BLACK, 1.0 - smoothstep(0.0, AA, abs(arc_m)) );
    col = mix( col, BLACK, 1.0 - smoothstep(0.0, AA, abs(arc_b)) );

    / / / @ note pattern
    float ttb = Pi / 20.;
    drawStripe(uv, vec2(- 82..1.52), ttb, 84..0.035, col);
    drawStripe(uv, vec2(82..1.52), ttb, 84..0.035, col);

    / / / @ note beard
    float angle = Pi / 6.* (. 5 * sin(iTime * 3.) + . 5);

    / / / static version
    float leftBeard = udSegment( uv, vec2(4 -..0.77), vec2(- 618..- 618.)) - 008.;
    col = mix(BLACK, col, smoothstep(0...01, leftBeard));
    
    / / / static version
    float rightBeard = udSegment( uv, vec2(4..0.77), vec2(618..- 618.)) -008.;
    col = mix(BLACK, col, smoothstep(0...01, rightBeard));

    fragColor = vec4(col, 1.0);
}

Copy the code