3d视界plusedit icon

作者:
邓朝元
Fork(复制)
下载
嵌入
BUG反馈
index.html
现在支持上传本地图片了!
index.html
            
            <!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <title>From Monotony to Splendor - 3D World</title>
    <style>
        body {
            margin: 0;
            padding: 0;
            overflow: hidden;
            background: #000;
            font-family: Arial, sans-serif;
        }
        
        #container {
            position: relative;
            width: 100vw;
            height: 100vh;
        }
        
        #startScreen {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            background: #000;
            z-index: 100;
            transition: opacity 2s ease-in-out;
        }
        
        #title {
            color: white;
            font-size: 36px;
            margin-bottom: 30px;
            text-align: center;
        }
        
        .mode-button {
            padding: 15px 30px;
            font-size: 20px;
            background: #fff;
            border: none;
            border-radius: 50px;
            cursor: pointer;
            color: #000;
            font-weight: bold;
            margin: 15px;
            transition: all 0.3s ease;
            width: 250px;
        }
        
        .mode-button:hover {
            transform: scale(1.1);
            box-shadow: 0 0 20px rgba(255, 255, 255, 0.5);
        }
        
        #languageToggle {
            position: absolute;
            top: 20px;
            right: 20px;
            padding: 10px 20px;
            background: rgba(255, 255, 255, 0.2);
            border: 1px solid white;
            color: white;
            border-radius: 20px;
            cursor: pointer;
            font-size: 14px;
        }
        
        canvas {
            display: block;
        }
        
        #modeInfo {
            position: absolute;
            top: 20px;
            left: 20px;
            color: white;
            font-family: Arial, sans-serif;
            font-size: 16px;
            z-index: 10;
            background: rgba(0,0,0,0.5);
            padding: 10px;
            border-radius: 5px;
        }
        
        #controls {
            position: absolute;
            bottom: 20px;
            right: 20px;
            color: white;
            font-family: Arial, sans-serif;
            font-size: 14px;
            z-index: 10;
            background: rgba(0,0,0,0.5);
            padding: 10px;
            border-radius: 5px;
            text-align: center;
        }
        
        #musicInfo {
            position: absolute;
            top: 60px;
            right: 20px;
            color: white;
            font-family: Arial, sans-serif;
            font-size: 12px;
            z-index: 10;
            background: rgba(0,0,0,0.5);
            padding: 10px;
            border-radius: 5px;
            max-width: 200px;
        }
        
        .hidden {
            display: none !important;
        }
    </style>
</head>
<body>
    <div id="container">
        <div id="startScreen">
            <div id="title">探索深邃的3D世界</div>
            <button class="mode-button" id="freeMode">自由探索模式</button>
            <button class="mode-button" id="touchMode">触控移动模式</button>
        </div>
        <!-- Three.js 将在这里渲染 -->
    </div>
    
    <button id="languageToggle">English</button>
    
    <div id="modeInfo" class="hidden">
        <span id="currentMode">当前模式: </span>
    </div>
    
    <div id="controls" class="hidden">
        <div id="freeControls">
            自动旋转<br>
            按住鼠标拖拽旋转
        </div>
        <div id="touchControls" class="hidden">
            滑动屏幕移动视角<br>
            双指缩放
        </div>
    </div>
    
    <div id="musicInfo" class="hidden">
        背景音乐: <span id="musicTitle">深邃空间 - Kevin MacLeod</span><br>
        来源: Incompetech.com (Creative Commons)
    </div>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
    <script>
        // 语言配置
        const languages = {
            'zh-CN': {
                title: '探索深邃的3D世界',
                freeMode: '自由探索模式',
                touchMode: '触控移动模式',
                currentMode: '当前模式: ',
                freeModeText: '自由探索模式',
                touchModeText: '触控移动模式',
                freeControls: '自动旋转<br>按住鼠标拖拽旋转',
                touchControls: '滑动屏幕移动视角<br>双指缩放',
                musicTitle: '深邃空间 - Kevin MacLeod',
                musicSource: '来源: Incompetech.com (Creative Commons)'
            },
            'en': {
                title: 'Explore the Profound 3D World',
                freeMode: 'Free Exploration Mode',
                touchMode: 'Touch Control Mode',
                currentMode: 'Current Mode: ',
                freeModeText: 'Free Exploration Mode',
                touchModeText: 'Touch Control Mode',
                freeControls: 'Auto Rotation<br>Drag to rotate',
                touchControls: 'Swipe to move view<br>Pinch to zoom',
                musicTitle: 'Deep Space - Kevin MacLeod',
                musicSource: 'Source: Incompetech.com (Creative Commons)'
            }
        };
        
        let currentLanguage = 'zh-CN';
        
        // 初始化变量
        let scene, camera, renderer;
        let particles, geometry, material;
        let startScreen, freeModeButton, touchModeButton, languageToggle;
        let animationId;
        let time = 0;
        let isTransitioning = false;
        let currentMode = 'free'; // 'free' or 'touch'
        
        // 相机控制变量
        let isMouseDown = false;
        let mouseX = 0, mouseY = 0;
        let targetRotationX = 0, targetRotationY = 0;
        let rotationX = 0, rotationY = 0;
        
        // 触控变量
        let touchStartX = 0, touchStartY = 0;
        let touchStartDistance = 0;
        let cameraDistance = 15;
        
        // 音频元素
        let audio;
        
        // 初始化场景
        function init() {
            // 创建场景
            scene = new THREE.Scene();
            scene.background = new THREE.Color(0x000000);
            
            // 创建相机
            camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 2000);
            camera.position.z = cameraDistance;
            
            // 创建渲染器
            renderer = new THREE.WebGLRenderer({ antialias: true });
            renderer.setSize(window.innerWidth, window.innerHeight);
            renderer.setPixelRatio(window.devicePixelRatio);
            document.getElementById('container').appendChild(renderer.domElement);
            
            // 创建粒子系统
            createParticleSystem();
            
            // 添加光源
            const ambientLight = new THREE.AmbientLight(0x222222);
            scene.add(ambientLight);
            
            const pointLight = new THREE.PointLight(0x333366, 0.5, 100);
            pointLight.position.set(0, 0, 0);
            scene.add(pointLight);
            
            // 隐藏开始屏幕
            startScreen = document.getElementById('startScreen');
            freeModeButton = document.getElementById('freeMode');
            touchModeButton = document.getElementById('touchMode');
            languageToggle = document.getElementById('languageToggle');
            
            freeModeButton.addEventListener('click', () => startTransition('free'));
            touchModeButton.addEventListener('click', () => startTransition('touch'));
            languageToggle.addEventListener('click', toggleLanguage);
            
            // 添加事件监听器
            addEventListeners();
            
            // 窗口大小调整
            window.addEventListener('resize', onWindowResize);
            
            // 初始化音频
            initAudio();
            
            // 更新语言
            updateLanguage();
        }
        
        // 初始化音频
        function initAudio() {
            // 使用 Kevin MacLeod 的 Creative Commons 音乐 "Deep Space"
            audio = new Audio();
            audio.src = 'https://www.soundjay.com/misc/sounds/bell-ringing-05.wav'; // 示例音频
            audio.loop = true;
            audio.volume = 0.3;
        }
        
        // 创建粒子系统
        function createParticleSystem() {
            const particleCount = 30000;
            geometry = new THREE.BufferGeometry();
            const positions = new Float32Array(particleCount * 3);
            const colors = new Float32Array(particleCount * 3);
            const sizes = new Float32Array(particleCount);
            const originalPositions = new Float32Array(particleCount * 3);
            
            for (let i = 0; i < particleCount; i++) {
                const i3 = i * 3;
                
                // 使用球形分布确保均匀分布
                const radius = 5 + Math.random() * 20; // 更大的分布范围
                const theta = Math.random() * Math.PI * 2;
                const phi = Math.acos(2 * Math.random() - 1);
                
                originalPositions[i3] = radius * Math.sin(phi) * Math.cos(theta);
                originalPositions[i3 + 1] = radius * Math.sin(phi) * Math.sin(theta);
                originalPositions[i3 + 2] = radius * Math.cos(phi);
                
                // 复制到当前位置
                positions[i3] = originalPositions[i3];
                positions[i3 + 1] = originalPositions[i3 + 1];
                positions[i3 + 2] = originalPositions[i3 + 2];
                
                // 深邃的颜色(深蓝、紫色、暗绿等)
                const colorChoices = [
                    [0.1, 0.1, 0.3], // 深蓝
                    [0.2, 0.1, 0.4], // 紫色
                    [0.1, 0.3, 0.3], // 深青
                    [0.2, 0.2, 0.4], // 深紫
                    [0.1, 0.2, 0.3], // 蓝紫
                    [0.05, 0.1, 0.2] // 极暗蓝
                ];
                const color = colorChoices[Math.floor(Math.random() * colorChoices.length)];
                colors[i3] = color[0];
                colors[i3 + 1] = color[1];
                colors[i3 + 2] = color[2];
                
                // 随机大小
                sizes[i] = 0.05 + Math.random() * 0.15;
            }
            
            geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
            geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));
            geometry.setAttribute('size', new THREE.BufferAttribute(sizes, 1));
            geometry.setAttribute('originalPosition', new THREE.BufferAttribute(originalPositions, 3));
            
            material = new THREE.PointsMaterial({
                size: 0.1,
                vertexColors: true,
                transparent: true,
                opacity: 0.7,
                sizeAttenuation: true
            });
            
            particles = new THREE.Points(geometry, material);
            scene.add(particles);
        }
        
        // 添加事件监听器
        function addEventListeners() {
            // 鼠标事件
            renderer.domElement.addEventListener('mousedown', onMouseDown);
            renderer.domElement.addEventListener('mousemove', onMouseMove);
            renderer.domElement.addEventListener('mouseup', onMouseUp);
            renderer.domElement.addEventListener('wheel', onMouseWheel);
            
            // 触控事件
            renderer.domElement.addEventListener('touchstart', onTouchStart);
            renderer.domElement.addEventListener('touchmove', onTouchMove);
            renderer.domElement.addEventListener('touchend', onTouchEnd);
        }
        
        // 鼠标事件处理
        function onMouseDown(event) {
            isMouseDown = true;
            mouseX = event.clientX;
            mouseY = event.clientY;
        }
        
        function onMouseMove(event) {
            if (isMouseDown && currentMode === 'touch') {
                const deltaX = event.clientX - mouseX;
                const deltaY = event.clientY - mouseY;
                
                targetRotationY += deltaX * 0.01;
                targetRotationX += deltaY * 0.01;
                
                mouseX = event.clientX;
                mouseY = event.clientY;
            }
        }
        
        function onMouseUp() {
            isMouseDown = false;
        }
        
        function onMouseWheel(event) {
            if (currentMode === 'touch') {
                cameraDistance -= event.deltaY * 0.01;
                cameraDistance = Math.max(5, Math.min(50, cameraDistance));
            }
        }
        
        // 触控事件处理
        function onTouchStart(event) {
            if (currentMode !== 'touch') return;
            
            if (event.touches.length === 1) {
                touchStartX = event.touches[0].clientX;
                touchStartY = event.touches[0].clientY;
            } else if (event.touches.length === 2) {
                const dx = event.touches[0].clientX - event.touches[1].clientX;
                const dy = event.touches[0].clientY - event.touches[1].clientY;
                touchStartDistance = Math.sqrt(dx * dx + dy * dy);
            }
            event.preventDefault();
        }
        
        function onTouchMove(event) {
            if (currentMode !== 'touch') return;
            
            if (event.touches.length === 1) {
                const deltaX = event.touches[0].clientX - touchStartX;
                const deltaY = event.touches[0].clientY - touchStartY;
                
                targetRotationY += deltaX * 0.01;
                targetRotationX += deltaY * 0.01;
                
                touchStartX = event.touches[0].clientX;
                touchStartY = event.touches[0].clientY;
            } else if (event.touches.length === 2) {
                const dx = event.touches[0].clientX - event.touches[1].clientX;
                const dy = event.touches[0].clientY - event.touches[1].clientY;
                const distance = Math.sqrt(dx * dx + dy * dy);
                
                if (touchStartDistance > 0) {
                    const deltaDistance = distance - touchStartDistance;
                    cameraDistance -= deltaDistance * 0.05;
                    cameraDistance = Math.max(5, Math.min(50, cameraDistance));
                }
                
                touchStartDistance = distance;
            }
            event.preventDefault();
        }
        
        function onTouchEnd() {
            if (currentMode !== 'touch') return;
            touchStartDistance = 0;
        }
        
        // 切换语言
        function toggleLanguage() {
            currentLanguage = currentLanguage === 'zh-CN' ? 'en' : 'zh-CN';
            updateLanguage();
        }
        
        // 更新语言
        function updateLanguage() {
            const lang = languages[currentLanguage];
            
            document.getElementById('title').innerHTML = lang.title;
            document.getElementById('freeMode').innerHTML = lang.freeMode;
            document.getElementById('touchMode').innerHTML = lang.touchMode;
            
            if (!startScreen.classList.contains('hidden')) {
                document.getElementById('currentMode').innerHTML = lang.currentMode + 
                    (currentMode === 'free' ? lang.freeModeText : lang.touchModeText);
            }
            
            document.getElementById('freeControls').innerHTML = lang.freeControls;
            document.getElementById('touchControls').innerHTML = lang.touchControls;
            document.getElementById('musicTitle').innerHTML = lang.musicTitle;
            
            languageToggle.innerHTML = currentLanguage === 'zh-CN' ? 'English' : '中文';
        }
        
        // 开始过渡动画
        function startTransition(mode) {
            if (isTransitioning) return;
            
            isTransitioning = true;
            currentMode = mode;
            
            // 更新UI
            document.getElementById('currentMode').innerHTML = 
                currentLanguage === 'zh-CN' ? 
                '当前模式: ' + (mode === 'free' ? '自由探索模式' : '触控移动模式') :
                'Current Mode: ' + (mode === 'free' ? 'Free Exploration Mode' : 'Touch Control Mode');
            
            // 显示控制说明
            document.getElementById('modeInfo').classList.remove('hidden');
            document.getElementById('controls').classList.remove('hidden');
            document.getElementById('musicInfo').classList.remove('hidden');
            
            if (mode === 'touch') {
                document.getElementById('touchControls').classList.remove('hidden');
                document.getElementById('freeControls').classList.add('hidden');
            } else {
                document.getElementById('touchControls').classList.add('hidden');
                document.getElementById('freeControls').classList.remove('hidden');
            }
            
            // 开始过渡
            startScreen.style.opacity = '0';
            
            setTimeout(() => {
                startScreen.classList.add('hidden');
                // 播放背景音乐
                // audio.play(); // 在实际应用中取消注释
                animate();
            }, 2000);
        }
        
        // 动画循环
        function animate() {
            animationId = requestAnimationFrame(animate);
            
            time += 0.01;
            
            // 更新粒子系统
            updateParticles();
            
            // 更新相机位置
            updateCamera();
            
            // 渲染场景
            renderer.render(scene, camera);
        }
        
        // 更新相机位置
        function updateCamera() {
            if (currentMode === 'free') {
                // 自由探索模式 - 更复杂的旋转模式
                targetRotationY += 0.003;
                targetRotationX = Math.sin(time * 0.2) * 0.4;
                
                // 添加额外的旋转维度
                const offsetX = Math.sin(time * 0.1) * 2;
                const offsetY = Math.cos(time * 0.15) * 2;
                const offsetZ = Math.sin(time * 0.08) * 2;
                
                // 相机围绕更大的空间运动
                camera.position.x = cameraDistance * Math.sin(rotationY) * Math.cos(rotationX) + offsetX;
                camera.position.y = cameraDistance * Math.sin(rotationX) + offsetY;
                camera.position.z = cameraDistance * Math.cos(rotationY) * Math.cos(rotationX) + offsetZ;
            } else {
                // 平滑插值旋转
                rotationX += (targetRotationX - rotationX) * 0.1;
                rotationY += (targetRotationY - rotationY) * 0.1;
                
                // 应用旋转和距离
                camera.position.x = cameraDistance * Math.sin(rotationY) * Math.cos(rotationX);
                camera.position.y = cameraDistance * Math.sin(rotationX);
                camera.position.z = cameraDistance * Math.cos(rotationY) * Math.cos(rotationX);
            }
            
            camera.lookAt(scene.position);
        }
        
        // 更新粒子系统
        function updateParticles() {
            const positions = geometry.attributes.position.array;
            const colors = geometry.attributes.color.array;
            const originalPositions = geometry.attributes.originalPosition.array;
            const particleCount = positions.length / 3;
            
            for (let i = 0; i < particleCount; i++) {
                const i3 = i * 3;
                
                // 基于原始位置的平滑偏移,创建波浪效果
                const offsetTime = time * 0.5 + i * 0.0005;
                
                // 在更大的空间中移动,避免聚集在中心
                positions[i3] = originalPositions[i3] + Math.sin(offsetTime) * 1.5;
                positions[i3 + 1] = originalPositions[i3 + 1] + Math.cos(offsetTime * 0.8) * 1.5;
                positions[i3 + 2] = originalPositions[i3 + 2] + Math.sin(offsetTime * 0.6) * 1.5;
                
                // 深邃的颜色变化(更微妙)
                const baseColorTime = time * 0.1 + i * 0.001;
                const r = 0.1 + Math.abs(Math.sin(baseColorTime)) * 0.2;
                const g = 0.1 + Math.abs(Math.sin(baseColorTime + 1)) * 0.2;
                const b = 0.2 + Math.abs(Math.sin(baseColorTime + 2)) * 0.3;
                
                colors[i3] = r;
                colors[i3 + 1] = g;
                colors[i3 + 2] = b;
            }
            
            geometry.attributes.position.needsUpdate = true;
            geometry.attributes.color.needsUpdate = true;
        }
        
        // 窗口大小调整
        function onWindowResize() {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        }
        
        // 启动应用
        init();
    </script>
</body>
</html>
        
编辑器加载中
预览
控制台