<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>精美3D圣诞树 - 圣诞快乐</title>
<script src="https://cdn.jsdelivr.net/npm/three@0.140.1/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.140.1/examples/js/controls/OrbitControls.js"></script>
<style>
body {
margin: 0;
overflow: hidden;
background-color: #0a1128;
}
#canvas-container {
position: relative;
width: 100%;
height: 100vh;
}
#info {
position: absolute;
top: 20px;
left: 20px;
color: white;
font-family: Arial, sans-serif;
z-index: 10;
background-color: rgba(0, 0, 0, 0.5);
padding: 10px;
border-radius: 5px;
}
#merry-christmas {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: white;
font-family: 'Arial Black', sans-serif;
font-size: 48px;
text-shadow: 0 0 10px #ff0000, 0 0 20px #ff0000, 0 0 30px #ff0000;
opacity: 0;
transition: opacity 1s ease-in-out;
z-index: 5;
pointer-events: none;
}
#santa-btn {
position: absolute;
bottom: 20px;
right: 20px;
padding: 10px 20px;
background-color: #ff0000;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
font-family: Arial, sans-serif;
font-weight: bold;
z-index: 10;
transition: all 0.3s ease;
}
#santa-btn:hover {
background-color: #cc0000;
transform: scale(1.05);
}
</style>
</head>
<body>
<div id="canvas-container">
<canvas id="scene-canvas"></canvas>
<div id="info">
<p>精美3D圣诞树</p>
<p>鼠标拖拽: 旋转视角</p>
<p>滚轮: 缩放</p>
<p>点击装饰球: 点亮特效</p>
</div>
<div id="merry-christmas">MERRY CHRISTMAS!</div>
<button id="santa-btn">召唤圣诞老人</button>
</div>
<script>
// 全局变量
let scene, camera, renderer, controls;
let snowflakes = [];
let ornaments = [];
let lights = [];
let santa = null;
let treeGroup;
let snowTexture;
let isSantaVisible = false;
let mouse = new THREE.Vector2();
let raycaster = new THREE.Raycaster();
// 初始化函数
function init() {
console.log('开始初始化精美3D圣诞树...');
// 创建场景
scene = new THREE.Scene();
scene.background = new THREE.Color(0x0a1128);
// 创建相机
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 5, 15);
// 创建渲染器
const canvas = document.getElementById('scene-canvas');
renderer = new THREE.WebGLRenderer({ canvas: canvas, antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
// 添加轨道控制器
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
controls.screenSpacePanning = false;
controls.maxPolarAngle = Math.PI / 2;
// 创建星空背景
createStarfield();
// 添加高级灯光
addAdvancedLights();
// 创建雪地
createSnowyGround();
// 创建圣诞树组
treeGroup = new THREE.Group();
scene.add(treeGroup);
// 创建精美圣诞树
createEnhancedTree();
// 创建高级雪花系统
createAdvancedSnowflakes();
// 添加事件监听器
window.addEventListener('resize', onWindowResize);
window.addEventListener('click', onClick);
document.getElementById('santa-btn').addEventListener('click', toggleSanta);
// 开始动画循环
animate();
console.log('初始化完成,开始渲染...');
}
// 创建星空背景
function createStarfield() {
const starsGeometry = new THREE.BufferGeometry();
const starsMaterial = new THREE.PointsMaterial({
color: 0xffffff,
size: 0.05,
transparent: true,
opacity: 0.8
});
const starsVertices = [];
for (let i = 0; i < 5000; i++) {
const x = (Math.random() - 0.5) * 200;
const y = (Math.random() - 0.5) * 200;
const z = (Math.random() - 0.5) * 200;
starsVertices.push(x, y, z);
}
starsGeometry.setAttribute('position', new THREE.Float32BufferAttribute(starsVertices, 3));
const stars = new THREE.Points(starsGeometry, starsMaterial);
scene.add(stars);
}
// 添加高级灯光
function addAdvancedLights() {
// 环境光
const ambientLight = new THREE.AmbientLight(0x404040, 0.4);
scene.add(ambientLight);
// 主方向光(模拟月光)
const moonLight = new THREE.DirectionalLight(0xd0e0ff, 0.6);
moonLight.position.set(5, 15, 7);
moonLight.castShadow = true;
moonLight.shadow.mapSize.width = 2048;
moonLight.shadow.mapSize.height = 2048;
moonLight.shadow.camera.near = 0.5;
moonLight.shadow.camera.far = 50;
scene.add(moonLight);
// 添加一些彩色点光源(模拟远处的灯光)
const colors = [0xff5555, 0x55ff55, 0x5555ff, 0xffff55];
for (let i = 0; i < 8; i++) {
const light = new THREE.PointLight(
colors[Math.floor(Math.random() * colors.length)],
0.3,
20
);
light.position.set(
Math.random() * 40 - 20,
Math.random() * 5 + 2,
Math.random() * 40 - 20
);
scene.add(light);
}
}
// 创建雪地
function createSnowyGround() {
// 雪地平面
const groundGeometry = new THREE.PlaneGeometry(100, 100);
const groundMaterial = new THREE.MeshStandardMaterial({
color: 0xffffff,
roughness: 0.9,
metalness: 0.1,
bumpScale: 0.05
});
const ground = new THREE.Mesh(groundGeometry, groundMaterial);
ground.rotation.x = -Math.PI / 2;
ground.position.y = -0.5;
ground.receiveShadow = true;
scene.add(ground);
// 添加雪堆
for (let i = 0; i < 50; i++) {
const moundGeometry = new THREE.SphereGeometry(
Math.random() * 0.8 + 0.3,
16,
16
);
const moundMaterial = new THREE.MeshStandardMaterial({
color: 0xffffff,
roughness: 0.9,
metalness: 0.05
});
const mound = new THREE.Mesh(moundGeometry, moundMaterial);
mound.position.set(
Math.random() * 80 - 40,
-0.4,
Math.random() * 80 - 40
);
mound.scale.set(
Math.random() * 2 + 1,
Math.random() * 0.5 + 0.3,
Math.random() * 2 + 1
);
mound.castShadow = true;
mound.receiveShadow = true;
scene.add(mound);
}
}
// 创建精美圣诞树
function createEnhancedTree() {
// 树干
const trunkGeometry = new THREE.CylinderGeometry(0.3, 0.5, 1.5, 16);
const trunkMaterial = new THREE.MeshStandardMaterial({
color: 0x8B4513,
roughness: 0.9,
metalness: 0.1
});
const trunk = new THREE.Mesh(trunkGeometry, trunkMaterial);
trunk.position.y = 0.75;
trunk.castShadow = true;
trunk.receiveShadow = true;
treeGroup.add(trunk);
// 树冠(多层圆锥体)
const treeParts = [];
for (let i = 0; i < 6; i++) {
const height = 1 - i * 0.05;
const radius = 3 - i * 0.4;
const coneHeight = 1.8;
const geometry = new THREE.ConeGeometry(radius, coneHeight, 32);
const material = new THREE.MeshStandardMaterial({
color: new THREE.Color(0x006400).offsetHSL(0, 0, i * 0.03),
roughness: 0.8,
metalness: 0.2
});
const part = new THREE.Mesh(geometry, material);
part.position.y = 1.5 + i * (coneHeight * 0.8);
part.castShadow = true;
part.receiveShadow = true;
treeGroup.add(part);
treeParts.push(part);
}
// 树顶星星
const starGeometry = new THREE.IcosahedronGeometry(0.5, 0);
const starMaterial = new THREE.MeshBasicMaterial({
color: 0xffff00,
emissive: 0xffff00,
emissiveIntensity: 0.8
});
const star = new THREE.Mesh(starGeometry, starMaterial);
star.position.y = 10.5;
treeGroup.add(star);
// 添加灯带
addChristmasLights();
// 添加装饰球
addOrnaments();
// 添加礼物盒
addGiftBoxes();
}
// 添加圣诞灯带
function addChristmasLights() {
const lightColors = [0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xff00ff];
for (let i = 0; i < 30; i++) {
const lightGeometry = new THREE.SphereGeometry(0.1, 8, 8);
const lightMaterial = new THREE.MeshBasicMaterial({
color: lightColors[Math.floor(Math.random() * lightColors.length)],
emissive: lightColors[Math.floor(Math.random() * lightColors.length)],
emissiveIntensity: 0.8
});
const light = new THREE.Mesh(lightGeometry, lightMaterial);
// 随机位置,在树的范围内
const angle = Math.random() * Math.PI * 2;
const height = Math.random() * 6 + 2;
const radius = (1 - height / 8) * 2.5;
light.position.set(
Math.cos(angle) * radius,
height,
Math.sin(angle) * radius
);
// 存储灯光数据
const lightData = {
mesh: light,
originalColor: lightMaterial.color.clone(),
pulseSpeed: Math.random() * 0.03 + 0.01,
pulseIntensity: Math.random()
};
treeGroup.add(light);
lights.push(lightData);
}
}
// 添加装饰球
function addOrnaments() {
const colors = [
0xff0000, // 红色
0x0000ff, // 蓝色
0xffff00, // 黄色
0xff00ff, // 粉色
0x00ffff, // 青色
0xffa500, // 橙色
0x9932cc, // 紫色
0xffc0cb // 浅粉色
];
for (let i = 0; i < 40; i++) {
const radius = Math.random() * 0.25 + 0.15;
const geometry = new THREE.SphereGeometry(radius, 16, 16);
const color = colors[Math.floor(Math.random() * colors.length)];
const material = new THREE.MeshStandardMaterial({
color: color,
roughness: 0.2,
metalness: 0.8,
reflectivity: 1.0
});
const ornament = new THREE.Mesh(geometry, material);
// 在树上随机位置
const angle = Math.random() * Math.PI * 2;
const height = Math.random() * 6 + 2;
const radiusFactor = (1 - (height - 2) / 6) * 2.5;
ornament.position.set(
Math.cos(angle) * radiusFactor,
height,
Math.sin(angle) * radiusFactor
);
// 随机旋转
ornament.rotation.x = Math.random() * Math.PI;
ornament.rotation.y = Math.random() * Math.PI;
ornament.castShadow = true;
ornament.receiveShadow = true;
treeGroup.add(ornament);
ornaments.push({
mesh: ornament,
originalColor: material.color.clone(),
pulseIntensity: 0,
pulseSpeed: 0
});
}
}
// 添加礼物盒
function addGiftBoxes() {
const boxColors = [
{ body: 0xff0000, ribbon: 0xffff00 }, // 红色盒子,黄色丝带
{ body: 0x0000ff, ribbon: 0xffffff }, // 蓝色盒子,白色丝带
{ body: 0x00ff00, ribbon: 0xff00ff }, // 绿色盒子,粉色丝带
{ body: 0x9932cc, ribbon: 0x00ffff } // 紫色盒子,青色丝带
];
for (let i = 0; i < 8; i++) {
const boxGroup = new THREE.Group();
// 盒子主体
const size = Math.random() * 0.5 + 0.4;
const boxGeometry = new THREE.BoxGeometry(size, size, size);
const boxColor = boxColors[Math.floor(Math.random() * boxColors.length)];
const boxMaterial = new THREE.MeshStandardMaterial({
color: boxColor.body,
roughness: 0.7,
metalness: 0.2
});
const box = new THREE.Mesh(boxGeometry, boxMaterial);
box.castShadow = true;
box.receiveShadow = true;
boxGroup.add(box);
// 丝带
const ribbonMaterial = new THREE.MeshStandardMaterial({
color: boxColor.ribbon,
roughness: 0.2,
metalness: 0.8
});
// 横向丝带
const ribbonHGeometry = new THREE.BoxGeometry(size * 1.1, size * 0.1, size * 0.1);
const ribbonH = new THREE.Mesh(ribbonHGeometry, ribbonMaterial);
ribbonH.position.y = size * 0.05;
boxGroup.add(ribbonH);
// 纵向丝带
const ribbonVGeometry = new THREE.BoxGeometry(size * 0.1, size * 1.1, size * 0.1);
const ribbonV = new THREE.Mesh(ribbonVGeometry, ribbonMaterial);
ribbonV.position.x = 0;
ribbonV.position.y = 0;
boxGroup.add(ribbonV);
// 丝带结
const bowGeometry = new THREE.SphereGeometry(size * 0.2, 8, 8);
const bow = new THREE.Mesh(bowGeometry, ribbonMaterial);
bow.position.y = size * 0.55;
boxGroup.add(bow);
// 随机位置(在树的底部周围)
const angle = Math.random() * Math.PI * 2;
const distance = Math.random() * 1.5 + 1.5;
boxGroup.position.set(
Math.cos(angle) * distance,
size * 0.5 - 0.5,
Math.sin(angle) * distance
);
// 随机旋转
boxGroup.rotation.y = Math.random() * Math.PI;
treeGroup.add(boxGroup);
}
}
// 创建高级雪花系统
function createAdvancedSnowflakes() {
// 创建雪花纹理
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.width = 64;
canvas.height = 64;
// 绘制雪花
context.fillStyle = 'white';
context.beginPath();
context.arc(32, 32, 30, 0, Math.PI * 2);
context.fill();
// 创建雪花形状
const createSnowflake = () => {
context.clearRect(0, 0, 64, 64);
context.fillStyle = 'white';
context.strokeStyle = 'white';
context.lineWidth = 2;
// 绘制雪花的基本形状
const centerX = 32;
const centerY = 32;
const size = 20;
// 绘制六条主分支
for (let i = 0; i < 6; i++) {
const angle = (i * Math.PI) / 3;
// 主分支
context.beginPath();
context.moveTo(centerX, centerY);
context.lineTo(
centerX + Math.cos(angle) * size,
centerY + Math.sin(angle) * size
);
context.stroke();
// 侧分支
const sideAngle1 = angle + Math.PI / 6;
const sideAngle2 = angle - Math.PI / 6;
context.beginPath();
context.moveTo(
centerX + Math.cos(angle) * size * 0.5,
centerY + Math.sin(angle) * size * 0.5
);
context.lineTo(
centerX + Math.cos(angle) * size * 0.5 + Math.cos(sideAngle1) * size * 0.3,
centerY + Math.sin(angle) * size * 0.5 + Math.sin(sideAngle1) * size * 0.3
);
context.stroke();
context.beginPath();
context.moveTo(
centerX + Math.cos(angle) * size * 0.5,
centerY + Math.sin(angle) * size * 0.5
);
context.lineTo(
centerX + Math.cos(angle) * size * 0.5 + Math.cos(sideAngle2) * size * 0.3,
centerY + Math.sin(angle) * size * 0.5 + Math.sin(sideAngle2) * size * 0.3
);
context.stroke();
}
};
createSnowflake();
const snowTexture = new THREE.CanvasTexture(canvas);
snowTexture.magFilter = THREE.LinearFilter;
snowTexture.minFilter = THREE.LinearFilter;
// 创建雪花粒子
const snowflakesGeometry = new THREE.BufferGeometry();
const snowflakesCount = 1000;
const positions = new Float32Array(snowflakesCount * 3);
const scales = new Float32Array(snowflakesCount);
const velocities = new Float32Array(snowflakesCount * 3);
const rotations = new Float32Array(snowflakesCount);
const rotationSpeeds = new Float32Array(snowflakesCount);
for (let i = 0; i < snowflakesCount; i++) {
// 位置
positions[i * 3] = (Math.random() - 0.5) * 100;
positions[i * 3 + 1] = Math.random() * 50;
positions[i * 3 + 2] = (Math.random() - 0.5) * 100;
// 缩放
scales[i] = Math.random() * 0.5 + 0.1;
// 速度
velocities[i * 3] = (Math.random() - 0.5) * 0.05;
velocities[i * 3 + 1] = -(Math.random() * 0.05 + 0.01);
velocities[i * 3 + 2] = (Math.random() - 0.5) * 0.05;
// 旋转
rotations[i] = Math.random() * Math.PI * 2;
rotationSpeeds[i] = (Math.random() - 0.5) * 0.02;
}
snowflakesGeometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
snowflakesGeometry.setAttribute('scale', new THREE.BufferAttribute(scales, 1));
snowflakesGeometry.setAttribute('velocity', new THREE.BufferAttribute(velocities, 3));
snowflakesGeometry.setAttribute('rotation', new THREE.BufferAttribute(rotations, 1));
snowflakesGeometry.setAttribute('rotationSpeed', new THREE.BufferAttribute(rotationSpeeds, 1));
// 创建雪花材质
const snowflakesMaterial = new THREE.PointsMaterial({
size: 0.5,
map: snowTexture,
transparent: true,
opacity: 0.8,
blending: THREE.AdditiveBlending,
depthTest: false
});
// 创建雪花粒子系统
const snowflakesParticles = new THREE.Points(snowflakesGeometry, snowflakesMaterial);
scene.add(snowflakesParticles);
// 存储雪花系统
snowflakes = {
particles: snowflakesParticles,
positions: positions,
velocities: velocities,
rotations: rotations,
rotationSpeeds: rotationSpeeds,
count: snowflakesCount
};
}
// 创建圣诞老人
function createSanta() {
const santaGroup = new THREE.Group();
// 身体
const bodyGeometry = new THREE.CylinderGeometry(0.8, 1, 2, 16);
const bodyMaterial = new THREE.MeshStandardMaterial({
color: 0xff0000,
roughness: 0.7,
metalness: 0.2
});
const body = new THREE.Mesh(bodyGeometry, bodyMaterial);
body.position.y = 1;
body.castShadow = true;
body.receiveShadow = true;
santaGroup.add(body);
// 手臂
const armGeometry = new THREE.CylinderGeometry(0.2, 0.15, 1.5, 8);
const armMaterial = new THREE.MeshStandardMaterial({ color: 0xff0000 });
const leftArm = new THREE.Mesh(armGeometry, armMaterial);
leftArm.position.set(-0.9, 1.2, 0);
leftArm.rotation.z = Math.PI / 6;
leftArm.castShadow = true;
leftArm.receiveShadow = true;
santaGroup.add(leftArm);
const rightArm = new THREE.Mesh(armGeometry, armMaterial);
rightArm.position.set(0.9, 1.2, 0);
rightArm.rotation.z = -Math.PI / 6;
rightArm.castShadow = true;
rightArm.receiveShadow = true;
santaGroup.add(rightArm);
// 头部
const headGeometry = new THREE.SphereGeometry(0.6, 16, 16);
const headMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff });
const head = new THREE.Mesh(headGeometry, headMaterial);
head.position.y = 2.6;
head.castShadow = true;
head.receiveShadow = true;
santaGroup.add(head);
// 帽子
const hatGeometry = new THREE.ConeGeometry(0.6, 1, 16);
const hatMaterial = new THREE.MeshStandardMaterial({ color: 0xff0000 });
const hat = new THREE.Mesh(hatGeometry, hatMaterial);
hat.position.y = 3.3;
hat.castShadow = true;
hat.receiveShadow = true;
santaGroup.add(hat);
// 胡子
const beardGeometry = new THREE.ConeGeometry(0.5, 0.8, 16);
const beardMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff });
const beard = new THREE.Mesh(beardGeometry, beardMaterial);
beard.rotation.x = Math.PI;
beard.position.y = 2.2;
beard.castShadow = true;
beard.receiveShadow = true;
santaGroup.add(beard);
// 眼睛
const eyeGeometry = new THREE.SphereGeometry(0.08, 8, 8);
const eyeMaterial = new THREE.MeshStandardMaterial({ color: 0x000000 });
const leftEye = new THREE.Mesh(eyeGeometry, eyeMaterial);
leftEye.position.set(-0.2, 2.8, 0.5);
santaGroup.add(leftEye);
const rightEye = new THREE.Mesh(eyeGeometry, eyeMaterial);
rightEye.position.set(0.2, 2.8, 0.5);
santaGroup.add(rightEye);
// 鼻子
const noseGeometry = new THREE.ConeGeometry(0.15, 0.3, 8);
const noseMaterial = new THREE.MeshStandardMaterial({ color: 0xff6600 });
const nose = new THREE.Mesh(noseGeometry, noseMaterial);
nose.position.set(0, 2.6, 0.5);
nose.rotation.x = Math.PI;
santaGroup.add(nose);
// 礼物袋
const bagGeometry = new THREE.CylinderGeometry(0.4, 0.6, 1, 16);
const bagMaterial = new THREE.MeshStandardMaterial({ color: 0x8B4513 });
const bag = new THREE.Mesh(bagGeometry, bagMaterial);
bag.position.set(0, -0.2, 0);
bag.castShadow = true;
bag.receiveShadow = true;
santaGroup.add(bag);
// 放置圣诞老人
santaGroup.position.set(8, 0, 8);
santaGroup.rotation.y = Math.PI / 4;
// 存储圣诞老人数据
santa = {
mesh: santaGroup,
targetPosition: new THREE.Vector3(8, 0, 8),
currentPosition: new THREE.Vector3(8, 0, 8),
animationPhase: 0,
wavePhase: 0
};
scene.add(santa.mesh);
isSantaVisible = true;
}
// 窗口大小调整
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
// 点击事件
function onClick(event) {
// 计算鼠标位置
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
// 更新射线
raycaster.setFromCamera(mouse, camera);
// 检测是否点击了装饰球
const intersects = raycaster.intersectObjects(ornaments.map(o => o.mesh));
if (intersects.length > 0) {
// 找到被点击的装饰球
const clickedOrnament = intersects[0].object;
const ornamentData = ornaments.find(o => o.mesh === clickedOrnament);
if (ornamentData) {
// 设置装饰球开始闪烁
ornamentData.pulseIntensity = 1;
ornamentData.pulseSpeed = Math.random() * 0.05 + 0.02;
// 显示圣诞快乐文字
showMerryChristmas();
}
} else {
// 随机点亮一些装饰球
for (let i = 0; i < 3; i++) {
const randomIndex = Math.floor(Math.random() * ornaments.length);
ornaments[randomIndex].pulseIntensity = 1;
ornaments[randomIndex].pulseSpeed = Math.random() * 0.05 + 0.02;
}
}
}
// 显示圣诞快乐文字
function showMerryChristmas() {
const element = document.getElementById('merry-christmas');
element.style.opacity = '1';
setTimeout(() => {
element.style.opacity = '0';
}, 3000);
}
// 切换圣诞老人显示
function toggleSanta() {
if (isSantaVisible) {
if (santa && santa.mesh) {
scene.remove(santa.mesh);
}
isSantaVisible = false;
document.getElementById('santa-btn').textContent = '召唤圣诞老人';
} else {
if (!santa) {
createSanta();
} else {
scene.add(santa.mesh);
isSantaVisible = true;
}
document.getElementById('santa-btn').textContent = '隐藏圣诞老人';
}
}
// 动画循环
function animate() {
requestAnimationFrame(animate);
// 更新控制器
controls.update();
// 更新雪花
updateSnowflakes();
// 更新灯光
updateLights();
// 更新装饰球
updateOrnaments();
// 更新圣诞老人
if (santa && isSantaVisible) {
updateSanta();
}
// 渲染场景
renderer.render(scene, camera);
}
// 更新雪花
function updateSnowflakes() {
if (!snowflakes.particles) return;
const positions = snowflakes.positions;
const velocities = snowflakes.velocities;
const rotations = snowflakes.rotations;
const rotationSpeeds = snowflakes.rotationSpeeds;
for (let i = 0; i < snowflakes.count; i++) {
// 更新位置
positions[i * 3] += velocities[i * 3];
positions[i * 3 + 1] += velocities[i * 3 + 1];
positions[i * 3 + 2] += velocities[i * 3 + 2];
// 更新旋转
rotations[i] += rotationSpeeds[i];
// 如果雪花超出边界,重置位置
if (
positions[i * 3] < -50 ||
positions[i * 3] > 50 ||
positions[i * 3 + 1] < -5 ||
positions[i * 3 + 1] > 50 ||
positions[i * 3 + 2] < -50 ||
positions[i * 3 + 2] > 50
) {
positions[i * 3] = Math.random() * 100 - 50;
positions[i * 3 + 1] = 50;
positions[i * 3 + 2] = Math.random() * 100 - 50;
velocities[i * 3] = (Math.random() - 0.5) * 0.05;
velocities[i * 3 + 1] = -(Math.random() * 0.05 + 0.01);
velocities[i * 3 + 2] = (Math.random() - 0.5) * 0.05;
}
}
snowflakes.particles.geometry.attributes.position.needsUpdate = true;
snowflakes.particles.geometry.attributes.rotation.needsUpdate = true;
}
// 更新灯光
function updateLights() {
lights.forEach(lightData => {
// 灯光闪烁效果
lightData.pulseIntensity += lightData.pulseSpeed;
if (lightData.pulseIntensity > 1 || lightData.pulseIntensity < 0) {
lightData.pulseSpeed *= -1;
}
// 调整发光强度
const intensity = 0.5 + Math.abs(Math.sin(lightData.pulseIntensity * Math.PI)) * 0.5;
lightData.mesh.material.emissiveIntensity = intensity;
});
}
// 更新装饰球
function updateOrnaments() {
ornaments.forEach(ornament => {
if (ornament.pulseIntensity > 0) {
// 装饰球闪烁效果
ornament.pulseIntensity -= ornament.pulseSpeed;
if (ornament.pulseIntensity < 0) {
ornament.pulseIntensity = 0;
}
// 计算当前颜色(在原始颜色和亮白色之间插值)
const pulseColor = new THREE.Color().lerpVectors(
ornament.originalColor,
new THREE.Color(0xffffff),
Math.sin(ornament.pulseIntensity * Math.PI) * 0.5 + 0.5
);
ornament.mesh.material.color.copy(pulseColor);
}
});
}
// 更新圣诞老人
function updateSanta() {
if (!santa) return;
// 更新动画阶段
santa.animationPhase += 0.02;
santa.wavePhase += 0.05;
// 随机改变目标位置
if (Math.random() < 0.01) {
santa.targetPosition.set(
Math.random() * 12 - 6,
0,
Math.random() * 12 - 6
);
}
// 向目标位置移动
santa.currentPosition.lerp(santa.targetPosition, 0.01);
santa.mesh.position.copy(santa.currentPosition);
// 朝向相机
santa.mesh.lookAt(camera.position);
santa.mesh.rotation.x = 0;
santa.mesh.rotation.z = 0;
// 手臂摆动动画
const rightArm = santa.mesh.children[3]; // 假设右手臂是第四个子元素
if (rightArm) {
rightArm.rotation.z = -Math.PI / 6 + Math.sin(santa.wavePhase) * 0.3;
}
// 身体轻微摆动
santa.mesh.rotation.z = Math.sin(santa.animationPhase) * 0.05;
}
// 页面加载完成后初始化
if (typeof THREE !== 'undefined') {
window.addEventListener('load', init);
// 立即尝试初始化
if (document.readyState !== 'loading') {
setTimeout(init, 100);
}
} else {
console.error('Three.js库没有正确加载!');
document.body.innerHTML = '<h1 style="color: red;">错误:Three.js库没有正确加载!</h1>';
}
</script>
</body>
</html>