WebGl/Three 粒子系统 人物破碎及还原运动

粒子

首先,加载模型,这是万千粒子的前身,模型对象由很多面构成,这些面又是由各个点构成的,所以可以将模型的几何体对象geometry赋给粒子对象,粒子物体用Points方式渲染

			bloader.load("obj/female02/Female02_bin.js", function (geometry) {
				// createMesh创建点对象
				createMesh(geometry, scene, 4.05, -1000, -350, 0, 0xffdd44, true);
			});

封装每个粒子模型的数据,结构有 Mesh、顶点数据、缓存顶点、顶点数量、到达地面和原始的顶点数量、速度、运动方向、是否运动以及何时运动等

			meshes.push(
				{
					mesh: mesh,
					vertices: geometry.vertices,
					vertices_tmp: vertices_tmp, // 缓存
					vl: vl, // 物体的顶点数量
					down: 0, // 顶点 到达地面的个数
					up: 0, // 顶点 到达原来位置的个数
					direction: 0, // 运动方向
					speed: 50, // 速度
					delay: Math.floor(200 + 200 * Math.random()), // 速度线性值
					started: false, // 是否在运动
					start: Math.floor(100 + 200 * Math.random()), // 100 ,300  物体在原始 或 地面 的停留时间
					dynamic: dynamic // 是否可以运动
				});

开始动画

注意一点,需要计算两帧之间经过的时间。这段时间delta对于确保流畅和一致的运动至关重要,无论程序运行的系统性能如何。基本上,它有助于使动画和运动独立于帧速率,从而确保在不同设备上显示平滑。也就是要根据帧率不同对运动速度进行线性变换,而不是每帧进来无差异帧运动,比如正常1s运行40帧,1帧运动1m,当性能瓶颈时,1s运行了20帧,同样1帧运动1m时,动画就会较之前慢,突变的感觉会很不自然

		function render() {

			// 计算每一帧的时间
			delta = clock.getDelta();
			delta = delta < 2 ? delta : 2; // 执行速率

			parent.rotation.y += -0.02 * delta;

            ......

		}

向下运动,循环点模型的每个点,对顶点y分量受控于速度和帧率递减,x和z分量左右和前后自然运动

一个粒子y值降为了0,即到达地面,记录一个顶点完成了向下运动的个数+1

			for (var j = 0; j < meshes.length; j++) {

				data = meshes[j];
				mesh = data.mesh;

				vertices = data.vertices;
				vertices_tmp = data.vertices_tmp;
				vl = data.vl;

				// 最开始的时候,没有移动,设置移动,向下
				if (data.start > 0) {
					data.start -= 1;
				} else {
					// 开始动画
					if (!data.started) {
						data.direction = -1;
						data.started = true;
					}
				}

				for (i = 0; i < vl; i++) {

					p = vertices[i];
					vt = vertices_tmp[i]; // 缓存的顶点:x y z down up

					if (data.direction < 0) {
						if (p.y > 0) { // 降到0截止
							p.x += 1.5 * (0.50 - Math.random()) * data.speed * delta;
							// 向下的概念明显大于向上的概率,所以整个人物总有一个时刻是向下的。
							p.y += 3.0 * (0.05 - Math.random()) * data.speed * delta;
							p.z += 1.5 * (0.50 - Math.random()) * data.speed * delta;

						} else {
							if (!vt[3]) { // down为 0 表示向下
								vt[3] = 1;
								data.down += 1; // 记录一下顶点到达地面的个数
							}
						}
					};

				}

}

直到到达地面的数量等于顶点的数量,停止向下运动状态, 改粒子状态为向上还原运动

				if (data.down === vl) { // 下降 顶点运动到地面的数量 == 顶点总数 停止向下的状态
					if (data.delay === 0) {
						data.direction = 1; // 下次向上运动
						data.speed = 10;
						data.down = 0;
						data.delay = 300;

						for (i = 0; i < vl; i++) {
							vertices_tmp[i][3] = 0; // 缓存的 down归0
						}

					} else {
						data.delay -= 1;
					}
				}

向上还原运动,将地面的每个粒子还原到初始的位置,需要每帧计算点坐标与其原始坐标的距离,这里误差算到1以内,也就是两者距离小于1时,默认当前粒子还原到了初始位置,记录完成运动的粒子数。

计算距离的方法  开根号 (newX - oldX)^2 + (newY - oldY) ^2 + (newZ - oldZ)^2

					if (data.direction > 0) {
						// 每帧计算顶点 当前坐标与原始坐标的距离
						d = Math.abs(p.x - vt[0]) + Math.abs(p.y - vt[1]) + Math.abs(p.z - vt[2]);

						if (d > 1) { // 线性递减
							p.x += -(p.x - vt[0]) / d * data.speed * delta * (0.85 - Math.random());
							p.y += -(p.y - vt[1]) / d * data.speed * delta * (1.5 + Math.random());
							p.z += -(p.z - vt[2]) / d * data.speed * delta * (0.85 - Math.random());

						} else { // 小于1 认为运动到了原始位置
							if (!vt[4]) {
								vt[4] = 1;
								data.up += 1;
							}
						}
					}

一个粒子对象完成还原运动,再次改为下降,往复循环

				if (data.up === vl) { // 上升 顶点运动到原来位置的数量 == 顶点总数 停止向上的状态
					if (data.delay === 0) {
						data.direction = -1; // 下次向下运动
						data.speed = 10;
						data.up = 0;
						data.delay = 300;

						for (i = 0; i < vl; i++) {
							vertices_tmp[i][4] = 0;
						}

					} else {
						data.delay -= 1;
					}
				}

 注意,每次改变geometry的顶点坐标信息,需要指明强制更新,否则GPU执行的还是旧的顶点坐标

mesh.geometry.verticesNeedUpdate = true;

  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山楂树の

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值