Heart Slasher

https://www.shadertoy.com/view/l3G3R1

Shader code
shader_type canvas_item;

#define iTime TIME
#define iResolution 1.0/SCREEN_PIXEL_SIZE

uniform float ARROWS : hint_range(-1.0, 100.0, 1) = 5.0;
uniform float VANISH_TIME = 1.5;
uniform float animation_speed : hint_range(0.0, 10.0, 0.1) = 2.0;
uniform float shake_amplitude : hint_range(0.0, 5.0, 0.1) = 0.7;
uniform vec3 heart_color = vec3(1, 0, 0);
uniform vec3 halo_color = vec3(1.000, 0.922, 0.078);
uniform vec3 bg_color = vec3(0.5, 0.0, 0.0);
uniform bool remove_bg = false;

const float HPI = PI * 0.5;

float dot2(vec2 x) {
    return dot(x, x);
}

float hash11(float p) {
    p = fract(p * .1031);
    p *= p + 33.33;
    p *= p + p;
    return fract(p);
}

float noise(float p) {
	float fl = floor(p);
	float fc = fract(p);
	return mix(hash11(fl), hash11(fl + 1.0), fc);
}

float hash12(vec2 p) {
	vec3 p3 = fract(p.xyx * .1031);
    p3 += dot(p3, p3.yzx + 33.33);
    return fract((p3.x + p3.y) * p3.z);
}

float noise2d(vec2 p) {
	vec2 ip = floor(p);
	vec2 u = fract(p);
	u = u * u * (3.0 - 2.0 * u);
	float res = mix(
		mix(hash12(ip), hash12(ip + vec2(1, 0)), u.x),
		mix(hash12(ip + vec2(0, 1)), hash12(ip + vec2(1)), u.x), u.y);
	return res * res;
}

float fbm(float p, int octaves) {
	float s = 0.0, m = 0.0, a = 1.0;
	for(int i = 0; i < octaves; i++) {
		s += a * noise(p);
		m += a;
		a *= 0.6;
		p *= 1.8;
	}
	return s / m;
}

float fbm2d(vec2 p, int octaves) {
	float s = 0.0, m = 0.0, a = 1.0;
	for(int i = 0; i < octaves; i++) {
		s += a * noise2d(p);
		m += a;
		a *= 0.6;
		p *= 1.8;
	}
	return s / m;
}


float heart(vec2 p) {
    p.y += 0.5;
    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 shake(float t) {
    t = clamp(t, 0.0, 1.0);
    return (fbm(pow(t, 0.3) * 8.0, 3) * (1.0 + cos(t * HPI)) - sin(t * HPI)) * (1.0 - t) * pow(t, 0.7);
}

float line(vec2 p, vec2 p1, vec2 p2) {
    vec2 center = (p1 + p2) * 0.5;
    float len = length(p2 - p1);
    vec2 dir = (p2 - p1) / len;
    vec2 rel_p = p - center;
    return dot(rel_p, vec2(dir.y, -dir.x));
}

float segment(vec2 p, vec2 p1, vec2 p2) {
    vec2 center = (p1 + p2) * 0.5;
    float len = length(p2 - p1);
    vec2 dir = (p2 - p1) / len;
    vec2 rel_p = p - center;
    float dist1 = abs(dot(rel_p, vec2(dir.y, -dir.x)));
    float dist2 = abs(dot(rel_p, dir)) - 0.5 * len;
    return max(dist1, dist2);
}

float arrow(vec2 uv) {
    const float outline = 0.01;
    const float line_width = 1.8;
    float height = 0.2 * max(0.5, sqrt(uv.x));
    const float head_size = 0.2;
    const float size = 0.02;
    uv.x -= line_width * 0.45 + head_size * 0.5;

    float a1 = line(uv, -head_size * vec2(1, -height), vec2(0));
    float a2 = line(uv, -head_size * vec2(1, -height), -vec2(3.0 * head_size / 4.0, 0));
    float a3 = line(uv, -head_size * vec2(1, height), vec2(0));
    float a4 = line(uv, -head_size * vec2(1, height), -vec2(3.0 * head_size / 4.0, 0));
    float head = max(max(-a1, a3), -max(-a2, a4));

    uv.y = abs(uv.y);
    vec2 n = vec2(0,(fbm(uv.x * 5.0 + iTime * 0.5, 3) * 2.0 - 1.0) * 0.03);
    float tail = segment(uv - n, vec2(-line_width*0.9, 0), vec2(-line_width - head_size * 0.9, head_size * 0.5));
    tail = min(tail, segment(uv - n, vec2(-line_width*0.85 - head_size , 0), vec2(-line_width - head_size * 1.4, head_size * 0.4)));
    tail = min(tail, segment(uv - n, vec2(-line_width*0.93 - head_size , 0), vec2(-line_width - head_size * 1.7, head_size * 0.3)));

    float stick = segment(uv, - vec2((head_size * 1.5 + line_width), 0), vec2(-0.2, 0));
    stick = min(stick, tail);

    return min(abs(head - size) - outline, mix(stick - outline * smoothstep(-1.9, -1.2, uv.x), max(outline, head - outline), step(head, size)));
}

float shoot_arrow(vec2 uv, float t, float id) {
    t = clamp(t - id, 0.0, 1.0);
    float f = length(fwidth(uv));
    vec2 auv = uv;
    float a = noise(-id * 5.0  - 0.05);
    auv = cos(a * TAU) * auv + sin(a * TAU) * vec2(-auv.y, auv.x);
    auv.x -= (smoothstep(0.0, 0.8, t * 2.0) - 1.0) * 7.0;
    return arrow(auv);
}

void fragment()
{
    float mr = min(iResolution.x, iResolution.y);
    vec2 uv = (FRAGCOORD.xy * 2.0 - iResolution.xy) / mr * 1.5;
	uv.y = -uv.y;
    float f = length(fwidth(uv));
    float t = mod(iTime * animation_speed, ARROWS + VANISH_TIME);
    float ft = floor(t);

    float a = noise(-ft * 5.0  - 0.05);
    vec2 dir = vec2(cos(-a * TAU), sin(-a * TAU));
    float ts = fract(min(t, ARROWS));
    float s = shake((ts * 2.0 - 0.65) * 2.5) * shake_amplitude;
    uv -= dir * s;


    float d = heart(uv);

    float m = smoothstep(0.0 + f, 0.0 - f, d);
    vec3 col = vec3(m) * heart_color;
    col += sqrt(max(0.0, -d * 4.0)) - m;
    col = abs(col);

    float arrw = shoot_arrow(uv, t, 0.0);
    for (float i = 1.0; i < ARROWS; ++i)
        arrw = min(arrw, shoot_arrow(uv, t, i));
    arrw += fbm2d(uv * 4.0, 4) * smoothstep(ARROWS, ARROWS + VANISH_TIME, t) * 0.5;
    col = mix(vec3(smoothstep(f, -f, arrw)), col, m);

    float flash = (1.0 - smoothstep(0.0, 1.0, ts)) * smoothstep(0.5, 0.9, ts * 2.0) * (1.0 + abs(s) * 6.0) * 0.7;
    float g = (1.0 - m) * exp(-sqrt(max(0.0, d)) * 3.0);
    col += g * sin(g * halo_color + bg_color);
    col.rb += (col.g + col.b) * vec2(1.0 / g, g + flash) - vec2(col.r, col.r);

    COLOR = vec4(col,1.0);
	if(remove_bg == true){
		COLOR.a = COLOR.r;
	}

}
This shader is a port from an existing Shadertoy project. Shadertoy shaders are by default protected under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported (CC BY-NC-SA 3.0) license unless anything else has been stated by the author. For more info, see our License terms.

More from RayL019

vortex and shrink

Quadrilateral Grid

High Pass vs Fwidth

Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments