🎮ArcadeLab

3D 卧室场景重建

by TurboKoala83
291 lines11.6 KB🛠️ Three.js (3D graphics)
▶ Play
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>3D 卧室场景重建</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
            background-color: #333;
        }
        canvas {
            display: block;
        }
        #info {
            position: absolute;
            top: 10px;
            width: 100%;
            text-align: center;
            color: white;
            font-family: Arial, sans-serif;
            pointer-events: none;
            text-shadow: 1px 1px 2px black;
        }
    </style>
    <!-- 引入 Three.js 和 OrbitControls -->
    <script type="importmap">
        {
            "imports": {
                "three": "https://unpkg.com/three@0.160.0/build/three.module.js",
                "three/addons/": "https://unpkg.com/three@0.160.0/examples/jsm/"
            }
        }
    </script>
</head>
<body>
    <div id="info">
        <h3>3D 卧室场景</h3>
        <p>左键旋转 | 滚轮缩放 | 右键平移</p>
    </div>

    <script type="module">
        import * as THREE from 'three';
        import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

        // 1. 基础场景设置
        const scene = new THREE.Scene();
        scene.background = new THREE.Color(0xaaccff); // 天空背景色

        const camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 1000);
        camera.position.set(6, 4, 6); // 相机初始位置

        const renderer = new THREE.WebGLRenderer({ antialias: true });
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.shadowMap.enabled = true; // 开启阴影
        renderer.shadowMap.type = THREE.PCFSoftShadowMap;
        document.body.appendChild(renderer.domElement);

        const controls = new OrbitControls(camera, renderer.domElement);
        controls.target.set(0, 1.5, -1);
        controls.enableDamping = true;
        controls.dampingFactor = 0.05;

        // 2. 光照设置
        const ambientLight = new THREE.AmbientLight(0xffffff, 0.6); // 环境光
        scene.add(ambientLight);

        // 模拟窗外自然光
        const windowLight = new THREE.DirectionalLight(0xfff5e6, 1.5);
        windowLight.position.set(5, 5, 2);
        windowLight.castShadow = true;
        windowLight.shadow.mapSize.width = 1024;
        windowLight.shadow.mapSize.height = 1024;
        windowLight.shadow.camera.near = 0.5;
        windowLight.shadow.camera.far = 20;
        windowLight.shadow.camera.left = -5;
        windowLight.shadow.camera.right = 5;
        windowLight.shadow.camera.top = 5;
        windowLight.shadow.camera.bottom = -5;
        scene.add(windowLight);

        // 室内补光
        const roomLight = new THREE.PointLight(0xffffff, 0.5);
        roomLight.position.set(0, 3, 2);
        scene.add(roomLight);

        // 3. 材质定义
        const wallMaterial = new THREE.MeshStandardMaterial({ color: 0xf0f0f0, roughness: 0.8 });
        const floorMaterial = new THREE.MeshStandardMaterial({ color: 0xdcdcdc, roughness: 0.6 });
        const woodMaterial = new THREE.MeshStandardMaterial({ color: 0x8b5a2b, roughness: 0.7 });
        const pinkMaterial = new THREE.MeshStandardMaterial({ color: 0xffb6c1, roughness: 0.5 });
        const plasticWhite = new THREE.MeshStandardMaterial({ color: 0xffffff, roughness: 0.3 });
        const darkPlastic = new THREE.MeshStandardMaterial({ color: 0x222222, roughness: 0.4 });
        const screenMaterial = new THREE.MeshStandardMaterial({ color: 0x111111, emissive: 0x333333 });
        const curtainMaterial = new THREE.MeshStandardMaterial({ color: 0xfffaf0, roughness: 1.0, side: THREE.DoubleSide });

        // 4. 房间结构构建
        // 地板
        const floorGeometry = new THREE.PlaneGeometry(8, 8);
        const floor = new THREE.Mesh(floorGeometry, floorMaterial);
        floor.rotation.x = -Math.PI / 2;
        floor.receiveShadow = true;
        scene.add(floor);

        // 后墙
        const backWall = new THREE.Mesh(new THREE.PlaneGeometry(8, 4), wallMaterial);
        backWall.position.set(0, 2, -4);
        backWall.receiveShadow = true;
        scene.add(backWall);

        // 右墙 (带窗户的那面)
        const rightWall = new THREE.Mesh(new THREE.PlaneGeometry(8, 4), wallMaterial);
        rightWall.rotation.y = -Math.PI / 2;
        rightWall.position.set(4, 2, 0);
        rightWall.receiveShadow = true;
        scene.add(rightWall);

        // 左墙
        const leftWall = new THREE.Mesh(new THREE.PlaneGeometry(8, 4), wallMaterial);
        leftWall.rotation.y = Math.PI / 2;
        leftWall.position.set(-4, 2, 0);
        leftWall.receiveShadow = true;
        scene.add(leftWall);

        // 5. 物品构建
        // --- 空调 ---
        const acUnit = new THREE.Mesh(new THREE.BoxGeometry(1.6, 0.5, 0.3), plasticWhite);
        acUnit.position.set(-1.5, 3.2, -3.8);
        acUnit.castShadow = true;
        scene.add(acUnit);
        // 空调管子
        const pipe = new THREE.Mesh(new THREE.CylinderGeometry(0.02, 0.02, 1.5), plasticWhite);
        pipe.position.set(-0.5, 3.0, -3.8);
        pipe.rotation.z = Math.PI / 6;
        scene.add(pipe);

        // --- 书桌 ---
        const deskGroup = new THREE.Group();
        // 桌面
        const deskTop = new THREE.Mesh(new THREE.BoxGeometry(3.5, 0.1, 0.8), woodMaterial);
        deskTop.position.set(0, 0.8, -3.2);
        deskTop.castShadow = true;
        deskTop.receiveShadow = true;
        deskGroup.add(deskTop);
        // 桌腿/柜子侧板
        const deskLeft = new THREE.Mesh(new THREE.BoxGeometry(0.1, 0.8, 0.8), woodMaterial);
        deskLeft.position.set(-1.7, 0.4, -3.2);
        deskLeft.castShadow = true;
        deskGroup.add(deskLeft);
        const deskRight = new THREE.Mesh(new THREE.BoxGeometry(0.1, 0.8, 0.8), woodMaterial);
        deskRight.position.set(1.7, 0.4, -3.2);
        deskRight.castShadow = true;
        deskGroup.add(deskRight);
        // 抽屉/背板
        const deskBack = new THREE.Mesh(new THREE.BoxGeometry(3.5, 0.6, 0.1), woodMaterial);
        deskBack.position.set(0, 0.4, -3.55);
        deskGroup.add(deskBack);
        scene.add(deskGroup);

        // --- 电脑显示器 ---
        const monitorBase = new THREE.Mesh(new THREE.BoxGeometry(0.3, 0.05, 0.2), darkPlastic);
        monitorBase.position.set(0.8, 0.87, -3.2);
        scene.add(monitorBase);
        const monitorStand = new THREE.Mesh(new THREE.BoxGeometry(0.05, 0.3, 0.05), darkPlastic);
        monitorStand.position.set(0.8, 1.05, -3.2);
        scene.add(monitorStand);
        const monitorScreen = new THREE.Mesh(new THREE.BoxGeometry(0.9, 0.6, 0.05), screenMaterial);
        monitorScreen.position.set(0.8, 1.4, -3.2);
        monitorScreen.castShadow = true;
        scene.add(monitorScreen);

        // --- 键盘鼠标 ---
        const keyboard = new THREE.Mesh(new THREE.BoxGeometry(0.6, 0.03, 0.2), darkPlastic);
        keyboard.position.set(0.8, 0.86, -2.9);
        scene.add(keyboard);

        // --- 粉色转椅 ---
        const chairGroup = new THREE.Group();
        chairGroup.position.set(-0.2, 0, -2.2);
        // 轮子底座
        const chairBase = new THREE.Mesh(new THREE.CylinderGeometry(0.3, 0.3, 0.05), plasticWhite);
        chairBase.position.y = 0.1;
        chairGroup.add(chairBase);
        const chairPole = new THREE.Mesh(new THREE.CylinderGeometry(0.05, 0.05, 0.4), plasticWhite);
        chairPole.position.y = 0.3;
        chairGroup.add(chairPole);
        // 坐垫
        const chairSeat = new THREE.Mesh(new THREE.BoxGeometry(0.5, 0.1, 0.5), pinkMaterial);
        chairSeat.position.y = 0.55;
        chairSeat.castShadow = true;
        chairGroup.add(chairSeat);
        // 靠背
        const chairBack = new THREE.Mesh(new THREE.BoxGeometry(0.5, 0.6, 0.1), pinkMaterial);
        chairBack.position.set(0, 0.9, -0.2);
        chairBack.rotation.x = -0.1;
        chairBack.castShadow = true;
        chairGroup.add(chairBack);
        scene.add(chairGroup);

        // --- 落地风扇 ---
        const fanGroup = new THREE.Group();
        fanGroup.position.set(-3.2, 0, -2.5);
        // 底座
        const fanBase = new THREE.Mesh(new THREE.CylinderGeometry(0.3, 0.3, 0.05), plasticWhite);
        fanBase.position.y = 0.025;
        fanGroup.add(fanBase);
        // 杆子
        const fanPole = new THREE.Mesh(new THREE.CylinderGeometry(0.03, 0.03, 1.2), plasticWhite);
        fanPole.position.y = 0.6;
        fanGroup.add(fanPole);
        // 电机
        const fanMotor = new THREE.Mesh(new THREE.CylinderGeometry(0.1, 0.1, 0.2), darkPlastic);
        fanMotor.position.set(0, 1.2, 0);
        fanMotor.rotation.x = Math.PI / 2;
        fanGroup.add(fanMotor);
        // 网罩
        const fanGrill = new THREE.Mesh(new THREE.CylinderGeometry(0.4, 0.4, 0.05, 16), plasticWhite);
        fanGrill.position.set(0, 1.2, 0.02);
        fanGrill.rotation.x = Math.PI / 2;
        fanGroup.add(fanGrill);
        // 风扇叶片 (简化表现)
        const fanBlades = new THREE.Mesh(new THREE.CylinderGeometry(0.35, 0.35, 0.02, 3), plasticWhite);
        fanBlades.position.set(0, 1.2, 0);
        fanBlades.rotation.x = Math.PI / 2;
        fanGroup.add(fanBlades);
        scene.add(fanGroup);

        // --- 窗帘和窗户区域 ---
        // 窗台/飘窗
        const windowsill = new THREE.Mesh(new THREE.BoxGeometry(1.5, 0.2, 0.6), plasticWhite);
        windowsill.position.set(3.6, 0.9, 1.5);
        windowsill.castShadow = true;
        scene.add(windowsill);
        
        // 飘窗上的绿植垫 (绿色区域)
        const greenMat = new THREE.MeshStandardMaterial({ color: 0x88cc88, roughness: 1.0 });
        const sillMat = new THREE.Mesh(new THREE.BoxGeometry(1.4, 0.05, 0.5), greenMat);
        sillMat.position.set(3.6, 1.02, 1.5);
        scene.add(sillMat);

        // 窗帘
        const curtainGeo = new THREE.PlaneGeometry(1.5, 3);
        const curtain = new THREE.Mesh(curtainGeo, curtainMaterial);
        curtain.position.set(3.8, 2, 0.2);
        curtain.rotation.y = -Math.PI / 2 + 0.2;
        curtain.castShadow = true;
        scene.add(curtain);

        // --- 垃圾桶 ---
        const trashCan = new THREE.Mesh(new THREE.CylinderGeometry(0.2, 0.15, 0.4), new THREE.MeshStandardMaterial({color: 0x888888}));
        trashCan.position.set(1.8, 0.2, -2.2);
        trashCan.castShadow = true;
        scene.add(trashCan);

        // --- 电脑主机 ---
        const pcTower = new THREE.Mesh(new THREE.BoxGeometry(0.4, 0.8, 0.8), darkPlastic);
        pcTower.position.set(1.5, 0.4, -2.2);
        pcTower.castShadow = true;
        scene.add(pcTower);

        // --- 地上的垫子/床沿 ---
        const matMaterial = new THREE.MeshStandardMaterial({ color: 0xcda87a });
        const mat = new THREE.Mesh(new THREE.BoxGeometry(3, 0.05, 1.5), matMaterial);
        mat.position.set(0, 0.025, 2);
        mat.receiveShadow = true;
        scene.add(mat);

        // --- 墙上的插座和线 ---
        const socket = new THREE.Mesh(new THREE.BoxGeometry(0.1, 0.1, 0.02), plasticWhite);
        socket.position.set(-2, 1.5, -3.99);
        scene.add(socket);

        // 6. 动画循环
        function animate() {
            requestAnimationFrame(animate);
            controls.update(); // 更新控制器
            renderer.render(scene, camera);
        }

        animate();

        // 7. 响应窗口大小调整
        window.addEventListener('resize', () => {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        });
    </script>
</body>
</html>

Game Source: 3D 卧室场景重建

Creator: TurboKoala83

Libraries: three

Complexity: complex (291 lines, 11.6 KB)

The full source code is displayed above on this page.

Remix Instructions

To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: 3d-turbokoala83" to link back to the original. Then publish at arcadelab.ai/publish.