优化星云相册

This commit is contained in:
DelLevin-Home
2026-06-05 19:02:52 +08:00
parent a2de47355c
commit d7505e5b0c
6 changed files with 315 additions and 297 deletions

View File

@@ -3,7 +3,21 @@
"allow": [ "allow": [
"mcp__Claude_Preview__preview_start", "mcp__Claude_Preview__preview_start",
"WebFetch(domain:cdnjs.cloudflare.com)", "WebFetch(domain:cdnjs.cloudflare.com)",
"Bash(curl -L -o \"D:\\\\UserData\\\\Desktop\\\\my_proj\\\\www.iletter.top\\\\static\\\\js\\\\three.min.js\" \"https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js\")" "Bash(curl -L -o \"D:\\\\UserData\\\\Desktop\\\\my_proj\\\\www.iletter.top\\\\static\\\\js\\\\three.min.js\" \"https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js\")",
"Bash(curl -L -o sun.jpg \"https://upload.wikimedia.org/wikipedia/commons/thumb/b/b4/The_Sun_by_the_Atmospheric_Imaging_Assembly_of_NASA%27s_Solar_Dynamics_Observatory_-_20100819.jpg/1200px-The_Sun_by_the_Atmospheric_Imaging_Assembly_of_NASA%27s_Solar_Dynamics_Observatory_-_20100819.jpg\")",
"Bash(curl -L -o earth.jpg \"https://upload.wikimedia.org/wikipedia/commons/thumb/c/cb/The_Blue_Marble_%28remastered%29.jpg/1200px-The_Blue_Marble_%28remastered%29.jpg\")",
"Bash(curl -L -o mars.jpg \"https://upload.wikimedia.org/wikipedia/commons/thumb/0/0c/Mars_-_August_30_2021_-_Flipped.jpg/1200px-Mars_-_August_30_2021_-_Flipped.jpg\")",
"Bash(curl -L -o saturn.jpg \"https://upload.wikimedia.org/wikipedia/commons/thumb/c/c7/Saturn_during_Equinox.jpg/1200px-Saturn_during_Equinox.jpg\")",
"Bash(curl -L -o jupiter.jpg \"https://upload.wikimedia.org/wikipedia/commons/thumb/c/c1/Jupiter_New_Horizons.jpg/1200px-Jupiter_New_Horizons.jpg\")",
"Bash(curl -sL \"https://upload.wikimedia.org/wikipedia/commons/thumb/b/b4/The_Sun_by_the_Atmospheric_Imaging_Assembly_of_NASA%27s_Solar_Dynamics_Observatory_-_20100819.jpg/600px-The_Sun_by_the_Atmospheric_Imaging_Assembly_of_NASA%27s_Solar_Dynamics_Observatory_-_20100819.jpg\" -o sun.jpg)",
"Bash(curl -sL \"https://images.unsplash.com/photo-1506318137071-a8e063b4bec0?w=300\" -o sun.jpg)",
"Bash(curl -sL \"https://images.unsplash.com/photo-1614730321146-b6fa6a46bcb4?w=300\" -o earth.jpg)",
"Bash(curl -sL \"https://images.unsplash.com/photo-1614728894747-a83421e2b9c9?w=300\" -o mars.jpg)",
"Bash(curl -sL \"https://images.unsplash.com/photo-1614732414444-096e5f1122d5?w=300\" -o saturn.jpg)",
"Bash(curl -sL \"https://images.unsplash.com/photo-1614313913007-2b4ae8ce32d6?w=300\" -o jupiter.jpg)",
"Bash(curl -sL \"https://images.unsplash.com/photo-1446776811953-b23d57bd21aa?w=2048&q=80\" -o moon.jpg)",
"Bash(curl -sL \"https://svs.gsfc.nasa.gov/vis/a000000/a004700/a004720/lroc_color_poles_4096.jpg\" -o moon.jpg)",
"Bash(curl -sL \"https://upload.wikimedia.org/wikipedia/commons/thumb/d/db/Moonmap_from_clementine_data.png/1280px-Moonmap_from_clementine_data.png\" -o moon.png)"
] ]
} }
} }

View File

@@ -161,102 +161,15 @@
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
width: 100%; right: 0;
height: 100%; bottom: 0;
background-image: background-image: url('../img/planets/bg.jpg');
/* 第一大区域 - 各种随机位置和大小 */ background-size: cover;
radial-gradient(1px 1px at 5px 15px, #fff, transparent), background-position: center;
radial-gradient(2px 2px at 45px 8px, rgba(255,255,255,0.85), transparent),
radial-gradient(1px 1px at 82px 42px, rgba(255,255,255,0.6), transparent),
radial-gradient(3px 3px at 120px 25px, #fff, transparent),
radial-gradient(1px 1px at 155px 58px, rgba(255,255,255,0.9), transparent),
radial-gradient(2px 2px at 192px 12px, rgba(255,255,255,0.4), transparent),
radial-gradient(1px 1px at 228px 48px, #fff, transparent),
radial-gradient(2px 2px at 265px 32px, rgba(255,255,255,0.7), transparent),
radial-gradient(1px 1px at 302px 65px, rgba(255,255,255,0.5), transparent),
radial-gradient(1px 1px at 338px 8px, #fff, transparent),
radial-gradient(2px 2px at 375px 42px, rgba(255,255,255,0.8), transparent),
radial-gradient(1px 1px at 412px 18px, rgba(255,255,255,0.6), transparent),
radial-gradient(2px 2px at 448px 55px, rgba(255,255,255,0.3), transparent),
radial-gradient(1px 1px at 485px 38px, #fff, transparent),
radial-gradient(1px 1px at 522px 72px, rgba(255,255,255,0.7), transparent),
radial-gradient(3px 3px at 558px 28px, rgba(255,255,255,0.5), transparent),
radial-gradient(1px 1px at 595px 52px, #fff, transparent),
/* 第二大区域 - 更随机的分布 */
radial-gradient(2px 2px at 22px 78px, rgba(255,255,255,0.45), transparent),
radial-gradient(1px 1px at 68px 92px, #fff, transparent),
radial-gradient(1px 1px at 108px 85px, rgba(255,255,255,0.55), transparent),
radial-gradient(2px 2px at 145px 98px, rgba(255,255,255,0.35), transparent),
radial-gradient(1px 1px at 182px 88px, #fff, transparent),
radial-gradient(1px 1px at 218px 75px, rgba(255,255,255,0.65), transparent),
radial-gradient(2px 2px at 255px 95px, rgba(255,255,255,0.45), transparent),
radial-gradient(1px 1px at 292px 82px, #fff, transparent),
radial-gradient(1px 1px at 328px 98px, rgba(255,255,255,0.75), transparent),
radial-gradient(2px 2px at 365px 78px, rgba(255,255,255,0.5), transparent),
radial-gradient(1px 1px at 402px 92px, #fff, transparent),
radial-gradient(1px 1px at 438px 85px, rgba(255,255,255,0.4), transparent),
radial-gradient(2px 2px at 475px 95px, rgba(255,255,255,0.6), transparent),
radial-gradient(1px 1px at 512px 78px, #fff, transparent),
radial-gradient(1px 1px at 548px 88px, rgba(255,255,255,0.8), transparent),
radial-gradient(1px 1px at 585px 82px, rgba(255,255,255,0.3), transparent),
/* 第三大区域 - 散落的小星星 */
radial-gradient(1px 1px at 15px 108px, rgba(255,255,255,0.25), transparent),
radial-gradient(1px 1px at 52px 118px, rgba(255,255,255,0.15), transparent),
radial-gradient(1px 1px at 88px 112px, rgba(255,255,255,0.35), transparent),
radial-gradient(1px 1px at 125px 105px, rgba(255,255,255,0.2), transparent),
radial-gradient(1px 1px at 162px 120px, rgba(255,255,255,0.4), transparent),
radial-gradient(1px 1px at 198px 108px, rgba(255,255,255,0.3), transparent),
radial-gradient(1px 1px at 235px 115px, rgba(255,255,255,0.5), transparent),
radial-gradient(1px 1px at 272px 102px, rgba(255,255,255,0.2), transparent),
radial-gradient(1px 1px at 308px 120px, rgba(255,255,255,0.35), transparent),
radial-gradient(1px 1px at 345px 108px, rgba(255,255,255,0.45), transparent),
radial-gradient(1px 1px at 382px 115px, rgba(255,255,255,0.15), transparent),
radial-gradient(1px 1px at 418px 102px, rgba(255,255,255,0.25), transparent),
radial-gradient(1px 1px at 455px 112px, rgba(255,255,255,0.4), transparent),
radial-gradient(1px 1px at 492px 105px, rgba(255,255,255,0.3), transparent),
radial-gradient(1px 1px at 528px 118px, rgba(255,255,255,0.5), transparent),
radial-gradient(1px 1px at 565px 108px, rgba(255,255,255,0.2), transparent),
radial-gradient(1px 1px at 602px 115px, rgba(255,255,255,0.35), transparent),
/* 额外的亮点 */
radial-gradient(2px 2px at 35px 55px, rgba(255,255,255,0.6), transparent),
radial-gradient(3px 3px at 175px 35px, rgba(255,255,255,0.8), transparent),
radial-gradient(2px 2px at 315px 68px, rgba(255,255,255,0.7), transparent),
radial-gradient(2px 2px at 455px 25px, rgba(255,255,255,0.5), transparent),
radial-gradient(1px 1px at 535px 42px, rgba(255,255,255,0.9), transparent),
radial-gradient(2px 2px at 75px 68px, rgba(255,255,255,0.65), transparent),
radial-gradient(1px 1px at 205px 82px, rgba(255,255,255,0.75), transparent),
radial-gradient(3px 3px at 385px 48px, rgba(255,255,255,0.55), transparent),
radial-gradient(1px 1px at 505px 72px, rgba(255,255,255,0.85), transparent),
radial-gradient(2px 2px at 625px 15px, rgba(255,255,255,0.4), transparent),
radial-gradient(1px 1px at 652px 58px, rgba(255,255,255,0.7), transparent),
radial-gradient(2px 2px at 688px 32px, rgba(255,255,255,0.6), transparent),
radial-gradient(1px 1px at 725px 45px, rgba(255,255,255,0.8), transparent),
radial-gradient(2px 2px at 762px 62px, rgba(255,255,255,0.5), transparent),
radial-gradient(1px 1px at 798px 18px, rgba(255,255,255,0.65), transparent),
radial-gradient(1px 1px at 835px 75px, rgba(255,255,255,0.45), transparent),
radial-gradient(2px 2px at 872px 42px, rgba(255,255,255,0.7), transparent),
radial-gradient(1px 1px at 908px 28px, rgba(255,255,255,0.55), transparent),
radial-gradient(2px 2px at 945px 65px, rgba(255,255,255,0.8), transparent),
radial-gradient(1px 1px at 982px 38px, rgba(255,255,255,0.4), transparent);
background-repeat: repeat;
background-size: 1000px 130px;
animation: twinkle 3s ease-in-out infinite alternate, drift 20s linear infinite;
pointer-events: none; pointer-events: none;
z-index: 0; z-index: 0;
} }
@keyframes twinkle {
0% { opacity: 0.4; }
33% { opacity: 0.7; }
66% { opacity: 0.5; }
100% { opacity: 0.8; }
}
@keyframes drift {
0% { transform: translate(0, 0); }
100% { transform: translate(-10px, -5px); }
}
.galaxy-canvas-wrapper canvas { .galaxy-canvas-wrapper canvas {
width: 100%; width: 100%;
height: 100%; height: 100%;

BIN
static/img/planets/bg.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 409 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

BIN
static/img/planets/moon.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 320 KiB

View File

@@ -213,21 +213,21 @@
galaxyGroups = []; galaxyGroups = [];
galaxyRotations = []; galaxyRotations = [];
// 创建9个银河系合理距离多种角度 // 创建9个银河系合理距离多种角度,大胆倾斜,保持足够距离
const galaxyPositions = [ const galaxyPositions = [
// 中心主银河系 // 中心主银河系 - 横着正常显示
{ x: 0, y: 0, z: 0, scale: 1.0, rotX: 0, rotZ: 0 }, { x: 0, y: 0, z: 0, scale: 1.0, rotX: 0, rotZ: 0 },
// 前面银河系z正方向 // 前面银河系z正方向- 距离主银河系1200+
{ x: 500, y: 200, z: 600, scale: 0.7, rotX: 0.1, rotZ: -0.05 }, { x: 900, y: 350, z: 1100, scale: 0.7, rotX: -0.4, rotZ: 0.6 },
{ x: -400, y: 350, z: 500, scale: 0.65, rotX: -0.08, rotZ: 0.12 }, { x: -800, y: 600, z: 1000, scale: 0.65, rotX: 0.5, rotZ: -0.3 },
{ x: 300, y: -250, z: 700, scale: 0.6, rotX: 0.15, rotZ: -0.1 }, { x: 600, y: -500, z: 1200, scale: 0.6, rotX: -0.7, rotZ: 0.4 },
// 近距离(600-900单位 // 近距离(1300-1600单位
{ x: 700, y: 200, z: -500, scale: 0.75, rotX: 0.1, rotZ: -0.05 }, { x: 1300, y: 400, z: -900, scale: 0.75, rotX: 0.8, rotZ: -0.5 },
{ x: -600, y: -350, z: -400, scale: 0.7, rotX: -0.08, rotZ: 0.12 }, { x: -1200, y: -600, z: -800, scale: 0.7, rotX: -0.3, rotZ: 0.7 },
// 中距离1000-1500单位 // 中距离1800-2200单位
{ x: 1200, y: 500, z: -1000, scale: 0.6, rotX: 0.15, rotZ: -0.1 }, { x: 2000, y: 800, z: -1700, scale: 0.6, rotX: 0.6, rotZ: -0.8 },
{ x: -1100, y: 400, z: -900, scale: 0.55, rotX: -0.12, rotZ: 0.08 }, { x: -1900, y: 700, z: -1600, scale: 0.55, rotX: -0.5, rotZ: 0.4 },
{ x: 400, y: -900, z: -800, scale: 0.65, rotX: 0.05, rotZ: 0.15 }, { x: 700, y: -1600, z: -1400, scale: 0.65, rotX: 0.9, rotZ: -0.6 },
]; ];
galaxyPositions.forEach((pos, index) => { galaxyPositions.forEach((pos, index) => {
@@ -307,9 +307,30 @@
function createPhotoStar(photo, index, galaxyGroup) { function createPhotoStar(photo, index, galaxyGroup) {
// 创建圆形纹理 // 创建圆形纹理
const textureLoader = new THREE.TextureLoader(); const textureLoader = new THREE.TextureLoader();
const texture = textureLoader.load(photo.src); const texture = textureLoader.load(photo.src, (loadedTexture) => {
// 图片加载完成后,根据原始比例调整几何体
const image = loadedTexture.image;
const aspectRatio = image.width / image.height;
let width = 30;
let height = 30;
// 创建正方形几何体 if (aspectRatio > 1) {
// 宽图宽度为30高度按比例
height = width / aspectRatio;
} else {
// 高图或正方形高度为30宽度按比例
height = 30;
width = height * aspectRatio;
}
// 更新几何体尺寸
star.geometry.dispose();
star.geometry = new THREE.PlaneGeometry(width, height);
hitArea.geometry.dispose();
hitArea.geometry = new THREE.PlaneGeometry(width * 2, height * 2);
});
// 创建默认正方形几何体(加载完成后会被替换)
const geometry = new THREE.PlaneGeometry(30, 30); const geometry = new THREE.PlaneGeometry(30, 30);
// 创建材质 - 无滤镜 // 创建材质 - 无滤镜
@@ -323,27 +344,46 @@
// 创建网格 // 创建网格
const star = new THREE.Mesh(geometry, material); const star = new THREE.Mesh(geometry, material);
// 创建一个更大的透明点击检测区域
const hitGeometry = new THREE.PlaneGeometry(60, 60);
const hitMaterial = new THREE.MeshBasicMaterial({
transparent: true,
opacity: 0.001, // 几乎透明但不完全透明以便raycaster能检测到
side: THREE.DoubleSide
});
const hitArea = new THREE.Mesh(hitGeometry, hitMaterial);
// 随机位置(银河系分布) // 随机位置(银河系分布)
const radius = 200 + Math.random() * 600; const radius = 200 + Math.random() * 600;
const theta = Math.random() * Math.PI * 2; const theta = Math.random() * Math.PI * 2;
const phi = (Math.random() - 0.5) * Math.PI * 0.3; // 扁平分布 const phi = (Math.random() - 0.5) * Math.PI * 0.3; // 扁平分布
star.position.x = radius * Math.cos(theta) * Math.cos(phi); const x = radius * Math.cos(theta) * Math.cos(phi);
star.position.y = radius * Math.sin(phi) * 0.3; // 更扁平 const y = radius * Math.sin(phi) * 0.3; // 更扁平
star.position.z = radius * Math.sin(theta) * Math.cos(phi); const z = radius * Math.sin(theta) * Math.cos(phi);
// 存储照片信息 // 设置两个网格的相同位置
star.userData = { star.position.set(x, y, z);
hitArea.position.set(x, y, z);
// 存储照片信息两个网格共享相同的userData
const userData = {
photoId: photo.id, photoId: photo.id,
photoSrc: photo.src, photoSrc: photo.src,
photoFilename: photo.filename photoFilename: photo.filename
}; };
star.userData = userData;
hitArea.userData = userData;
// 面向相机 // 面向相机
star.lookAt(camera.position); star.lookAt(camera.position);
hitArea.lookAt(camera.position);
// 将点击检测区域添加到组中
galaxyGroup.add(hitArea);
galaxyGroup.add(star); galaxyGroup.add(star);
stars.push(star); stars.push(star);
stars.push(hitArea); // 也添加到检测数组中
} }
// 创建默认星星 // 创建默认星星
@@ -373,21 +413,21 @@
// 添加装饰性星星(银河系效果) // 添加装饰性星星(银河系效果)
function addDecorativeStars(galaxyGroup, scale = 1, galaxyIndex = 0) { function addDecorativeStars(galaxyGroup, scale = 1, galaxyIndex = 0) {
const starCount = Math.floor(4000 * scale); // 根据缩放调整星星数量 const starCount = Math.floor(8000 * scale); // 星星数量增加到8000
const starGeometry = new THREE.BufferGeometry(); const starGeometry = new THREE.BufferGeometry();
const positions = new Float32Array(starCount * 3); const positions = new Float32Array(starCount * 3);
const colors = new Float32Array(starCount * 3); const colors = new Float32Array(starCount * 3);
const sizes = new Float32Array(starCount); const sizes = new Float32Array(starCount);
// 银河系参数 // 银河系参数
const bulgeRadius = 120; // 银核半径 const bulgeRadius = 150; // 银核半径
const diskRadius = 700; // 银盘半径 const diskRadius = 600; // 银盘半径
const armCount = 4; // 旋臂数量 const armCount = galaxyIndex === 0 ? 4 : (galaxyIndex % 2 === 0 ? 4 : 6); // 主银河4条其他4或6条
const spiralAngle = 12; // 螺旋角(度) const spin = 0.3; // 旋臂旋转角度
const spiralTightness = 0.005; // 螺旋紧密度 const radialRandomness = 0.4; // 径向随机性
// 根据银河系索引选择配色方案 // 根据银河系索引选择配色方案(主银河系用蓝色调)
const colorScheme = galaxyIndex === 0 ? 'warm' : getColorScheme(galaxyIndex); const colorScheme = galaxyIndex === 0 ? 'blue' : getColorScheme(galaxyIndex);
// 获取银河系配色方案 // 获取银河系配色方案
function getColorScheme(index) { function getColorScheme(index) {
@@ -414,195 +454,157 @@
} }
// 根据配色方案获取颜色 // 根据配色方案获取颜色
function getColor(scheme, brightness, distanceFromCenter) { function getColor(scheme, radiusRatio) {
let color; let color;
const t = radiusRatio; // 0=中心1=边缘
switch (scheme) { switch (scheme) {
case 'warm': // 主银河系 - 暖黄色(不淡化) case 'warm': // 主银河系 - 暖黄色
if (distanceFromCenter < 0.3) { return [1, 0.9 - t * 0.3, 0.6 - t * 0.4]; // 橙到紫
color = [1, 0.9 + brightness * 0.1, 0.7 + brightness * 0.3];
} else if (distanceFromCenter < 0.5) {
color = [1, 0.8 + Math.random() * 0.15, 0.4 + Math.random() * 0.3];
} else {
color = [0.9 + Math.random() * 0.1, 0.85 + Math.random() * 0.1, 0.6 + Math.random() * 0.2];
}
return color; // 主银河系不淡化
case 'blue': // 蓝色系(淡化) case 'blue':
if (distanceFromCenter < 0.3) { color = [0.3, 0.5 + t * 0.3, 0.9 - t * 0.2];
color = [0.3, 0.5 + brightness * 0.3, 0.9 + brightness * 0.1];
} else if (distanceFromCenter < 0.5) {
color = [0.2 + Math.random() * 0.1, 0.4 + Math.random() * 0.2, 0.8 + Math.random() * 0.15];
} else {
color = [0.1 + Math.random() * 0.15, 0.3 + Math.random() * 0.2, 0.7 + Math.random() * 0.2];
}
return fadeColor(color, 0.45); return fadeColor(color, 0.45);
case 'purple': // 紫色系(淡化) case 'purple':
if (distanceFromCenter < 0.3) { color = [0.7 - t * 0.3, 0.3, 0.9 - t * 0.1];
color = [0.7 + brightness * 0.3, 0.3, 0.9 + brightness * 0.1];
} else if (distanceFromCenter < 0.5) {
color = [0.6 + Math.random() * 0.2, 0.2 + Math.random() * 0.1, 0.8 + Math.random() * 0.15];
} else {
color = [0.5 + Math.random() * 0.2, 0.1 + Math.random() * 0.15, 0.7 + Math.random() * 0.2];
}
return fadeColor(color, 0.45); return fadeColor(color, 0.45);
case 'cyan': // 青色系(淡化) case 'cyan':
if (distanceFromCenter < 0.3) { color = [0.2, 0.8 - t * 0.3, 0.9 - t * 0.2];
color = [0.2, 0.8 + brightness * 0.2, 0.9 + brightness * 0.1];
} else if (distanceFromCenter < 0.5) {
color = [0.1 + Math.random() * 0.1, 0.7 + Math.random() * 0.15, 0.8 + Math.random() * 0.15];
} else {
color = [0.05 + Math.random() * 0.1, 0.6 + Math.random() * 0.2, 0.7 + Math.random() * 0.2];
}
return fadeColor(color, 0.45); return fadeColor(color, 0.45);
case 'pink': // 粉色系(淡化) case 'pink':
if (distanceFromCenter < 0.3) { color = [0.9 - t * 0.2, 0.4 + t * 0.1, 0.6 - t * 0.2];
color = [0.9 + brightness * 0.1, 0.4 + brightness * 0.2, 0.6 + brightness * 0.2];
} else if (distanceFromCenter < 0.5) {
color = [0.8 + Math.random() * 0.15, 0.3 + Math.random() * 0.15, 0.5 + Math.random() * 0.2];
} else {
color = [0.7 + Math.random() * 0.2, 0.2 + Math.random() * 0.15, 0.4 + Math.random() * 0.2];
}
return fadeColor(color, 0.45); return fadeColor(color, 0.45);
case 'red': // 红色系(淡化) case 'red':
if (distanceFromCenter < 0.3) { color = [0.9 - t * 0.2, 0.3 + t * 0.1, 0.3];
color = [0.9 + brightness * 0.1, 0.3, 0.3];
} else if (distanceFromCenter < 0.5) {
color = [0.8 + Math.random() * 0.15, 0.2 + Math.random() * 0.1, 0.2 + Math.random() * 0.1];
} else {
color = [0.7 + Math.random() * 0.2, 0.1 + Math.random() * 0.15, 0.1 + Math.random() * 0.15];
}
return fadeColor(color, 0.45); return fadeColor(color, 0.45);
case 'green': // 绿色系(淡化) case 'green':
if (distanceFromCenter < 0.3) { color = [0.3, 0.8 - t * 0.2, 0.4 + t * 0.1];
color = [0.3, 0.8 + brightness * 0.2, 0.4];
} else if (distanceFromCenter < 0.5) {
color = [0.2 + Math.random() * 0.1, 0.7 + Math.random() * 0.15, 0.3 + Math.random() * 0.1];
} else {
color = [0.1 + Math.random() * 0.15, 0.6 + Math.random() * 0.2, 0.2 + Math.random() * 0.15];
}
return fadeColor(color, 0.45); return fadeColor(color, 0.45);
case 'orange': // 橙色系(淡化) case 'orange':
if (distanceFromCenter < 0.3) { color = [0.9 - t * 0.2, 0.6 - t * 0.3, 0.2 + t * 0.1];
color = [0.9 + brightness * 0.1, 0.6 + brightness * 0.2, 0.2];
} else if (distanceFromCenter < 0.5) {
color = [0.8 + Math.random() * 0.15, 0.5 + Math.random() * 0.15, 0.15 + Math.random() * 0.1];
} else {
color = [0.7 + Math.random() * 0.2, 0.4 + Math.random() * 0.2, 0.1 + Math.random() * 0.15];
}
return fadeColor(color, 0.45); return fadeColor(color, 0.45);
case 'white': // 白色系(已经是淡色,稍微淡化) case 'white':
if (distanceFromCenter < 0.3) { color = [0.9 - t * 0.2, 0.9 - t * 0.2, 0.9 - t * 0.2];
color = [0.9 + brightness * 0.1, 0.9 + brightness * 0.1, 0.9 + brightness * 0.1]; return fadeColor(color, 0.3);
} else if (distanceFromCenter < 0.5) {
color = [0.8 + Math.random() * 0.1, 0.8 + Math.random() * 0.1, 0.8 + Math.random() * 0.1];
} else {
color = [0.7 + Math.random() * 0.15, 0.7 + Math.random() * 0.15, 0.7 + Math.random() * 0.15];
}
return fadeColor(color, 0.3); // 白色系淡化程度低一些
default: default:
color = [1, 1, 1]; return [1, 0.9 - t * 0.3, 0.6 - t * 0.4];
return color;
} }
} }
// 随机极坐标(用于径向偏移)
function getRandomPolarCoordinate(radius) {
const theta = Math.random() * Math.PI * 2;
const phi = Math.random() * Math.PI * 2;
return {
x: radius * Math.sin(theta) * Math.cos(phi),
y: radius * Math.sin(theta) * Math.sin(phi),
z: radius * Math.cos(theta)
};
}
for (let i = 0; i < starCount; i++) { for (let i = 0; i < starCount; i++) {
let x, y, z, brightness; let x, y, z, brightness, color;
// 根据概率分配
const rand = Math.random(); const rand = Math.random();
if (rand < 0.15) { if (rand < 0.12) {
// ==================== 银核15%==================== // ==================== 银核12%====================
// 非常明亮的圆球区域,大量星星密集分布 // 非常明亮的圆球区域,厚实密集
const r = Math.pow(Math.random(), 0.3) * bulgeRadius;
// 使用球形分布,中心密度最高
const r = Math.pow(Math.random(), 0.2) * bulgeRadius; // 高度集中在中心
const theta = Math.random() * Math.PI * 2; const theta = Math.random() * Math.PI * 2;
const phi = Math.acos(2 * Math.random() - 1); // 均匀的球形分布 const phi = Math.acos(2 * Math.random() - 1);
x = r * Math.sin(phi) * Math.cos(theta); x = r * Math.sin(phi) * Math.cos(theta);
y = r * Math.cos(phi) * 0.5; // 稍微扁平一些 y = r * Math.cos(phi) * 0.6; // 稍微扁平
z = r * Math.sin(phi) * Math.sin(theta); z = r * Math.sin(phi) * Math.sin(theta);
// 银核非常亮,中心最亮
brightness = 0.85 + Math.pow(1 - r / bulgeRadius, 2) * 0.15; brightness = 0.85 + Math.pow(1 - r / bulgeRadius, 2) * 0.15;
sizes[i] = 3 + Math.random() * 4; // 大尺寸的明亮星星 sizes[i] = 3 + Math.random() * 5; // 大尺寸
} else if (rand < 0.85) { // 银核颜色:暖白色
// ==================== 旋臂70%==================== const bulgeColor = getColor(colorScheme, 0);
// 星星严格分布在旋臂上 color = [
Math.min(1, bulgeColor[0] + 0.2),
Math.min(1, bulgeColor[1] + 0.15),
Math.min(1, bulgeColor[2] + 0.1)
];
} else if (rand < 0.30) {
// ==================== 旋臂上18%====================
// 参考 test.html 的旋臂算法
// 选择一条旋臂 // 选择一条旋臂
const armIndex = Math.floor(Math.random() * armCount); const armIndex = i % armCount;
const armBaseAngle = (armIndex / armCount) * Math.PI * 2; const branchAngle = (armIndex / armCount) * Math.PI * 2;
// 从银核向外延伸的距离 // 从银核向外的距离
const distance = bulgeRadius + Math.pow(Math.random(), 0.6) * (diskRadius - bulgeRadius); const radius = bulgeRadius + Math.random() * (diskRadius - bulgeRadius);
// 螺旋线角度 // 旋臂旋转角度(距离越远旋转越多)
const spiralTheta = armBaseAngle + spiralTightness * distance * Math.log(1 + distance / bulgeRadius); const spinAngle = spin * radius * 0.01;
// 旋臂宽度(更粗壮) // 径向随机偏移(让旋臂更粗壮)
const armWidth = 880 + distance * 0.12; const randRadius = Math.random() * radialRandomness * radius * 0.5;
const randOffset = getRandomPolarCoordinate(randRadius);
// 高斯分布让星星集中在旋臂中心
const gaussianRandom = (Math.random() + Math.random() + Math.random()) / 3 - 0.5;
const offset = gaussianRandom * armWidth * 0.5;
// 计算位置 // 计算位置
const angle = spiralTheta; x = radius * Math.cos(branchAngle + spinAngle) + randOffset.x;
x = distance * Math.cos(angle) + offset * Math.cos(angle + Math.PI / 2); z = radius * Math.sin(branchAngle + spinAngle) + randOffset.z;
z = distance * Math.sin(angle) + offset * Math.sin(angle + Math.PI / 2); y = randOffset.y * 0.3; // 扁平分布
// 高度分布(扁平) // 亮度随距离衰减
y = (Math.random() - 0.5) * 15 * (distance / diskRadius); const radiusRatio = (radius - bulgeRadius) / (diskRadius - bulgeRadius);
brightness = Math.max(0.5, 1 - radiusRatio * 0.4);
sizes[i] = 1.5 + Math.random() * 2.5;
// 旋臂较亮 // 颜色从内到外渐变
brightness = Math.max(0.6, 1 - distance / diskRadius * 0.3); color = getColor(colorScheme, radiusRatio);
sizes[i] = 1.5 + Math.random() * 2;
} else { } else {
// ==================== 背景星星30%==================== // ==================== 旋臂之间70%====================
// 随机分布,但避开旋臂区域(相对稀疏) // 随机分布在银盘上,不在旋臂上
const distance = bulgeRadius + Math.random() * (diskRadius - bulgeRadius); // 从银核向外的距离
const radius = bulgeRadius + Math.random() * (diskRadius - bulgeRadius);
// 随机角度(不跟随旋臂)
const theta = Math.random() * Math.PI * 2; const theta = Math.random() * Math.PI * 2;
x = distance * Math.cos(theta); // 随机偏移
z = distance * Math.sin(theta); const randOffset = getRandomPolarCoordinate(radius * 0.15);
y = (Math.random() - 0.5) * 50; // 扁平分布
// 背景较暗 // 计算位置
brightness = Math.max(0.2, 0.5 - distance / diskRadius * 0.3); x = radius * Math.cos(theta) + randOffset.x;
sizes[i] = 0.5 + Math.random() * 1; z = radius * Math.sin(theta) + randOffset.z;
y = (Math.random() - 0.5) * 20; // 扁平分布
// 背景星星亮度提高,但不超过旋臂
const radiusRatio = (radius - bulgeRadius) / (diskRadius - bulgeRadius);
brightness = Math.max(0.45, 0.75 - radiusRatio * 0.3);
sizes[i] = 0.8 + Math.random() * 1.5; // 较小尺寸
// 颜色从内到外渐变,亮度提高但仍比旋臂暗
color = getColor(colorScheme, radiusRatio);
color[0] *= 0.75;
color[1] *= 0.75;
color[2] *= 0.75;
} }
positions[i * 3] = x; positions[i * 3] = x;
positions[i * 3 + 1] = y; positions[i * 3 + 1] = y;
positions[i * 3 + 2] = z; positions[i * 3 + 2] = z;
// 设置颜色(根据配色方案) colors[i * 3] = color[0] * brightness;
const distanceFromCenter = Math.sqrt(x * x + y * y + z * z) / bulgeRadius; colors[i * 3 + 1] = color[1] * brightness;
const color = getColor(colorScheme, brightness, distanceFromCenter); colors[i * 3 + 2] = color[2] * brightness;
colors[i * 3] = color[0];
colors[i * 3 + 1] = color[1];
colors[i * 3 + 2] = color[2];
// 背景星星用冷色调(除了主银河系)
if (rand >= 0.70 && galaxyIndex !== 0) {
colors[i * 3] *= 0.5;
colors[i * 3 + 1] *= 0.5;
colors[i * 3 + 2] *= 0.5;
}
sizes[i] *= brightness; sizes[i] *= brightness;
} }
@@ -623,61 +625,131 @@
const starField = new THREE.Points(starGeometry, starMaterial); const starField = new THREE.Points(starGeometry, starMaterial);
galaxyGroup.add(starField); galaxyGroup.add(starField);
// 添加银核发光球体 // 添加银核发光球体(使用不同的行星样式)
addGalacticCore(galaxyGroup, scale); addGalacticCore(galaxyGroup, scale, galaxyIndex);
// 添加星云效果 // 添加星云效果
addNebulaEffect(galaxyGroup, scale); addNebulaEffect(galaxyGroup, scale, galaxyIndex, colorScheme);
} }
// 添加银核发光球体 // 添加银核发光球体
function addGalacticCore(galaxyGroup, scale = 1) { function addGalacticCore(galaxyGroup, scale = 1, galaxyIndex = 0) {
// 创建一个明亮的发光球体作为银核 if (galaxyIndex === 0) {
const coreGeometry = new THREE.SphereGeometry(80, 32, 32); // 主银河系 - 使用地球纹理
const coreMaterial = new THREE.MeshBasicMaterial({ const textureLoader = new THREE.TextureLoader();
color: 0xFFF5E1, // 暖白色 const earthTexture = textureLoader.load('./static/img/planets/earth.jpg');
// 创建地球球体
const earthGeometry = new THREE.SphereGeometry(100, 64, 64);
const earthMaterial = new THREE.MeshBasicMaterial({
map: earthTexture,
transparent: true,
opacity: 0.95,
side: THREE.DoubleSide
});
const earthMesh = new THREE.Mesh(earthGeometry, earthMaterial);
galaxyGroup.add(earthMesh);
// 添加蓝色发光效果层
const glowGeometry = new THREE.SphereGeometry(110, 32, 32);
const glowMaterial = new THREE.MeshBasicMaterial({
color: 0x4169E1, // 蓝色光晕
transparent: true, transparent: true,
opacity: 0.3, opacity: 0.3,
side: THREE.DoubleSide side: THREE.DoubleSide
}); });
const glowMesh = new THREE.Mesh(glowGeometry, glowMaterial);
galaxyGroup.add(glowMesh);
// 创建月球
const moonTexture = textureLoader.load('./static/img/planets/moon.jpg');
const moonGeometry = new THREE.SphereGeometry(25, 32, 32);
const moonMaterial = new THREE.MeshBasicMaterial({
map: moonTexture,
transparent: true,
opacity: 0.9,
side: THREE.DoubleSide
});
const moonMesh = new THREE.Mesh(moonGeometry, moonMaterial);
// 初始位置(离地球更远)
moonMesh.position.set(250, 0, 0);
galaxyGroup.add(moonMesh);
// 存储地球和月球引用用于动画
galaxyGroup.userData = {
earth: earthMesh,
earthRotation: 0,
moon: moonMesh,
moonAngle: 0,
moonRotation: 0
};
} else {
// 其他银河系 - 白色圆球
// 外层白色球体
const coreGeometry = new THREE.SphereGeometry(100, 32, 32);
const coreMaterial = new THREE.MeshBasicMaterial({
color: 0xFFFFFF,
transparent: true,
opacity: 0.35,
side: THREE.DoubleSide
});
const coreMesh = new THREE.Mesh(coreGeometry, coreMaterial); const coreMesh = new THREE.Mesh(coreGeometry, coreMaterial);
galaxyGroup.add(coreMesh); galaxyGroup.add(coreMesh);
// 添加第二层发光(更亮更小) // 中层更亮
const innerCoreGeometry = new THREE.SphereGeometry(40, 32, 32); const innerCoreGeometry = new THREE.SphereGeometry(55, 32, 32);
const innerCoreMaterial = new THREE.MeshBasicMaterial({ const innerCoreMaterial = new THREE.MeshBasicMaterial({
color: 0xFFFBE6, // 更亮的白色 color: 0xFFFFFF,
transparent: true, transparent: true,
opacity: 0.5, opacity: 0.55,
side: THREE.DoubleSide side: THREE.DoubleSide
}); });
const innerCoreMesh = new THREE.Mesh(innerCoreGeometry, innerCoreMaterial); const innerCoreMesh = new THREE.Mesh(innerCoreGeometry, innerCoreMaterial);
galaxyGroup.add(innerCoreMesh); galaxyGroup.add(innerCoreMesh);
// 添加核心光点(最亮) // 核心光点
const coreLightGeometry = new THREE.SphereGeometry(15, 32, 32); const coreLightGeometry = new THREE.SphereGeometry(20, 32, 32);
const coreLightMaterial = new THREE.MeshBasicMaterial({ const coreLightMaterial = new THREE.MeshBasicMaterial({
color: 0xFFFFF0, // 纯白偏黄 color: 0xFFFFFF,
transparent: true, transparent: true,
opacity: 0.7, opacity: 0.8,
side: THREE.DoubleSide side: THREE.DoubleSide
}); });
const coreLightMesh = new THREE.Mesh(coreLightGeometry, coreLightMaterial); const coreLightMesh = new THREE.Mesh(coreLightGeometry, coreLightMaterial);
galaxyGroup.add(coreLightMesh); galaxyGroup.add(coreLightMesh);
} }
}
// 添加星云效果 // 添加星云效果
function addNebulaEffect(galaxyGroup, scale = 1) { function addNebulaEffect(galaxyGroup, scale = 1, galaxyIndex = 0, colorScheme = 'blue') {
const nebulaCount = Math.floor(80 * scale); // 根据缩放调整数量 const nebulaCount = Math.floor(80 * scale); // 根据缩放调整数量
const armCount = galaxyIndex === 0 ? 4 : (galaxyIndex % 2 === 0 ? 4 : 6);
const nebulaGeometry = new THREE.BufferGeometry(); const nebulaGeometry = new THREE.BufferGeometry();
const nebulaPositions = new Float32Array(nebulaCount * 3); const nebulaPositions = new Float32Array(nebulaCount * 3);
const nebulaColors = new Float32Array(nebulaCount * 3); const nebulaColors = new Float32Array(nebulaCount * 3);
const nebulaSizes = new Float32Array(nebulaCount); const nebulaSizes = new Float32Array(nebulaCount);
// 根据配色方案获取星云基础颜色
function getNebulaBaseColor(scheme) {
switch (scheme) {
case 'blue': return [0.4, 0.6, 1.0];
case 'purple': return [0.7, 0.4, 1.0];
case 'cyan': return [0.3, 0.9, 1.0];
case 'pink': return [1.0, 0.5, 0.7];
case 'red': return [1.0, 0.4, 0.4];
case 'green': return [0.4, 0.9, 0.5];
case 'orange': return [1.0, 0.7, 0.3];
case 'white': return [0.9, 0.9, 0.9];
default: return [0.9, 0.7, 0.3];
}
}
const baseColor = getNebulaBaseColor(colorScheme);
for (let i = 0; i < nebulaCount; i++) { for (let i = 0; i < nebulaCount; i++) {
// 主要分布在旋臂区域 // 主要分布在旋臂区域
const armIndex = Math.floor(Math.random() * 4); const armIndex = Math.floor(Math.random() * armCount);
const armAngle = (armIndex / 4) * Math.PI * 2; const armAngle = (armIndex / armCount) * Math.PI * 2;
const r = 150 + Math.pow(Math.random(), 0.3) * 500; const r = 150 + Math.pow(Math.random(), 0.3) * 500;
const spiralTightness = 0.12; const spiralTightness = 0.12;
@@ -688,10 +760,10 @@
nebulaPositions[i * 3 + 1] = (Math.random() - 0.5) * 20; nebulaPositions[i * 3 + 1] = (Math.random() - 0.5) * 20;
nebulaPositions[i * 3 + 2] = r * Math.sin(theta) + offset * Math.sin(theta + Math.PI / 2); nebulaPositions[i * 3 + 2] = r * Math.sin(theta) + offset * Math.sin(theta + Math.PI / 2);
// 暖黄色星云(金黄色,与银河系协调) // 使用银河系配色,带轻微随机变化
nebulaColors[i * 3] = 0.9 + Math.random() * 0.1; nebulaColors[i * 3] = baseColor[0] * (0.8 + Math.random() * 0.4);
nebulaColors[i * 3 + 1] = 0.7 + Math.random() * 0.2; nebulaColors[i * 3 + 1] = baseColor[1] * (0.8 + Math.random() * 0.4);
nebulaColors[i * 3 + 2] = 0.3 + Math.random() * 0.2; nebulaColors[i * 3 + 2] = baseColor[2] * (0.8 + Math.random() * 0.4);
nebulaSizes[i] = 15 + Math.random() * 25; nebulaSizes[i] = 15 + Math.random() * 25;
} }
@@ -881,6 +953,25 @@
galaxyGroups.forEach((galaxyGroup, index) => { galaxyGroups.forEach((galaxyGroup, index) => {
galaxyRotations[index] += 0.0001 + index * 0.00005; // 不同的旋转速度 galaxyRotations[index] += 0.0001 + index * 0.00005; // 不同的旋转速度
galaxyGroup.rotation.y = galaxyRotations[index]; galaxyGroup.rotation.y = galaxyRotations[index];
// 月球围绕地球旋转
if (galaxyGroup.userData && galaxyGroup.userData.moon) {
galaxyGroup.userData.moonAngle += 0.001; // 公转速度(更慢)
galaxyGroup.userData.moonRotation += 0.005; // 自转速度(更慢)
const moonAngle = galaxyGroup.userData.moonAngle;
const moonRadius = 250; // 月球轨道半径(更远)
galaxyGroup.userData.moon.position.x = Math.cos(moonAngle) * moonRadius;
galaxyGroup.userData.moon.position.z = Math.sin(moonAngle) * moonRadius;
galaxyGroup.userData.moon.position.y = Math.sin(moonAngle * 0.5) * 30; // 轻微上下浮动
// 月球自转
galaxyGroup.userData.moon.rotation.y = galaxyGroup.userData.moonRotation;
}
// 地球自转
if (galaxyGroup.userData && galaxyGroup.userData.earth) {
galaxyGroup.userData.earthRotation += 0.002; // 地球自转速度(缓慢)
galaxyGroup.userData.earth.rotation.y = galaxyGroup.userData.earthRotation;
}
}); });
// 更新相机位置 // 更新相机位置