“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

rendering

flowers

Stretch out a little bit

Stagger the time a little bit more

Fireworks can be set off not only during Spring Festival, but also on Valentine’s Day

Introduction to design Idea

First, we implement a glowing particle, code as

vec3 burst(vec2 st, vec2 pos, float r, vec3 col)
{
    st -= pos;
    r = 0.6 * r * r;

    /// glow effect
    return (r / dot(st, st)) * col * 0.6;
}
Copy the code

Then, according to the physics knowledge in middle school, the particle rises at an initial speed and gradually slows down under the influence of the acceleration of gravity, and then reaches the maximum height it can reach.

The relevant codes are as follows

// s = p0 + ut + 0.5at^2
/// distance acceleration formula
vec2 get_pos(vec2 u, vec2 a, vec2 p0, float t, float ang)
{
    /// Update the current position based on the initial position, horizontal and vertical velocity and acceleration
    vec2 d = p0 + vec2(u.x * cos(ang), u.y * sin(ang)) * t + 0.5 * a * t * t;
    return d;
}

// Particle velocity at time t
vec2 get_velocity(vec2 u, vec2 a, float t, float ang)
{
    /// Update the current speed based on acceleration, current horizontal and vertical speed
    return vec2(u.x * cos(ang), u.y * sin(ang)) + a * t;
}
Copy the code

Then we have to consider the initial position and velocity of the new particle when it reaches a certain height and then explodes (heart shape). Then, as before, the vertical position and velocity are updated with the acceleration of gravity.

The relevant code is

        /// @note explosion after the particle diffusion
        /// When the particle stops rising and the current time of the particle has reached the time of rising

        if (v.y > 6.5 && v.y < 0.0 && t_i >= t_up /*&& SPAWN == 1*/)
        {
            /// Divide a circle into sectors according to the Angle
            float unit = (360. / snp);
            for (float j = 0.0; j < snp; j++)
            {
                float ang = rad(j * unit);

                float r = 0.035;             ///< radius of the heart-shaped particle
                r -= (t_i - t_up) * R_RATIO; ///< change the particle size according to the time difference (smaller)

                /// --------------------------------------------------
                /// @note Calculates Cartesian coordinates based on the Angle
                float x = cos(ang); //coords of unit circle
                float y = sin(ang);
                /// The heart-shaped formula
                y = y + abs(x) * sqrt((8. - abs(x)) / 50.0 );
                /// The heart-shaped velocity vector decreases over time
                vec2 heart = vec2(x * x + y * y) * (0.4 / (t_i * sqrt(t_i)));

                /// Update the position of the particle according to the current velocity and acceleration of the heart, the initial position, etc
                vec2 S = get_pos(heart, acc * ACC_RATIO, h_max, t_i - (t_up), ang);
                /// --------------------------------------------------

                // vec3 pcol = colors[int(rand.x * float(NUM_COLS))];
                vec3 pcol = vec3(1.);

                particles += burst(uv, S, max(0.0, r), pcol); }}Copy the code

The schematic diagram of the heart-shaped formula is

And that gives us the initial position of each particle at the time of the explosion.

It is worth noting that the radius (size) of the particle also decreases over time

float r = 0.035; ///< radius of the heart-shaped particle
r -= (t_i - t_up) * R_RATIO; ///< change the particle size according to the time difference (smaller)
Copy the code

Complete code and detailed comments


//random value
vec2 N22(vec2 p)
{
    vec3 a = fract(p.xyx * vec3(123.34.234.34.345.65));
    a += dot(a, a + 34.45);
    return fract(vec2(a.x * a.y, a.y * a.z));
}

vec3 burst(vec2 st, vec2 pos, float r, vec3 col)
{
    st -= pos;
    r = 0.6 * r * r;

    /// glow effect
    return (r / dot(st, st)) * col * 0.6;
}

// s = p0 + ut + 0.5at^2
/// distance acceleration formula
vec2 get_pos(vec2 u, vec2 a, vec2 p0, float t, float ang)
{
    /// Update the current position based on the initial position, horizontal and vertical velocity and acceleration
    vec2 d = p0 + vec2(u.x * cos(ang), u.y * sin(ang)) * t + 0.5 * a * t * t;
    return d;
}

// Particle velocity at time t
vec2 get_velocity(vec2 u, vec2 a, float t, float ang)
{
    /// Update the current speed based on acceleration, current horizontal and vertical speed
    return vec2(u.x * cos(ang), u.y * sin(ang)) + a * t;
}

#define rad(x) radians(x)
float np = 100.;
float snp = 20.;
float R = 0.032;
float R_RATIO = 0.04;
float ACC_RATIO = 0.03;
float ANG = 90.;
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv = (2.*fragCoord - iResolution.xy) / iResolution.y;
    float aspect = iResolution.x / iResolution.y;
    vec3 col = vec3(0.0);
    float t = mod(iTime, 10.);

    vec2 u = vec2(0.);                / / / < initial velocity
    const vec2 acc = vec2(0.0.9.8); ///< gravity acc
    float ang = rad(ANG);             ///< the emission Angle of rising particles

    vec3 particles = vec3(0.0); //particle

    for (float i = 0.; i < np; i++)
    {
        float r = R;
        vec2 rand = N22(vec2(i));

        /// @note particles rise before explosion

        /// the initial position
        vec2 ip = vec2(sin(30.*rand.x) * aspect, 1. + r);

        // true initialization speed
        u = vec2(sin(5.*rand.x), 5. + sin(4.*rand.y));

        float t_i = t - i / 5.; ///< time differentiation
        vec2 s = get_pos(u, acc, ip, t_i, ang);
        vec2 v = get_velocity(u, acc, t_i, ang);

        /// Calculate the vertical movement time
        float t_up = u.y * sin(ang) / abs(acc.y);
        /// Calculate the maximum height of upward movement according to the time
        vec2 h_max = get_pos(u, acc, ip, t_up, ang);

        vec3 pcol = vec3(1..1..1.);


        if (v.y < 0.5) ///< the falling speed exceeds a certain size and disappears
        {
            r = 0.0;    / / / < hidden
        }

        particles += burst(uv, s, r, pcol); ///< emit rising particles


        /// @note explosion after the particle diffusion
        /// When the particle stops rising and the current time of the particle has reached the time of rising

        if (v.y > 6.5 && v.y < 0.0 && t_i >= t_up /*&& SPAWN == 1*/)
        {
            /// Divide a circle into sectors according to the Angle
            float unit = (360. / snp);
            for (float j = 0.0; j < snp; j++)
            {
                float ang = rad(j * unit);

                float r = 0.035;             ///< radius of the heart-shaped particle
                r -= (t_i - t_up) * R_RATIO; ///< change the particle size according to the time difference (smaller)

                /// --------------------------------------------------
                /// @note Calculates Cartesian coordinates based on the Angle
                float x = cos(ang); //coords of unit circle
                float y = sin(ang);
                /// The heart-shaped formula
                y = y + abs(x) * sqrt((8. - abs(x)) / 50.0 );
                /// The heart-shaped velocity vector decreases over time
                vec2 heart = vec2(x * x + y * y) * (0.4 / (t_i * sqrt(t_i)));

                /// Update the position of the particle according to the current velocity and acceleration of the heart, the initial position, etc
                vec2 S = get_pos(heart, acc * ACC_RATIO, h_max, t_i - (t_up), ang);
                /// --------------------------------------------------

                vec3 pcol = vec3(1.);
                particles += burst(uv, S, max(0.0, r), pcol);
            }
        }

    }

    col = particles;

    fragColor = vec4(col,  1.0);
}
Copy the code

The following “core” effects can be achieved with the above code

With a few tweaks, it looks like the beginning of this article. For more interesting results, stay tuned for other articles in ShaderJoy’s column.