three.js象素地球3s后爆炸

<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>象素地球爆炸</title>
<style>
body {
margin: 0
overflow: hidden
background-color:
color: white
font-family: Arial, sans-serif
}
canvas {
display: block
}
position: absolute
top: 10px
width: 100%
text-align: center
z-index: 100
display: block
font-size: 1.5em
}
</style>
</head>
<body>
<div id="info">象素粒子组成地球...</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script>
// --- 核心变量 ---
let scene, camera, renderer
let particles
let positions
let velocities
let targetPositions
const particleCount = 15000
let isExploded = false
// --- 初始化 ---
function init() {
// 场景
scene = new THREE.Scene()
// 相机
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
camera.position.z = 150
// 渲染器
renderer = new THREE.WebGLRenderer({ antialias: true })
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.appendChild(renderer.domElement)
// --- 创建粒子 ---
const geometry = new THREE.BufferGeometry()
positions = new Float32Array(particleCount * 3)
velocities = new Float32Array(particleCount * 3)
targetPositions = new Float32Array(particleCount * 3)
// 创建一个球体几何来获取顶点作为粒子的目标位置
const earthRadius = 60
const sphereGeometry = new THREE.SphereGeometry(earthRadius, 64, 64)
const earthVertices = sphereGeometry.attributes.position.array
for (let i = 0
const i3 = i * 3
// 初始位置:随机分布在一个更大的球体中
const theta = Math.random() * Math.PI * 2
const phi = Math.acos((Math.random() * 2) - 1)
const r = Math.random() * 500 + 200
positions[i3] = r * Math.sin(phi) * Math.cos(theta)
positions[i3 + 1] = r * Math.sin(phi) * Math.sin(theta)
positions[i3 + 2] = r * Math.cos(phi)
// 目标位置:从地球模型的顶点中随机选取
const randomVertexIndex = Math.floor(Math.random() * (earthVertices.length / 3)) * 3
targetPositions[i3] = earthVertices[randomVertexIndex]
targetPositions[i3 + 1] = earthVertices[randomVertexIndex + 1]
targetPositions[i3 + 2] = earthVertices[randomVertexIndex + 2]
// 爆炸速度:随机方向和大小
const explosionStrength = (Math.random() - 0.5) * 4
velocities[i3] = (Math.random() - 0.5) * explosionStrength
velocities[i3 + 1] = (Math.random() - 0.5) * explosionStrength
velocities[i3 + 2] = (Math.random() - 0.5) * explosionStrength
}
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3))
const material = new THREE.PointsMaterial({
color: 0x4169E1, // 皇家蓝
size: 1.5,
blending: THREE.AdditiveBlending,
transparent: true,
opacity: 0.8
})
particles = new THREE.Points(geometry, material)
scene.add(particles)
// --- 设置3秒后爆炸 ---
setTimeout(() => {
isExploded = true
document.getElementById('info').textContent = '爆炸!'
}, 3000)
// 监听窗口大小变化
window.addEventListener('resize', onWindowResize, false)
}
// --- 动画循环 ---
function animate() {
requestAnimationFrame(animate)
const positionsAttribute = particles.geometry.attributes.position
const material = particles.material
if (!isExploded) {
// 聚合阶段:粒子向目标位置移动
for (let i = 0
const i3 = i * 3
positionsAttribute.array[i3] += (targetPositions[i3] - positionsAttribute.array[i3]) * 0.05
positionsAttribute.array[i3 + 1] += (targetPositions[i3 + 1] - positionsAttribute.array[i3 + 1]) * 0.05
positionsAttribute.array[i3 + 2] += (targetPositions[i3 + 2] - positionsAttribute.array[i3 + 2]) * 0.05
}
particles.rotation.y += 0.001
} else {
// 爆炸阶段:粒子根据速度向外移动
for (let i = 0
const i3 = i * 3
positionsAttribute.array[i3] += velocities[i3]
positionsAttribute.array[i3 + 1] += velocities[i3 + 1]
positionsAttribute.array[i3 + 2] += velocities[i3 + 2]
}
// 粒子逐渐消失
if(material.opacity > 0) {
material.opacity -= 0.005
}
}
positionsAttribute.needsUpdate = true
renderer.render(scene, camera)
}
// --- 窗口大小调整 ---
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight
camera.updateProjectionMatrix()
renderer.setSize(window.innerWidth, window.innerHeight)
}
// --- 启动 ---
init()
animate()
</script>
</body>
</html>