1

Introduction

In the effect of drawing the trajectory , after a while, it will be found that there are only a few fixed trajectories left in the end. This phenomenon is also mentioned in the original of , and it also provides solutions. I still want to look at the source code. Look.

reason

Over time, some particles will disappear when the offset exceeds the range, so it is necessary to randomly reset the disappearing wind particles.

solution

Issues to consider are:

  • When to reset?
  • What is the judgment condition for reset?
  • What is the way to reset?

When to reset?

In the drawing track of , we know that the generated offset is in the last stage of updating the particle texture information. At this time, it is more appropriate to judge whether to keep the new particle state or reset it.

What is the judgment condition for reset?

The relevant main logic is as follows:


const updateFrag = `
uniform float u_rand_seed;
uniform float u_drop_rate;
uniform float u_drop_rate_bump;

// pseudo-random generator
const vec3 rand_constants = vec3(12.9898, 78.233, 4375.85453);
float rand(const vec2 co) {
    float t = dot(rand_constants.xy, co);
    return fract(sin(t) * (rand_constants.z + t));
}

void main() {
  vec4 color = texture2D(u_particles, v_tex_pos);
  vec2 pos = vec2(
      color.r / 255.0 + color.b,
      color.g / 255.0 + color.a); // decode particle position from pixel RGBA

  vec2 velocity = mix(u_wind_min, u_wind_max, lookup_wind(pos));
  float speed_t = length(velocity) / length(u_wind_max);

  pos = fract(1.0 + pos + offset);
  // a random seed to use for the particle drop
  vec2 seed = (pos + v_tex_pos) * u_rand_seed;

  // drop rate is a chance a particle will restart at random position, to avoid degeneration
  float drop_rate = u_drop_rate + speed_t * u_drop_rate_bump;
  float drop = step(1.0 - drop_rate, rand(seed));

  vec2 random_pos = vec2(
      rand(seed + 1.3),
      rand(seed + 2.1));
  pos = mix(pos, random_pos, drop);
}
`
this.dropRate = 0.003; // how often the particles move to a random place
this.dropRateBump = 0.01; // drop rate increase relative to individual particle speed
// 代码省略
gl.uniform1f(program.u_rand_seed, Math.random());
gl.uniform1f(program.u_drop_rate, this.dropRate);
gl.uniform1f(program.u_drop_rate_bump, this.dropRateBump);

Let's first introduce the built-in functions:

  • step(edge, x): If x < edge, return 0.0, otherwise return 1.0.
vec2 seed = (pos + v_tex_pos) * u_rand_seed;

The resulting offset position pos added to the vertex position v_tex_pos , multiplied by a random number between [0, 1) u_rand_seed , to get a random particle position seed .

float drop_rate = u_drop_rate + speed_t * u_drop_rate_bump;

Multiply the particle interpolation percentage speed_t by the custom single particle churn rate u_drop_rate_bump , plus the custom overall churn rate, to get the combined churn rate drop_rate .

float drop = step(1.0 - drop_rate, rand(seed));

If rand(seed) is less than the comprehensive non-churn rate 1.0 - drop_rate , then drop = 0, which means that the particles will not be reset, otherwise the particles will be reset.

What is the way to reset?

The way to reset is this part above:

const vec3 rand_constants = vec3(12.9898, 78.233, 4375.85453);
float rand(const vec2 co) {
    float t = dot(rand_constants.xy, co);
    return fract(sin(t) * (rand_constants.z + t));
}

vec2 seed = (pos + v_tex_pos) * u_rand_seed;
vec2 random_pos = vec2(
    rand(seed + 1.3),
    rand(seed + 2.1));

This is mainly to generate pseudo-random numbers as mentioned in the original text. As for why such a calculation method is used, it is necessary to work hard on the mathematical side.

References


XXHolic
363 声望1.1k 粉丝

[链接]