diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 8eabd86..b2ccee3 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -3,7 +3,21 @@ "allow": [ "mcp__Claude_Preview__preview_start", "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)" ] } } diff --git a/static/css/galaxy.css b/static/css/galaxy.css index bdd5c3c..d0f742a 100644 --- a/static/css/galaxy.css +++ b/static/css/galaxy.css @@ -161,102 +161,15 @@ position: absolute; top: 0; left: 0; - width: 100%; - height: 100%; - background-image: - /* 第一大区域 - 各种随机位置和大小 */ - radial-gradient(1px 1px at 5px 15px, #fff, transparent), - 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; + right: 0; + bottom: 0; + background-image: url('../img/planets/bg.jpg'); + background-size: cover; + background-position: center; pointer-events: none; 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 { width: 100%; height: 100%; diff --git a/static/img/planets/bg.jpg b/static/img/planets/bg.jpg new file mode 100644 index 0000000..6f44e9e Binary files /dev/null and b/static/img/planets/bg.jpg differ diff --git a/static/img/planets/earth.jpg b/static/img/planets/earth.jpg new file mode 100644 index 0000000..e673a7c Binary files /dev/null and b/static/img/planets/earth.jpg differ diff --git a/static/img/planets/moon.jpg b/static/img/planets/moon.jpg new file mode 100644 index 0000000..d4aa5e6 Binary files /dev/null and b/static/img/planets/moon.jpg differ diff --git a/static/js/galaxy.js b/static/js/galaxy.js index 2afca77..442d7fc 100644 --- a/static/js/galaxy.js +++ b/static/js/galaxy.js @@ -213,21 +213,21 @@ galaxyGroups = []; galaxyRotations = []; - // 创建9个银河系(合理距离,多种角度) + // 创建9个银河系(合理距离,多种角度,大胆倾斜,保持足够距离) const galaxyPositions = [ - // 中心主银河系 + // 中心主银河系 - 横着正常显示 { x: 0, y: 0, z: 0, scale: 1.0, rotX: 0, rotZ: 0 }, - // 前面银河系(z正方向) - { x: 500, y: 200, z: 600, scale: 0.7, rotX: 0.1, rotZ: -0.05 }, - { x: -400, y: 350, z: 500, scale: 0.65, rotX: -0.08, rotZ: 0.12 }, - { x: 300, y: -250, z: 700, scale: 0.6, rotX: 0.15, rotZ: -0.1 }, - // 近距离(600-900单位) - { x: 700, y: 200, z: -500, scale: 0.75, rotX: 0.1, rotZ: -0.05 }, - { x: -600, y: -350, z: -400, scale: 0.7, rotX: -0.08, rotZ: 0.12 }, - // 中距离(1000-1500单位) - { x: 1200, y: 500, z: -1000, scale: 0.6, rotX: 0.15, rotZ: -0.1 }, - { x: -1100, y: 400, z: -900, scale: 0.55, rotX: -0.12, rotZ: 0.08 }, - { x: 400, y: -900, z: -800, scale: 0.65, rotX: 0.05, rotZ: 0.15 }, + // 前面银河系(z正方向)- 距离主银河系1200+ + { x: 900, y: 350, z: 1100, scale: 0.7, rotX: -0.4, rotZ: 0.6 }, + { x: -800, y: 600, z: 1000, scale: 0.65, rotX: 0.5, rotZ: -0.3 }, + { x: 600, y: -500, z: 1200, scale: 0.6, rotX: -0.7, rotZ: 0.4 }, + // 近距离(1300-1600单位) + { x: 1300, y: 400, z: -900, scale: 0.75, rotX: 0.8, rotZ: -0.5 }, + { x: -1200, y: -600, z: -800, scale: 0.7, rotX: -0.3, rotZ: 0.7 }, + // 中距离(1800-2200单位) + { x: 2000, y: 800, z: -1700, scale: 0.6, rotX: 0.6, rotZ: -0.8 }, + { x: -1900, y: 700, z: -1600, scale: 0.55, rotX: -0.5, rotZ: 0.4 }, + { x: 700, y: -1600, z: -1400, scale: 0.65, rotX: 0.9, rotZ: -0.6 }, ]; galaxyPositions.forEach((pos, index) => { @@ -307,9 +307,30 @@ function createPhotoStar(photo, index, galaxyGroup) { // 创建圆形纹理 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); // 创建材质 - 无滤镜 @@ -323,27 +344,46 @@ // 创建网格 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 theta = Math.random() * Math.PI * 2; const phi = (Math.random() - 0.5) * Math.PI * 0.3; // 扁平分布 - star.position.x = radius * Math.cos(theta) * Math.cos(phi); - star.position.y = radius * Math.sin(phi) * 0.3; // 更扁平 - star.position.z = radius * Math.sin(theta) * Math.cos(phi); + const x = radius * Math.cos(theta) * Math.cos(phi); + const y = radius * Math.sin(phi) * 0.3; // 更扁平 + 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, photoSrc: photo.src, photoFilename: photo.filename }; + star.userData = userData; + hitArea.userData = userData; // 面向相机 star.lookAt(camera.position); + hitArea.lookAt(camera.position); + // 将点击检测区域添加到组中 + galaxyGroup.add(hitArea); galaxyGroup.add(star); stars.push(star); + stars.push(hitArea); // 也添加到检测数组中 } // 创建默认星星 @@ -373,21 +413,21 @@ // 添加装饰性星星(银河系效果) 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 positions = new Float32Array(starCount * 3); const colors = new Float32Array(starCount * 3); const sizes = new Float32Array(starCount); // 银河系参数 - const bulgeRadius = 120; // 银核半径 - const diskRadius = 700; // 银盘半径 - const armCount = 4; // 旋臂数量 - const spiralAngle = 12; // 螺旋角(度) - const spiralTightness = 0.005; // 螺旋紧密度 + const bulgeRadius = 150; // 银核半径 + const diskRadius = 600; // 银盘半径 + const armCount = galaxyIndex === 0 ? 4 : (galaxyIndex % 2 === 0 ? 4 : 6); // 主银河4条,其他4或6条 + const spin = 0.3; // 旋臂旋转角度 + const radialRandomness = 0.4; // 径向随机性 - // 根据银河系索引选择配色方案 - const colorScheme = galaxyIndex === 0 ? 'warm' : getColorScheme(galaxyIndex); + // 根据银河系索引选择配色方案(主银河系用蓝色调) + const colorScheme = galaxyIndex === 0 ? 'blue' : getColorScheme(galaxyIndex); // 获取银河系配色方案 function getColorScheme(index) { @@ -414,195 +454,157 @@ } // 根据配色方案获取颜色 - function getColor(scheme, brightness, distanceFromCenter) { + function getColor(scheme, radiusRatio) { let color; + const t = radiusRatio; // 0=中心,1=边缘 switch (scheme) { - case 'warm': // 主银河系 - 暖黄色(不淡化) - if (distanceFromCenter < 0.3) { - 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 'warm': // 主银河系 - 暖黄色 + return [1, 0.9 - t * 0.3, 0.6 - t * 0.4]; // 橙到紫 - case 'blue': // 蓝色系(淡化) - if (distanceFromCenter < 0.3) { - 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]; - } + case 'blue': + color = [0.3, 0.5 + t * 0.3, 0.9 - t * 0.2]; return fadeColor(color, 0.45); - case 'purple': // 紫色系(淡化) - if (distanceFromCenter < 0.3) { - 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]; - } + case 'purple': + color = [0.7 - t * 0.3, 0.3, 0.9 - t * 0.1]; return fadeColor(color, 0.45); - case 'cyan': // 青色系(淡化) - if (distanceFromCenter < 0.3) { - 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]; - } + case 'cyan': + color = [0.2, 0.8 - t * 0.3, 0.9 - t * 0.2]; return fadeColor(color, 0.45); - case 'pink': // 粉色系(淡化) - if (distanceFromCenter < 0.3) { - 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]; - } + case 'pink': + color = [0.9 - t * 0.2, 0.4 + t * 0.1, 0.6 - t * 0.2]; return fadeColor(color, 0.45); - case 'red': // 红色系(淡化) - if (distanceFromCenter < 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]; - } + case 'red': + color = [0.9 - t * 0.2, 0.3 + t * 0.1, 0.3]; return fadeColor(color, 0.45); - case 'green': // 绿色系(淡化) - if (distanceFromCenter < 0.3) { - 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]; - } + case 'green': + color = [0.3, 0.8 - t * 0.2, 0.4 + t * 0.1]; return fadeColor(color, 0.45); - case 'orange': // 橙色系(淡化) - if (distanceFromCenter < 0.3) { - 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]; - } + case 'orange': + color = [0.9 - t * 0.2, 0.6 - t * 0.3, 0.2 + t * 0.1]; return fadeColor(color, 0.45); - case 'white': // 白色系(已经是淡色,稍微淡化) - if (distanceFromCenter < 0.3) { - color = [0.9 + brightness * 0.1, 0.9 + brightness * 0.1, 0.9 + brightness * 0.1]; - } 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); // 白色系淡化程度低一些 + case 'white': + color = [0.9 - t * 0.2, 0.9 - t * 0.2, 0.9 - t * 0.2]; + return fadeColor(color, 0.3); default: - color = [1, 1, 1]; - return color; + return [1, 0.9 - t * 0.3, 0.6 - t * 0.4]; } } - for (let i = 0; i < starCount; i++) { - let x, y, z, brightness; + // 随机极坐标(用于径向偏移) + 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++) { + let x, y, z, brightness, color; - // 根据概率分配 const rand = Math.random(); - if (rand < 0.15) { - // ==================== 银核(15%)==================== - // 非常明亮的圆球区域,大量星星密集分布 - - // 使用球形分布,中心密度最高 - const r = Math.pow(Math.random(), 0.2) * bulgeRadius; // 高度集中在中心 + if (rand < 0.12) { + // ==================== 银核(12%)==================== + // 非常明亮的圆球区域,厚实密集 + const r = Math.pow(Math.random(), 0.3) * bulgeRadius; 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); - y = r * Math.cos(phi) * 0.5; // 稍微扁平一些 + y = r * Math.cos(phi) * 0.6; // 稍微扁平 z = r * Math.sin(phi) * Math.sin(theta); - // 银核非常亮,中心最亮 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 armBaseAngle = (armIndex / armCount) * Math.PI * 2; + const armIndex = i % armCount; + 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 gaussianRandom = (Math.random() + Math.random() + Math.random()) / 3 - 0.5; - const offset = gaussianRandom * armWidth * 0.5; + // 径向随机偏移(让旋臂更粗壮) + const randRadius = Math.random() * radialRandomness * radius * 0.5; + const randOffset = getRandomPolarCoordinate(randRadius); // 计算位置 - const angle = spiralTheta; - x = distance * Math.cos(angle) + offset * Math.cos(angle + Math.PI / 2); - z = distance * Math.sin(angle) + offset * Math.sin(angle + Math.PI / 2); + x = radius * Math.cos(branchAngle + spinAngle) + randOffset.x; + z = radius * Math.sin(branchAngle + spinAngle) + randOffset.z; + 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); - sizes[i] = 1.5 + Math.random() * 2; + // 颜色从内到外渐变 + color = getColor(colorScheme, radiusRatio); } else { - // ==================== 背景星星(30%)==================== - // 随机分布,但避开旋臂区域(相对稀疏) + // ==================== 旋臂之间(70%)==================== + // 随机分布在银盘上,不在旋臂上 - const distance = bulgeRadius + Math.random() * (diskRadius - bulgeRadius); + // 从银核向外的距离 + const radius = bulgeRadius + Math.random() * (diskRadius - bulgeRadius); + + // 随机角度(不跟随旋臂) const theta = Math.random() * Math.PI * 2; - x = distance * Math.cos(theta); - z = distance * Math.sin(theta); - y = (Math.random() - 0.5) * 50; // 扁平分布 + // 随机偏移 + const randOffset = getRandomPolarCoordinate(radius * 0.15); - // 背景较暗 - brightness = Math.max(0.2, 0.5 - distance / diskRadius * 0.3); - sizes[i] = 0.5 + Math.random() * 1; + // 计算位置 + x = radius * Math.cos(theta) + randOffset.x; + 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 + 1] = y; positions[i * 3 + 2] = z; - // 设置颜色(根据配色方案) - const distanceFromCenter = Math.sqrt(x * x + y * y + z * z) / bulgeRadius; - const color = getColor(colorScheme, brightness, distanceFromCenter); - 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; - } + colors[i * 3] = color[0] * brightness; + colors[i * 3 + 1] = color[1] * brightness; + colors[i * 3 + 2] = color[2] * brightness; sizes[i] *= brightness; } @@ -623,61 +625,131 @@ const starField = new THREE.Points(starGeometry, starMaterial); galaxyGroup.add(starField); - // 添加银核发光球体 - addGalacticCore(galaxyGroup, scale); + // 添加银核发光球体(使用不同的行星样式) + addGalacticCore(galaxyGroup, scale, galaxyIndex); // 添加星云效果 - addNebulaEffect(galaxyGroup, scale); + addNebulaEffect(galaxyGroup, scale, galaxyIndex, colorScheme); } // 添加银核发光球体 - function addGalacticCore(galaxyGroup, scale = 1) { - // 创建一个明亮的发光球体作为银核 - const coreGeometry = new THREE.SphereGeometry(80, 32, 32); - const coreMaterial = new THREE.MeshBasicMaterial({ - color: 0xFFF5E1, // 暖白色 - transparent: true, - opacity: 0.3, - side: THREE.DoubleSide - }); - const coreMesh = new THREE.Mesh(coreGeometry, coreMaterial); - galaxyGroup.add(coreMesh); + function addGalacticCore(galaxyGroup, scale = 1, galaxyIndex = 0) { + if (galaxyIndex === 0) { + // 主银河系 - 使用地球纹理 + const textureLoader = new THREE.TextureLoader(); + const earthTexture = textureLoader.load('./static/img/planets/earth.jpg'); - // 添加第二层发光(更亮更小) - const innerCoreGeometry = new THREE.SphereGeometry(40, 32, 32); - const innerCoreMaterial = new THREE.MeshBasicMaterial({ - color: 0xFFFBE6, // 更亮的白色 - transparent: true, - opacity: 0.5, - side: THREE.DoubleSide - }); - const innerCoreMesh = new THREE.Mesh(innerCoreGeometry, innerCoreMaterial); - galaxyGroup.add(innerCoreMesh); + // 创建地球球体 + 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 coreLightGeometry = new THREE.SphereGeometry(15, 32, 32); - const coreLightMaterial = new THREE.MeshBasicMaterial({ - color: 0xFFFFF0, // 纯白偏黄 - transparent: true, - opacity: 0.7, - side: THREE.DoubleSide - }); - const coreLightMesh = new THREE.Mesh(coreLightGeometry, coreLightMaterial); - galaxyGroup.add(coreLightMesh); + // 添加蓝色发光效果层 + const glowGeometry = new THREE.SphereGeometry(110, 32, 32); + const glowMaterial = new THREE.MeshBasicMaterial({ + color: 0x4169E1, // 蓝色光晕 + transparent: true, + opacity: 0.3, + 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); + galaxyGroup.add(coreMesh); + + // 中层更亮 + const innerCoreGeometry = new THREE.SphereGeometry(55, 32, 32); + const innerCoreMaterial = new THREE.MeshBasicMaterial({ + color: 0xFFFFFF, + transparent: true, + opacity: 0.55, + side: THREE.DoubleSide + }); + const innerCoreMesh = new THREE.Mesh(innerCoreGeometry, innerCoreMaterial); + galaxyGroup.add(innerCoreMesh); + + // 核心光点 + const coreLightGeometry = new THREE.SphereGeometry(20, 32, 32); + const coreLightMaterial = new THREE.MeshBasicMaterial({ + color: 0xFFFFFF, + transparent: true, + opacity: 0.8, + side: THREE.DoubleSide + }); + const coreLightMesh = new THREE.Mesh(coreLightGeometry, coreLightMaterial); + galaxyGroup.add(coreLightMesh); + } } // 添加星云效果 - function addNebulaEffect(galaxyGroup, scale = 1) { + function addNebulaEffect(galaxyGroup, scale = 1, galaxyIndex = 0, colorScheme = 'blue') { const nebulaCount = Math.floor(80 * scale); // 根据缩放调整数量 + const armCount = galaxyIndex === 0 ? 4 : (galaxyIndex % 2 === 0 ? 4 : 6); const nebulaGeometry = new THREE.BufferGeometry(); const nebulaPositions = new Float32Array(nebulaCount * 3); const nebulaColors = new Float32Array(nebulaCount * 3); 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++) { // 主要分布在旋臂区域 - const armIndex = Math.floor(Math.random() * 4); - const armAngle = (armIndex / 4) * Math.PI * 2; + const armIndex = Math.floor(Math.random() * armCount); + const armAngle = (armIndex / armCount) * Math.PI * 2; const r = 150 + Math.pow(Math.random(), 0.3) * 500; const spiralTightness = 0.12; @@ -688,10 +760,10 @@ nebulaPositions[i * 3 + 1] = (Math.random() - 0.5) * 20; 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 + 1] = 0.7 + Math.random() * 0.2; - nebulaColors[i * 3 + 2] = 0.3 + Math.random() * 0.2; + // 使用银河系配色,带轻微随机变化 + nebulaColors[i * 3] = baseColor[0] * (0.8 + Math.random() * 0.4); + nebulaColors[i * 3 + 1] = baseColor[1] * (0.8 + Math.random() * 0.4); + nebulaColors[i * 3 + 2] = baseColor[2] * (0.8 + Math.random() * 0.4); nebulaSizes[i] = 15 + Math.random() * 25; } @@ -881,6 +953,25 @@ galaxyGroups.forEach((galaxyGroup, index) => { galaxyRotations[index] += 0.0001 + index * 0.00005; // 不同的旋转速度 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; + } }); // 更新相机位置