0

风场可视化:随机重置

 2 years ago
source link: https://segmentfault.com/a/1190000041572225
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

绘制轨迹的效果中,过一段时间就会发现,最后只剩下固定的几条轨迹,原文中也提到了这种现象,也提供了解决思路,个人还是想结合源码再看看。

随着时间推移,有些粒子产生的偏移超过了范围就会消失,所以需要随机重置消失的风粒子。

需要考虑的问题有:

  • 什么时候重置?
  • 重置的判断条件是什么?
  • 重置的方式是什么?

什么时候重置?

绘制轨迹中,我们知道了产生的偏移是在最后更新粒子纹理信息阶段,这个时机判断保留新的粒子状态还是重置比较合适。

重置的判断条件是什么?

相关的主要逻辑如下:

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);

先介绍一下内置函数:

  • step(edge, x):如果 x < edge ,则返回 0.0 ,否则返回 1.0 。
vec2 seed = (pos + v_tex_pos) * u_rand_seed;

得到的偏移后的位置 pos 加上顶点位置 v_tex_pos ,乘以随机 [0, 1) 之间的随机数 u_rand_seed ,得到一个随机粒子位置 seed

float drop_rate = u_drop_rate + speed_t * u_drop_rate_bump;

粒子插值百分比 speed_t 乘以自定义单个粒子流失率 u_drop_rate_bump ,再加上自定义整体流失率,得到综合流失率 drop_rate

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

如果 rand(seed) 小于综合非流失率 1.0 - drop_rate ,那么 drop = 0 ,表示不会重置粒子,否则就会重置粒子。

重置的方式是什么?

重置的方式就是上面的这部分:

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));

这个主要就是原文中所说生成伪随机数。至于为什么用这样的计算方式,需要在数学方面下功夫。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK