New Chat
Ctrl
K
Kimi+
Chat History

来自分享的会话

Write code for a 3D solar system visualization in JavaScript using Three.js. Include 8 planets with accurate orbits, rotation speeds, and tooltips that display data on hover (e.g., distance from sun, gravity, orbital time). Allow zoom and pan with mouse. Make the scene interactive and educational.
HTML
Preview
Copy
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>3D Solar System</title>
    <style>
        @import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&display=swap');
        
        body {
            margin: 0;
            overflow: hidden;
            background-color: #000;
            font-family: 'Orbitron', monospace;
            cursor: grab;
        }
        
        body:active {
            cursor: grabbing;
        }
        
        #canvas-container {
            position: relative;
            width: 100vw;
            height: 100vh;
        }
        
        #info-panel {
            position: absolute;
            top: 20px;
            left: 20px;
            background: linear-gradient(135deg, rgba(20, 20, 40, 0.9), rgba(10, 10, 30, 0.9));
            color: white;
            padding: 20px;
            border-radius: 15px;
            max-width: 350px;
            display: none;
            border: 1px solid rgba(100, 100, 255, 0.3);
            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
            backdrop-filter: blur(10px);
            animation: fadeIn 0.3s ease-out;
        }
        
        @keyframes fadeIn {
            from {
                opacity: 0;
                transform: translateY(-10px);
            }
            to {
                opacity: 1;
                transform: translateY(0);
            }
        }
        
        #info-panel h3 {
            margin-top: 0;
            color: #4a9eff;
            font-size: 24px;
            text-shadow: 0 0 10px rgba(74, 158, 255, 0.5);
            margin-bottom: 15px;
        }
        
        #info-panel p {
            margin: 8px 0;
            font-size: 14px;
            line-height: 1.4;
        }
        
        #info-panel .label {
            color: #8a8aff;
            font-weight: bold;
            display: inline-block;
            width: 120px;
        }
        
        #info-panel .value {
            color: #ffffff;
        }
        
        .tooltip {
            position: absolute;
            background: linear-gradient(135deg, rgba(0, 0, 0, 0.9), rgba(20, 20, 40, 0.9));
            color: white;
            padding: 10px 15px;
            border-radius: 8px;
            font-size: 14px;
            pointer-events: none;
            display: none;
            border: 1px solid rgba(100, 100, 255, 0.3);
            box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5);
            backdrop-filter: blur(5px);
            animation: tooltipFade 0.2s ease-out;
        }
        
        @keyframes tooltipFade {
            from {
                opacity: 0;
                transform: scale(0.9);
            }
            to {
                opacity: 1;
                transform: scale(1);
            }
        }
        
        #controls {
            position: absolute;
            bottom: 20px;
            left: 50%;
            transform: translateX(-50%);
            background: linear-gradient(135deg, rgba(20, 20, 40, 0.9), rgba(10, 10, 30, 0.9));
            padding: 15px 30px;
            border-radius: 30px;
            border: 1px solid rgba(100, 100, 255, 0.3);
            box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5);
            backdrop-filter: blur(10px);
            text-align: center;
            color: white;
            font-size: 14px;
        }
        
        #speed-controls {
            margin-top: 10px;
        }
        
        #speed-slider {
            width: 150px;
            margin: 0 10px;
            vertical-align: middle;
        }
        
        #speed-value {
            display: inline-block;
            width: 30px;
            text-align: left;
            color: #4a9eff;
        }
        
        #title {
            position: absolute;
            top: 20px;
            right: 20px;
            color: white;
            text-align: right;
        }
        
        #title h1 {
            margin: 0;
            font-size: 36px;
            font-weight: 900;
            background: linear-gradient(135deg, #4a9eff, #8a8aff);
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            text-shadow: 0 0 30px rgba(74, 158, 255, 0.5);
        }
        
        #title p {
            margin: 5px 0 0 0;
            font-size: 14px;
            color: #8a8aff;
            opacity: 0.8;
        }
        
        .planet-label {
            position: absolute;
            color: white;
            font-size: 12px;
            pointer-events: none;
            text-shadow: 0 0 5px rgba(0, 0, 0, 0.8);
            opacity: 0.7;
        }
    </style>
</head>
<body>
    <div id="canvas-container">
        <div id="info-panel"></div>
        <div class="tooltip"></div>
        <div id="controls">
            <div>Mouse: Rotate | Scroll: Zoom | Shift+Drag: Pan</div>
            <div id="speed-controls">
                Speed: <input type="range" id="speed-slider" min="0" max="5" value="1" step="0.1">
                <span id="speed-value">1x</span>
            </div>
        </div>
        <div id="title">
            <h1>SOLAR SYSTEM</h1>
            <p>Interactive 3D Visualization</p>
        </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/[email protected]/build/three.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/controls/OrbitControls.js"></script>
    <script>
        // Speed control
        let speedMultiplier = 1;
        const speedSlider = document.getElementById('speed-slider');
        const speedValue = document.getElementById('speed-value');
        
        speedSlider.addEventListener('input', (e) => {
            speedMultiplier = parseFloat(e.target.value);
            speedValue.textContent = speedMultiplier + 'x';
        });

        // Planet data
        const planetData = {
            mercury: {
                name: "Mercury",
                radius: 0.38,
                distance: 5.8,
                orbitPeriod: 0.24,
                rotationPeriod: 58.6,
                color: 0xC0C0C0,
                gravity: "3.7 m/s²",
                moons: 0,
                temperature: "430°C (day) / -180°C (night)",
                texture: "https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/planets/mercury.jpg"
            },
            venus: {
                name: "Venus",
                radius: 0.95,
                distance: 10.8,
                orbitPeriod: 0.62,
                rotationPeriod: -243,
                color: 0xFFA500,
                gravity: "8.87 m/s²",
                moons: 0,
                temperature: "462°C (average)",
                texture: "https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/planets/venus.jpg"
            },
            earth: {
                name: "Earth",
                radius: 1,
                distance: 15,
                orbitPeriod: 1,
                rotationPeriod: 1,
                color: 0x0000FF,
                gravity: "9.8 m/s²",
                moons: 1,
                temperature: "15°C (average)",
                texture: "https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/planets/earth.jpg"
            },
            mars: {
                name: "Mars",
                radius: 0.53,
                distance: 22.8,
                orbitPeriod: 1.88,
                rotationPeriod: 1.03,
                color: 0xFF4500,
                gravity: "3.71 m/s²",
                moons: 2,
                temperature: "-63°C (average)",
                texture: "https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/planets/mars.jpg"
            },
            jupiter: {
                name: "Jupiter",
                radius: 11.2,
                distance: 77.8,
                orbitPeriod: 11.86,
                rotationPeriod: 0.41,
                color: 0xFFA500,
                gravity: "24.79 m/s²",
                moons: 79,
                temperature: "-108°C (cloud top)",
                texture: "https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/planets/jupiter.jpg"
            },
            saturn: {
                name: "Saturn",
                radius: 9.45,
                distance: 143,
                orbitPeriod: 29.46,
                rotationPeriod: 0.45,
                color: 0xFFD700,
                gravity: "10.44 m/s²",
                moons: 82,
                temperature: "-139°C (cloud top)",
                texture: "https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/planets/saturn.jpg"
            },
            uranus: {
                name: "Uranus",
                radius: 4.0,
                distance: 287.1,
                orbitPeriod: 84.01,
                rotationPeriod: -0.72,
                color: 0x00FFFF,
                gravity: "8.69 m/s²",
                moons: 27,
                temperature: "-197°C (cloud top)",
                texture: "https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/planets/uranus.jpg"
            },
            neptune: {
                name: "Neptune",
                radius: 3.88,
                distance: 449.5,
                orbitPeriod: 164.8,
                rotationPeriod: 0.67,
                color: 0x0000FF,
                gravity: "11.15 m/s²",
                moons: 14,
                temperature: "-200°C (cloud top)",
                texture: "https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/planets/neptune.jpg"
            }
        };

        // Initialize scene
        const scene = new THREE.Scene();
        scene.fog = new THREE.FogExp2(0x000000, 0.00000025);
        
        // Camera setup
        const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
        camera.position.set(0, 30, 50);
        
        // Renderer setup
        const renderer = new THREE.WebGLRenderer({ antialias: true });
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.setPixelRatio(window.devicePixelRatio);
        document.getElementById('canvas-container').appendChild(renderer.domElement);
        
        // Controls
        const controls = new THREE.OrbitControls(camera, renderer.domElement);
        controls.enableDamping = true;
        controls.dampingFactor = 0.05;
        controls.minDistance = 5;
        controls.maxDistance = 500;
        
        // Lighting
        const ambientLight = new THREE.AmbientLight(0x404040, 0.5);
        scene.add(ambientLight);
        
        const sunLight = new THREE.PointLight(0xffffff, 2, 1000);
        sunLight.castShadow = true;
        scene.add(sunLight);
        
        // Add rim lighting for planets
        const rimLight = new THREE.DirectionalLight(0x4444ff, 0.3);
        rimLight.position.set(100, 100, 100);
        scene.add(rimLight);
        
        // Create sun
        const sunGeometry = new THREE.SphereGeometry(3, 64, 64);
        const sunMaterial = new THREE.MeshBasicMaterial({ 
            color: 0xffff00,
            emissive: 0xffff00,
            emissiveIntensity: 1
        });
        const sun = new THREE.Mesh(sunGeometry, sunMaterial);
        scene.add(sun);
        
        // Add glow to sun
        const sunGlowGeometry = new THREE.SphereGeometry(4, 32, 32);
        const sunGlowMaterial = new THREE.MeshBasicMaterial({
            color: 0xffaa00,
            transparent: true,
            opacity: 0.3,
            side: THREE.BackSide
        });
        const sunGlow = new THREE.Mesh(sunGlowGeometry, sunGlowMaterial);
        sun.add(sunGlow);
        
        // Add sun corona
        const coronaGeometry = new THREE.SphereGeometry(5, 32, 32);
        const coronaMaterial = new THREE.ShaderMaterial({
            uniforms: {
                time: { value: 0 }
            },
            vertexShader: `
                varying vec3 vNormal;
                void main() {
                    vNormal = normalize(normalMatrix * normal);
                    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
                }
            `,
            fragmentShader: `
                uniform float time;
                varying vec3 vNormal;
                void main() {
                    float intensity = pow(0.6 - dot(vNormal, vec3(0.0, 0.0, 1.0)), 2.0);
                    gl_FragColor = vec4(1.0, 0.6, 0.0, 1.0) * intensity * (1.0 + 0.2 * sin(time));
                }
            `,
            side: THREE.BackSide,
            blending: THREE.AdditiveBlending,
            transparent: true
        });
        const corona = new THREE.Mesh(coronaGeometry, coronaMaterial);
        sun.add(corona);
        
        // Create planets
        const planets = {};
        const planetMeshes = [];
        const textureLoader = new THREE.TextureLoader();
        
        // Create starfield
        const starsGeometry = new THREE.BufferGeometry();
        const starsMaterial = new THREE.PointsMaterial({
            color: 0xFFFFFF,
            size: 0.7,
            sizeAttenuation: true,
            blending: THREE.AdditiveBlending
        });
        
        const starsVertices = [];
        for (let i = 0; i < 10000; i++) {
            const x = THREE.MathUtils.randFloatSpread(2000);
            const y = THREE.MathUtils.randFloatSpread(2000);
            const z = THREE.MathUtils.randFloatSpread(2000);
            starsVertices.push(x, y, z);
        }
        
        starsGeometry.setAttribute('position', new THREE.Float32BufferAttribute(starsVertices, 3));
        const starField = new THREE.Points(starsGeometry, starsMaterial);
        scene.add(starField);
        
        // Create planets and orbits
        Object.keys(planetData).forEach(planetKey => {
            const planet = planetData[planetKey];
            
            // Create orbit
            const orbitGeometry = new THREE.RingGeometry(planet.distance, planet.distance + 0.05, 128);
            const orbitMaterial = new THREE.MeshBasicMaterial({
                color: 0x444444,
                side: THREE.DoubleSide,
                transparent: true,
                opacity: 0.3
            });
            const orbit = new THREE.Mesh(orbitGeometry, orbitMaterial);
            orbit.rotation.x = Math.PI / 2;
            scene.add(orbit);
            
            // Create planet
            const planetGeometry = new THREE.SphereGeometry(planet.radius, 64, 64);
            const planetMaterial = new THREE.MeshPhongMaterial({
                map: textureLoader.load(planet.texture)
            });
            
            const planetMesh = new THREE.Mesh(planetGeometry, planetMaterial);
            planetMesh.userData = {
                planetKey: planetKey,
                name: planet.name,
                distance: planet.distance + " million km",
                gravity: planet.gravity,
                moons: planet.moons,
                temperature: planet.temperature,
                orbitPeriod: planet.orbitPeriod + " Earth years",
                rotationPeriod: Math.abs(planet.rotationPeriod) + " Earth days" + (planet.rotationPeriod < 0 ? " (retrograde)" : ""),
                objectType: 'planet'
            };
            
            // Add rings to Saturn
            if (planetKey === 'saturn') {
                const ringGeometry = new THREE.RingGeometry(planet.radius * 1.2, planet.radius * 2, 64);
                const ringMaterial = new THREE.MeshBasicMaterial({
                    color: 0xFFD700,
                    side: THREE.DoubleSide,
                    transparent: true,
                    opacity: 0.6
                });
                const rings = new THREE.Mesh(ringGeometry, ringMaterial);
                rings.rotation.x = Math.PI / 2;
                planetMesh.add(rings);
            }
            
            // Create planet orbit container
            const planetOrbit = new THREE.Object3D();
            planetOrbit.add(planetMesh);
            scene.add(planetOrbit);
            
            // Position planet
            planetMesh.position.x = planet.distance;
            
            planets[planetKey] = {
                mesh: planetMesh,
                orbit: planetOrbit,
                data: planet
            };
            
            planetMeshes.push(planetMesh);
        });
        
        // Raycaster for interaction
        const raycaster = new THREE.Raycaster();
        const mouse = new THREE.Vector2();
        const tooltip = document.querySelector('.tooltip');
        const infoPanel = document.getElementById('info-panel');
        
        // Handle mouse move
        function onMouseMove(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(planetMeshes);
            
            if (intersects.length > 0) {
                const planet = intersects[0].object;
                const data = planet.userData;
                
                // Show tooltip
                tooltip.style.display = 'block';
                tooltip.style.left = `${event.clientX + 10}px`;
                tooltip.style.top = `${event.clientY + 10}px`;
                tooltip.innerHTML = `<strong>${data.name}</strong><br>Click for details`;
                
                document.body.style.cursor = 'pointer';
            } else {
                tooltip.style.display = 'none';
                document.body.style.cursor = 'default';
            }
        }
        
        // Handle click
        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(planetMeshes);
            
            if (intersects.length > 0) {
                const planet = intersects[0].object;
                const data = planet.userData;
                
                // Show info panel
                infoPanel.style.display = 'block';
                infoPanel.innerHTML = `
                    <h3>${data.name}</h3>
                    <p><span class="label">Distance from Sun:</span> <span class="value">${data.distance}</span></p>
                    <p><span class="label">Gravity:</span> <span class="value">${data.gravity}</span></p>
                    <p><span class="label">Orbital Period:</span> <span class="value">${data.orbitPeriod}</span></p>
                    <p><span class="label">Rotation Period:</span> <span class="value">${data.rotationPeriod}</span></p>
                    <p><span class="label">Number of Moons:</span> <span class="value">${data.moons}</span></p>
                    <p><span class="label">Temperature:</span> <span class="value">${data.temperature}</span></p>
                `;
            } else {
                infoPanel.style.display = 'none';
            }
        }
        
        window.addEventListener('mousemove', onMouseMove);
        window.addEventListener('click', onClick);
        
        // Handle window resize
        function onWindowResize() {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        }
        
        window.addEventListener('resize', onWindowResize);
        
        // Animation loop
        const clock = new THREE.Clock();
        
        function animate() {
            requestAnimationFrame(animate);
            
            const elapsedTime = clock.getElapsedTime();
            const speed = speedMultiplier;
            
            // Rotate sun
            sun.rotation.y = elapsedTime * 0.1;
            
            // Update corona shader
            corona.material.uniforms.time.value = elapsedTime;
            
            // Update planets
            Object.keys(planets).forEach(planetKey => {
                const planet = planets[planetKey];
                
                // Orbit around the sun
                planet.orbit.rotation.y = elapsedTime * (1 / planet.data.orbitPeriod) * 0.5 * speed;
                
                // Rotate the planet
                planet.mesh.rotation.y = elapsedTime * (1 / planet.data.rotationPeriod) * 5 * speed;
            });
            
            controls.update();
            renderer.render(scene, camera);
        }
        
        animate();
    </script>
</body>
</html>