单个球体

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
body {
background-color: black;
overflow: hidden;
}
canvas {
display: block;
margin: auto;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
</style>
</head>
<body>
<canvas id="canvas1" width="500" height="500"></canvas>
<script>
var canvas = document.querySelector("canvas");
var ctx = canvas.getContext("2d");
var cw = canvas.width,
cx = cw / 2;
var ch = canvas.height,
cy = ch / 2;
var balls = [];
var fl = 250;
function spherePointPicking(R) {
var u1 = Math.random();
var u2 = Math.random();
var s = Math.acos(2 * u1 - 1) - Math.PI / 2;
var t = 2 * Math.PI * u2;
return {
x: R * Math.cos(s) * Math.cos(t),
y: R * Math.cos(s) * Math.sin(t),
z: R * Math.sin(s),
};
}
function oGrd(r, h) {
grd = ctx.createRadialGradient(0, 0, 0, 0, 0, r);
grd.addColorStop(0, "hsla(" + h + ",95%,95%, 1)");
grd.addColorStop(0.4, "hsla(" + h + ",95%,45%,.5)");
grd.addColorStop(1, "hsla(" + h + ", 95%, 45%, 0.1)");
return grd;
}
function Ball(R) {
this.r = 3;
this.R = R;
this.pos = spherePointPicking(this.R);
this.x = this.pos.x + cx;
this.y = this.pos.y + cy;
this.scale = { x: 1, y: 1 };
this.draw3D = function () {
if (this.pos.z > -fl) {
var scale = fl / (fl - this.pos.z);
this.scale = { x: scale, y: scale };
this.x = cx + this.pos.x * scale;
this.y = cy + this.pos.y * scale;
this.visible = true;
} else {
this.visible = false;
}
};
this.draw2D = function () {
ctx.save();
ctx.translate(this.x, this.y);
ctx.scale(this.scale.x, this.scale.y);
ctx.beginPath();
ctx.arc(0, 0, this.r, 0, 2 * Math.PI);
ctx.fillStyle = oGrd(this.r, 210);
ctx.fill();
ctx.restore();
};
this.rotateX = function (angle) {
var cos = Math.cos(angle);
var sin = Math.sin(angle);
var y1 = this.pos.y * cos - this.pos.z * sin;
var z1 = this.pos.z * cos + this.pos.y * sin;
this.pos.y = y1;
this.pos.z = z1;
};
this.rotateY = function (angle) {
var cos = Math.cos(angle);
var sin = Math.sin(angle);
var x1 = this.pos.x * cos - this.pos.z * sin;
var z1 = this.pos.z * cos + this.pos.x * sin;
this.pos.x = x1;
this.pos.z = z1;
};
}
for (let i = 0; i < 1000; i++) {
balls.push(new Ball(150));
balls.push(new Ball(75));
}
var frames = 0;
var m = { x: 0, y: 0 };
var target = { x: 0, y: 0 };
var speed = 0.0005;
var easing = 0.9;
function Draw() {
window.requestAnimationFrame(Draw);
ctx.clearRect(0, 0, cw, ch);
frames += 0.1;
t = new Date().getTime() / 127;
m.x = cx + Math.cos(t / 43 + Math.cos(t / 47 + frames)) * 50;
m.y = cy + Math.sin(t / 31 + Math.cos(t / 37 + frames)) * 50;
target.x = (m.y - cy) * speed * easing;
target.y = (m.x - cx) * speed * easing;
balls.map((b) => {
b.draw3D();
});
balls.sort((a, b) => {
return a.pos.z - b.pos.z;
});
balls.map((b) => {
b.rotateX(target.x);
b.rotateY(target.y);
if (b.visible) {
b.draw2D();
}
});
}
Draw();
</script>
</body>
</html>
多个球体

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
body {
background-color: black;
overflow: hidden;
}
canvas {
display: block;
margin: auto;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
</style>
</head>
<body>
<canvas id="canvas1" width="1500" height="500"></canvas>
<script>
var canvas = document.querySelector("canvas");
var ctx = canvas.getContext("2d");
var cw = canvas.width,
cx = cw / 2;
var ch = canvas.height,
cy = ch / 2;
const balls = {
balls0: [],
balls1: [],
balls2: [],
balls3: [],
balls4: [],
balls5: [],
};
var fl = 250;
function spherePointPicking(R) {
var u1 = Math.random();
var u2 = Math.random();
var s = Math.acos(2 * u1 - 1) - Math.PI / 2;
var t = 2 * Math.PI * u2;
return {
x: R * Math.cos(s) * Math.cos(t),
y: R * Math.cos(s) * Math.sin(t),
z: R * Math.sin(s),
};
}
function oGrd(r, h) {
grd = ctx.createRadialGradient(0, 0, 0, 0, 0, r);
grd.addColorStop(0, "hsla(" + h + ",95%,95%, 1)");
grd.addColorStop(0.4, "hsla(" + h + ",95%,45%,.5)");
grd.addColorStop(1, "hsla(" + h + ", 95%, 45%, 0.1)");
return grd;
}
function Ball(R, circleX, circleY, color) {
this.r = 3;
this.R = R;
this.pos = spherePointPicking(this.R);
this.x = this.pos.x + circleX;
this.y = this.pos.y + circleY;
this.scale = { x: 1, y: 1 };
this.draw3D = function () {
if (this.pos.z > -fl) {
var scale = fl / (fl - this.pos.z);
this.scale = { x: scale, y: scale };
this.x = circleX + this.pos.x * scale;
this.y = circleY + this.pos.y * scale;
this.visible = true;
} else {
this.visible = false;
}
};
this.draw2D = function () {
ctx.save();
ctx.translate(this.x, this.y);
ctx.scale(this.scale.x, this.scale.y);
ctx.beginPath();
ctx.arc(0, 0, this.r, 0, 2 * Math.PI);
ctx.fillStyle = oGrd(this.r, color);
ctx.fill();
ctx.restore();
};
this.rotateX = function (angle) {
var cos = Math.cos(angle);
var sin = Math.sin(angle);
var y1 = this.pos.y * cos - this.pos.z * sin;
var z1 = this.pos.z * cos + this.pos.y * sin;
this.pos.y = y1;
this.pos.z = z1;
};
this.rotateY = function (angle) {
var cos = Math.cos(angle);
var sin = Math.sin(angle);
var x1 = this.pos.x * cos - this.pos.z * sin;
var z1 = this.pos.z * cos + this.pos.x * sin;
this.pos.x = x1;
this.pos.z = z1;
};
}
for (let i = 0; i < 1000; i++) {
balls.balls0.push(new Ball(150, cx, cy, 210));
balls.balls0.push(new Ball(75, cx, cy, 210));
}
for (let i = 0; i < 800; i++) {
balls.balls1.push(new Ball(100, cx / 2, cy / 2, 225));
balls.balls1.push(new Ball(50, cx / 2, cy / 2, 225));
}
for (let i = 0; i < 300; i++) {
balls.balls2.push(new Ball(75, (cx / 2) * 3, cy / 2, 230));
balls.balls2.push(new Ball(50, (cx / 2) * 3, cy / 2, 230));
}
for (let i = 0; i < 100; i++) {
balls.balls3.push(new Ball(25, (cx / 3) * 4, (cy / 3) * 4, 255));
balls.balls3.push(new Ball(20, (cx / 3) * 4, (cy / 3) * 4, 255));
}
for (let i = 0; i < 600; i++) {
balls.balls4.push(new Ball(90, cx / 4, (cy / 3) * 4, 200));
balls.balls4.push(new Ball(65, cx / 4, (cy / 3) * 4, 200));
}
for (let i = 0; i < 500; i++) {
balls.balls4.push(new Ball(100, (cx / 5) * 9, (cy / 7) * 10, 190));
balls.balls4.push(new Ball(75, (cx / 5) * 9, (cy / 7) * 10, 190));
}
var frames = 0;
var m = { x: 0, y: 0 };
var target = { x: 0, y: 0 };
var speed = 0.0005;
var easing = 0.9;
function Draw() {
window.requestAnimationFrame(Draw);
ctx.clearRect(0, 0, cw, ch);
frames += 0.1;
t = new Date().getTime() / 127;
m.x = cx + Math.cos(t / 43 + Math.cos(t / 47 + frames)) * 50;
m.y = cy + Math.sin(t / 31 + Math.cos(t / 37 + frames)) * 50;
target.x = (m.y - cy) * speed * easing;
target.y = (m.x - cx) * speed * easing;
Object.keys(balls).forEach((item) => {
balls[item].map((b) => {
b.draw3D();
});
balls[item].sort((a, b) => {
return a.pos.z - b.pos.z;
});
const random = Math.random() + 0.5;
console.log("123", random);
balls[item].map((b, index) => {
b.rotateX(target.x * random);
b.rotateY(target.y * random);
if (b.visible) {
b.draw2D();
}
});
});
}
Draw();
</script>
</body>
</html>