“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