风场可视化:随机重置
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.
在绘制轨迹的效果中,过一段时间就会发现,最后只剩下固定的几条轨迹,原文中也提到了这种现象,也提供了解决思路,个人还是想结合源码再看看。
随着时间推移,有些粒子产生的偏移超过了范围就会消失,所以需要随机重置消失的风粒子。
需要考虑的问题有:
- 什么时候重置?
- 重置的判断条件是什么?
- 重置的方式是什么?
什么时候重置?
在绘制轨迹中,我们知道了产生的偏移是在最后更新粒子纹理信息阶段,这个时机判断保留新的粒子状态还是重置比较合适。
重置的判断条件是什么?
相关的主要逻辑如下:
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));
这个主要就是原文中所说生成伪随机数。至于为什么用这样的计算方式,需要在数学方面下功夫。
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK