绚烂旋涡
本帖最后由 马黑黑 于 2022-8-20 20:07 编辑 <br /><br /><style>#papa { left: -342px; width: 1280px; height: 768px; box-shadow: 3px 3px 20px #000; background: #000; position: relative; z-index: 8; }
#canvas { position: absolute; width: 100%; height: 100%; }
#disc { position: absolute; width: 40px; height: 40px; left: 10px; top: 10px; background: conic-gradient(red,orange,yellow,green,teal,blue,purple); mask: radial-gradient(transparent 4px,red 0); -webkit-mask: radial-gradient(transparent 4px,red 0); border-radius: 50%; cursor: pointer; z-index: 10; animation: rot 2s linear infinite; }
#lrcbox { position: absolute; left: 60px; top: 10px;font: bold 22px / 40px sans-serif; color: hsla(50, 100%, 50%, .45); text-shadow: 2px 2px 4px #666; user-select: none; z-index: 9;}
@keyframes rot { to { transform: rotate(360deg); } }
</style>
</head>
<body>
<div id="papa">
<span id="lrcbox">绚烂旋涡</span>
<span id="disc"></span>
<canvas id="canvas" width="1280" height="768"></canvas>
</div>
<script>
let aud = new Audio();
aud.src = 'https://music.163.com/song/media/outer/url?id=1970109180.mp3';
aud.loop = true;
aud.autoplay = true;
disc.style.animationPlayState = aud.paused ? 'paused' : 'running';
disc.onclick = () => aud.paused ? aud.play() : aud.pause();
aud.addEventListener('playing', () => disc.style.animationPlayState = 'running');
aud.addEventListener('pause', () => disc.style.animationPlayState = 'paused');
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 + w2 * RGB2, w1 * RGB1 + w2 * RGB2, w1 * RGB1 + w2 * RGB2]
}
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
}
function colorString(arr) {
var r = parseInt(arr);
var g = parseInt(arr);
var b = parseInt(arr);
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 j = 0; j < vars.points.length; ++j) {
x = vars.points.x;
y = vars.points.y;
z = vars.points.z;
d = Math.sqrt(x * x + z * z) / 1.0075;
t = .1 / (1 + d * d / 5);
p = Math.atan2(x, z) + t;
vars.points.x = Math.sin(p) * d;
vars.points.z = Math.cos(p) * d;
vars.points.y += vars.points.vy * t * ((Math.sqrt(vars.distributionRadius) - d) * 2);
if (vars.points.y > vars.vortexHeight / 2 || d < .25) {
vars.points.splice(j, 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), , .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), , .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 j = 0; j < vars.points.length; ++j) {
x = vars.points.x;
y = vars.points.y;
z = vars.points.z;
point = project3D(x, y, z, vars);
if (point.d != -1) {
vars.points.dist = point.d;
size = 1 + vars.points.radius / (1 + point.d);
d = Math.abs(vars.points.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.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 = papa.clientWidth;
vars.canvas.height = papa.clientHeight;
window.addEventListener("resize", function() {
vars.canvas.width = papa.clientWidth;
vars.canvas.height = papa.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 = 1000;
vars.initV = .01;
vars.distributionRadius = 800;
vars.vortexHeight = 25
}
vars.frameNo++;
requestAnimationFrame(function() {
frame(vars);
});
process(vars);
draw(vars)
}
frame();
</script>
等待漩涡出现……{:4_203:} 参考代码(全)
<style>
#papa { left: -342px; width: 1280px; height: 768px; box-shadow: 3px 3px 20px #000; background: #000; position: relative; z-index: 8; }
#canvas { position: absolute; width: 100%; height: 100%; }
#disc { position: absolute; width: 40px; height: 40px; left: 10px; top: 10px; background: conic-gradient(red,orange,yellow,green,teal,blue,purple); mask: radial-gradient(transparent 4px,red 0); -webkit-mask: radial-gradient(transparent 4px,red 0); border-radius: 50%; cursor: pointer; z-index: 10; animation: rot 2s linear infinite; }
#lrcbox { position: absolute; left: 60px; top: 10px;font: bold 22px / 40px sans-serif; color: hsla(50, 100%, 50%, .45); text-shadow: 2px 2px 4px #666; user-select: none; z-index: 9;}
@keyframes rot { to { transform: rotate(360deg); } }
</style>
</head>
<body>
<div id="papa">
<span id="lrcbox">绚烂旋涡</span>
<span id="disc"></span>
<canvas id="canvas" width="1280" height="768"></canvas>
</div>
<script>
let aud = new Audio();
aud.src = 'https://music.163.com/song/media/outer/url?id=1970109180.mp3';
aud.loop = true;
aud.autoplay = true;
disc.style.animationPlayState = aud.paused ? 'paused' : 'running';
disc.onclick = () => aud.paused ? aud.play() : aud.pause();
aud.addEventListener('playing', () => disc.style.animationPlayState = 'running');
aud.addEventListener('pause', () => disc.style.animationPlayState = 'paused');
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 + w2 * RGB2, w1 * RGB1 + w2 * RGB2, w1 * RGB1 + w2 * RGB2]
}
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
}
function colorString(arr) {
var r = parseInt(arr);
var g = parseInt(arr);
var b = parseInt(arr);
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 j = 0; j < vars.points.length; ++j) {
x = vars.points.x;
y = vars.points.y;
z = vars.points.z;
d = Math.sqrt(x * x + z * z) / 1.0075;
t = .1 / (1 + d * d / 5);
p = Math.atan2(x, z) + t;
vars.points.x = Math.sin(p) * d;
vars.points.z = Math.cos(p) * d;
vars.points.y += vars.points.vy * t * ((Math.sqrt(vars.distributionRadius) - d) * 2);
if (vars.points.y > vars.vortexHeight / 2 || d < .25) {
vars.points.splice(j, 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), , .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), , .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 j = 0; j < vars.points.length; ++j) {
x = vars.points.x;
y = vars.points.y;
z = vars.points.z;
point = project3D(x, y, z, vars);
if (point.d != -1) {
vars.points.dist = point.d;
size = 1 + vars.points.radius / (1 + point.d);
d = Math.abs(vars.points.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.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 = papa.clientWidth;
vars.canvas.height = papa.clientHeight;
window.addEventListener("resize", function() {
vars.canvas.width = papa.clientWidth;
vars.canvas.height = papa.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 = 1000;
vars.initV = .01;
vars.distributionRadius = 800;
vars.vortexHeight = 25
}
vars.frameNo++;
requestAnimationFrame(function() {
frame(vars);
});
process(vars);
draw(vars)
}
frame();
</script>
粒子特效部分修改自开源代码 千羽 发表于 2022-8-20 20:07
等待漩涡出现……
前面我有了压缩代码,论坛不支持,现在用回全码,可以了 持续变幻的漩涡炫目靓丽,效果太好了{:4_187:} 马黑黑 发表于 2022-8-20 20:09
前面我有了压缩代码,论坛不支持,现在用回全码,可以了
祝贺下{:4_187:}{:4_199:} 这效果太炫了,如梦似幻,粒子龙卷风啊{:4_199:} 看得如在梦中,代码真是太强大了{:4_199:} 红影 发表于 2022-8-20 20:15
看得如在梦中,代码真是太强大了
实现机制很复杂 看得舍不得移开眼睛,这样的场景只有梦里才会出现吧{:4_187:} 千羽 发表于 2022-8-20 20:12
持续变幻的漩涡炫目靓丽,效果太好了
这个效果确实惊艳 红影 发表于 2022-8-20 20:15
这效果太炫了,如梦似幻,粒子龙卷风啊
是粒子风的一种形态 马黑黑 发表于 2022-8-20 20:17
这个效果确实惊艳
嗯,{:5_116:} 千羽 发表于 2022-8-20 20:12
祝贺下
用了金笔格式化一下代码即可 马黑黑 发表于 2022-8-20 20:18
用了金笔格式化一下代码即可
黑黑老师棒棒哒{:4_187:} 千羽 发表于 2022-8-20 20:18
嗯,
H5之所以完全不要Flash,原因之一是因为Flash能做的,H5也能做。当然,主要是Flash解决不了安全隐患,所以H5没有给它留下一席之地。 队长还没来,俺越权亮起来。实在是太喜欢这个效果了{:4_199:} 千羽 发表于 2022-8-20 20:19
黑黑老师棒棒哒
是金笔棒 红影 发表于 2022-8-20 20:16
看得舍不得移开眼睛,这样的场景只有梦里才会出现吧
嗯,梦里会有