js粒子漩涡

<!doctype html>
<html>
	<head>
		<meta charset="utf-8">
		<title>漩涡粒子</title>
		<style>
			html,
			body {
				margin: 0px;
				width: 100%;
				height: 100%;
				overflow: hidden;
				background: #000;
			}
			#canvas {
				position: absolute;
				width: 100%;
				height: 100%;
			}
		</style>
	</head>
	<body>
		<canvas id="canvas"></canvas>
		<script>
			function project3D(x, y, z, vars) {
				var p, d;
				x -= vars.camX;
				y -= vars.camY - 8;
				z -= vars.camZ;
				p = Math.atan2(x, z);
				d = Math.sqrt(x * x + z * z);
				x = Math.sin(p - vars.yaw) * d;
				z = Math.cos(p - vars.yaw) * d;
				p = Math.atan2(y, z);
				d = Math.sqrt(y * y + z * z);
				y = Math.sin(p - vars.pitch) * d;
				z = Math.cos(p - vars.pitch) * d;
				var rx1 = -1000;
				var ry1 = 1;
				var rx2 = 1000;
				var ry2 = 1;
				var rx3 = 0;
				var ry3 = 0;
				var rx4 = x;
				var ry4 = z;
				var uc = (ry4 - ry3) * (rx2 - rx1) - (rx4 - rx3) * (ry2 - ry1);
				var ua = ((rx4 - rx3) * (ry1 - ry3) - (ry4 - ry3) * (rx1 - rx3)) / uc;
				var ub = ((rx2 - rx1) * (ry1 - ry3) - (ry2 - ry1) * (rx1 - rx3)) / uc;
				if (!z) z = 0.000000001;
				if (ua > 0 && ua < 1 && ub > 0 && ub < 1) {
					return {
						x: vars.cx + (rx1 + ua * (rx2 - rx1)) * vars.scale,
						y: vars.cy + y / z * vars.scale,
						d: (x * x + y * y + z * z)
					};
				} else {
					return {
						d: -1
					};
				}
			}
			function elevation(x, y, z) {
				var dist = Math.sqrt(x * x + y * y + z * z);
				if (dist && z / dist >= -1 && z / dist <= 1) return Math.acos(z / dist);
				return 0.00000001;
			}
			function rgb(col) {
				col += 0.000001;
				var r = parseInt((0.5 + Math.sin(col) * 0.5) * 16);
				var g = parseInt((0.5 + Math.cos(col) * 0.5) * 16);
				var b = parseInt((0.5 - Math.sin(col) * 0.5) * 16);
				return "#" + r.toString(16) + g.toString(16) + b.toString(16);
			}
			function interpolateColors(RGB1, RGB2, degree) {
				var w2 = degree;
				var w1 = 1 - w2;
				return [w1 * RGB1[0] + w2 * RGB2[0], w1 * RGB1[1] + w2 * RGB2[1], w1 * RGB1[2] + w2 * RGB2[2]];
			}
			function rgbArray(col) {
				col += 0.000001;
				var r = parseInt((0.5 + Math.sin(col) * 0.5) * 256);
				var g = parseInt((0.5 + Math.cos(col) * 0.5) * 256);
				var b = parseInt((0.5 - Math.sin(col) * 0.5) * 256);
				return [r, g, b];
			}
			function colorString(arr) {
				var r = parseInt(arr[0]);
				var g = parseInt(arr[1]);
				var b = parseInt(arr[2]);
				return "#" + ("0" + r.toString(16)).slice(-2) + ("0" + g.toString(16)).slice(-2) + ("0" + b.toString(16)).slice(-
					2);
			}
			function process(vars) {
				if (vars.points.length < vars.initParticles)
					for (var i = 0; i < 5; ++i) spawnParticle(vars);
				var p, d, t;
				p = Math.atan2(vars.camX, vars.camZ);
				d = Math.sqrt(vars.camX * vars.camX + vars.camZ * vars.camZ);
				d -= Math.sin(vars.frameNo / 80) / 25;
				t = Math.cos(vars.frameNo / 300) / 165;
				vars.camX = Math.sin(p + t) * d;
				vars.camZ = Math.cos(p + t) * d;
				vars.camY = -Math.sin(vars.frameNo / 220) * 15;
				vars.yaw = Math.PI + p + t;
				vars.pitch = elevation(vars.camX, vars.camZ, vars.camY) - Math.PI / 2;
				var t;
				for (var i = 0; i < vars.points.length; ++i) {
					x = vars.points[i].x;
					y = vars.points[i].y;
					z = vars.points[i].z;
					d = Math.sqrt(x * x + z * z) / 1.0075;
					t = .1 / (1 + d * d / 5);
					p = Math.atan2(x, z) + t;
					vars.points[i].x = Math.sin(p) * d;
					vars.points[i].z = Math.cos(p) * d;
					vars.points[i].y += vars.points[i].vy * t * ((Math.sqrt(vars.distributionRadius) - d) * 2);
					if (vars.points[i].y > vars.vortexHeight / 2 || d < .25) {
						vars.points.splice(i, 1);
						spawnParticle(vars);
					}
				}
			}
			function drawFloor(vars) {
				var x, y, z, d, point, a;
				for (var i = -25; i <= 25; i += 1) {
					for (var j = -25; j <= 25; j += 1) {
						x = i * 2;
						z = j * 2;
						y = vars.floor;
						d = Math.sqrt(x * x + z * z);
						point = project3D(x, y - d * d / 85, z, vars);
						if (point.d != -1) {
							size = 1 + 15000 / (1 + point.d);
							a = 0.15 - Math.pow(d / 50, 4) * 0.15;
							if (a > 0) {
								vars.ctx.fillStyle = colorString(interpolateColors(rgbArray(d / 26 - vars.frameNo / 40), [0, 128,
									32
								], .5 + Math.sin(d / 6 - vars.frameNo / 8) / 2));
								vars.ctx.globalAlpha = a;
								vars.ctx.fillRect(point.x - size / 2, point.y - size / 2, size, size);
							}
						}
					}
				}
				vars.ctx.fillStyle = "#82f";
				for (var i = -25; i <= 25; i += 1) {
					for (var j = -25; j <= 25; j += 1) {
						x = i * 2;
						z = j * 2;
						y = -vars.floor;
						d = Math.sqrt(x * x + z * z);
						point = project3D(x, y + d * d / 85, z, vars);
						if (point.d != -1) {
							size = 1 + 15000 / (1 + point.d);
							a = 0.15 - Math.pow(d / 50, 4) * 0.15;
							if (a > 0) {
								vars.ctx.fillStyle = colorString(interpolateColors(rgbArray(-d / 26 - vars.frameNo / 40), [32, 0,
									128
								], .5 + Math.sin(-d / 6 - vars.frameNo / 8) / 2));
								vars.ctx.globalAlpha = a;
								vars.ctx.fillRect(point.x - size / 2, point.y - size / 2, size, size);
							}
						}
					}
				}
			}
			function sortFunction(a, b) {
				return b.dist - a.dist;
			}
			function draw(vars) {
				vars.ctx.globalAlpha = .15;
				vars.ctx.fillStyle = "#000";
				vars.ctx.fillRect(0, 0, canvas.width, canvas.height);
				drawFloor(vars);
				var point, x, y, z, a;
				for (var i = 0; i < vars.points.length; ++i) {
					x = vars.points[i].x;
					y = vars.points[i].y;
					z = vars.points[i].z;
					point = project3D(x, y, z, vars);
					if (point.d != -1) {
						vars.points[i].dist = point.d;
						size = 1 + vars.points[i].radius / (1 + point.d);
						d = Math.abs(vars.points[i].y);
						a = .8 - Math.pow(d / (vars.vortexHeight / 2), 1000) * .8;
						vars.ctx.globalAlpha = a >= 0 && a <= 1 ? a : 0;
						vars.ctx.fillStyle = rgb(vars.points[i].color);
						if (point.x > -1 && point.x < vars.canvas.width && point.y > -1 && point.y < vars.canvas.height) vars.ctx
							.fillRect(point.x - size / 2, point.y - size / 2, size, size);
					}
				}
				vars.points.sort(sortFunction);
			}
			function spawnParticle(vars) {
				var p, ls;
				pt = {};
				p = Math.PI * 2 * Math.random();
				ls = Math.sqrt(Math.random() * vars.distributionRadius);
				pt.x = Math.sin(p) * ls;
				pt.y = -vars.vortexHeight / 2;
				pt.vy = vars.initV / 20 + Math.random() * vars.initV;
				pt.z = Math.cos(p) * ls;
				pt.radius = 200 + 800 * Math.random();
				pt.color = pt.radius / 1000 + vars.frameNo / 250;
				vars.points.push(pt);
			}
			function frame(vars) {
				if (vars === undefined) {
					var vars = {};
					vars.canvas = document.querySelector("canvas");
					vars.ctx = vars.canvas.getContext("2d");
					vars.canvas.width = document.body.clientWidth;
					vars.canvas.height = document.body.clientHeight;
					window.addEventListener("resize", function() {
						vars.canvas.width = document.body.clientWidth;
						vars.canvas.height = document.body.clientHeight;
						vars.cx = vars.canvas.width / 2;
						vars.cy = vars.canvas.height / 2;
					}, true);
					vars.frameNo = 0;
					vars.camX = 0;
					vars.camY = 0;
					vars.camZ = -14;
					vars.pitch = elevation(vars.camX, vars.camZ, vars.camY) - Math.PI / 2;
					vars.yaw = 0;
					vars.cx = vars.canvas.width / 2;
					vars.cy = vars.canvas.height / 2;
					vars.bounding = 10;
					vars.scale = 500;
					vars.floor = 26.5;
					vars.points = [];
					vars.initParticles = 700;
					vars.initV = .01;
					vars.distributionRadius = 800;
					vars.vortexHeight = 25;
				}
				vars.frameNo++;
				requestAnimationFrame(function() {
					frame(vars);
				});
				process(vars);
				draw(vars);
			}
			frame();
		</script>
	</body>
</html>

效果如图:
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
这个特效的实现需要使用粒子系统,以下是一个简单的爱心粒子漩涡特效代码示例: ```csharp using UnityEngine; public class HeartParticle : MonoBehaviour { public ParticleSystem particleSystem; public int particleCount = 100; public float radius = 5f; public float speed = 1f; private ParticleSystem.Particle[] particles; void Start() { particles = new ParticleSystem.Particle[particleCount]; particleSystem.Emit(particleCount); particleSystem.GetParticles(particles); for (int i = 0; i < particleCount; i++) { float angle = Random.Range(0f, Mathf.PI * 2f); float distance = Random.Range(0f, radius); Vector3 position = new Vector3(Mathf.Cos(angle) * distance, Mathf.Sin(angle) * distance, 0f); particles[i].position = position; particles[i].startSize = Random.Range(0.1f, 0.3f); particles[i].startColor = new Color(Random.Range(0.8f, 1f), Random.Range(0.2f, 0.5f), Random.Range(0.2f, 0.5f), 1f); } particleSystem.SetParticles(particles, particleCount); } void Update() { for (int i = 0; i < particleCount; i++) { float angle = Mathf.Atan2(particles[i].position.y, particles[i].position.x) + Time.deltaTime * speed; float distance = particles[i].position.magnitude; Vector3 position = new Vector3(Mathf.Cos(angle) * distance, Mathf.Sin(angle) * distance, 0f); particles[i].position = position; } particleSystem.SetParticles(particles, particleCount); } } ``` 这个代码会在场景中生成一个粒子系统,包含指定数量的粒子,每个粒子的位置和颜色都是随机生成的。然后在 Update 函数中,根据粒子当前的位置和速度计算出下一帧的位置,并更新粒子系统。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

风筱默染

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

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

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

打赏作者

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

抵扣说明:

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

余额充值