🎮ArcadeLab

我的房间 - 3D 模型 (Three.js)

by EpicCoder88
233 lines9.4 KB🛠️ Three.js (3D graphics)
▶ Play
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>我的房间 - 3D 模型 (Three.js)</title>
    <style>
        body { margin: 0; overflow: hidden; background-color: #222; }
        canvas { display: block; }
        #info {
            position: absolute;
            top: 10px;
            width: 100%;
            text-align: center;
            color: white;
            font-family: sans-serif;
            pointer-events: none;
        }
    </style>
</head>
<body>
    <div id="info">鼠标左键拖拽旋转 | 滚轮缩放 | 右键平移</div>

    <!-- 引入 Three.js 和相机控制器 -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.js"></script>

    <script>
        // 1. 初始化场景、相机和渲染器
        const scene = new THREE.Scene();
        scene.background = new THREE.Color(0xf0f4f8); // 柔和的背景色

        const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);
        camera.position.set(8, 12, 18); // 设置相机初始位置
        camera.lookAt(0, 3, 0);

        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 THREE.OrbitControls(camera, renderer.domElement);
        controls.target.set(0, 3, 0);
        controls.update();

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

        // 主光源(模拟窗外透进来的自然光)
        const dirLight = new THREE.DirectionalLight(0xffffff, 0.8);
        dirLight.position.set(10, 15, 10);
        dirLight.castShadow = true;
        dirLight.shadow.mapSize.width = 2048;
        dirLight.shadow.mapSize.height = 2048;
        dirLight.shadow.camera.near = 0.5;
        dirLight.shadow.camera.far = 50;
        dirLight.shadow.camera.left = -15;
        dirLight.shadow.camera.right = 15;
        dirLight.shadow.camera.top = 15;
        dirLight.shadow.camera.bottom = -15;
        scene.add(dirLight);

        // 3. 辅助函数:创建盒子几何体
        function createBox(w, h, d, color, x, y, z, castShadow = true, receiveShadow = true) {
            const geometry = new THREE.BoxGeometry(w, h, d);
            const material = new THREE.MeshStandardMaterial({ color: color });
            const mesh = new THREE.Mesh(geometry, material);
            mesh.position.set(x, y, z);
            mesh.castShadow = castShadow;
            mesh.receiveShadow = receiveShadow;
            scene.add(mesh);
            return mesh;
        }

        // 4. 构建房间基础结构
        // 地板 (浅色地砖)
        const floorGeo = new THREE.PlaneGeometry(20, 20);
        const floorMat = new THREE.MeshStandardMaterial({ color: 0xe3e5e8, roughness: 0.8 });
        const floor = new THREE.Mesh(floorGeo, floorMat);
        floor.rotation.x = -Math.PI / 2;
        floor.receiveShadow = true;
        scene.add(floor);

        // 左侧墙壁
        createBox(0.5, 12, 20, 0xfdfaf7, -10, 6, 0, false, true);
        // 后侧墙壁
        createBox(20, 12, 0.5, 0xfdfaf7, 0, 6, -10, false, true);
        // 右侧墙壁 (留出空间模拟窗户和窗帘)
        createBox(0.5, 12, 20, 0xfdfaf7, 10, 6, 0, false, true);

        // 墙面水渍 (用半透明材质模拟)
        const stainGeo = new THREE.PlaneGeometry(3, 6);
        const stainMat = new THREE.MeshStandardMaterial({ color: 0xcdaa7d, transparent: true, opacity: 0.4 });
        const stain = new THREE.Mesh(stainGeo, stainMat);
        stain.position.set(8.8, 3, -8);
        stain.rotation.y = -Math.PI / 2;
        scene.add(stain);

        // 5. 构建家具
        // --- 空调 ---
        createBox(4, 1.2, 0.8, 0xffffff, 0, 9, -9.5);

        // --- 书桌 (右侧) ---
        const deskX = 5, deskY = 2.5, deskZ = -7;
        // 桌面
        createBox(7, 0.3, 3, 0x8b5a2b, deskX, deskY, deskZ);
        // 抽屉柜
        createBox(2.5, 4, 2.8, 0x754a22, deskX - 2.25, deskY - 2.15, deskZ);

        // --- 电脑显示器 ---
        createBox(2.5, 1.8, 0.2, 0x1a1a1a, deskX + 2, deskY + 1.05, deskZ - 0.5);
        // 显示器底座
        createBox(0.8, 0.2, 0.8, 0x333333, deskX + 2, deskY + 0.2, deskZ - 0.5);

        // --- 电脑主机 ---
        createBox(1.5, 2.5, 2, 0x222222, deskX + 2.5, deskY - 1.25, deskZ + 0.5);

        // --- 粉色椅子 ---
        const chairX = 3, chairY = 1.5, chairZ = -3;
        // 坐垫
        createBox(2, 0.5, 2, 0xf4b6c2, chairX, chairY, chairZ);
        // 靠背 (稍微倾斜)
        const backGeo = new THREE.BoxGeometry(2, 2, 0.4);
        const backMat = new THREE.MeshStandardMaterial({ color: 0xf4b6c2 });
        const back = new THREE.Mesh(backGeo, backMat);
        back.position.set(chairX, chairY + 1, chairZ - 0.8);
        back.rotation.x = -0.2;
        back.castShadow = true;
        scene.add(back);
        // 椅子腿 (简化为圆柱)
        const legGeo = new THREE.CylinderGeometry(0.1, 0.1, 1.5, 8);
        const legMat = new THREE.MeshStandardMaterial({ color: 0xffffff });
        const leg = new THREE.Mesh(legGeo, legMat);
        leg.position.set(chairX, chairY - 0.75, chairZ);
        leg.castShadow = true;
        scene.add(leg);
        // 椅子底座
        const baseGeo = new THREE.CylinderGeometry(1.2, 1.2, 0.2, 16);
        const base = new THREE.Mesh(baseGeo, legMat);
        base.position.set(chairX, chairY - 1.5, chairZ);
        base.castShadow = true;
        scene.add(base);

        // --- 落地风扇 (左侧) ---
        const fanX = -6, fanZ = -4;
        // 风扇底座
        const fanBaseGeo = new THREE.CylinderGeometry(1.2, 1.2, 0.2, 16);
        const fanBaseMat = new THREE.MeshStandardMaterial({ color: 0xeeeeee });
        const fanBase = new THREE.Mesh(fanBaseGeo, fanBaseMat);
        fanBase.position.set(fanX, 0.1, fanZ);
        fanBase.castShadow = true;
        scene.add(fanBase);
        // 风扇杆
        const fanPoleGeo = new THREE.CylinderGeometry(0.1, 0.1, 4, 8);
        const fanPole = new THREE.Mesh(fanPoleGeo, fanBaseMat);
        fanPole.position.set(fanX, 2, fanZ);
        fanPole.castShadow = true;
        scene.add(fanPole);
        // 风扇头部 (圆形外壳)
        const fanHeadGeo = new THREE.CylinderGeometry(1.5, 1.5, 0.5, 32);
        const fanHeadMat = new THREE.MeshStandardMaterial({ color: 0x555555 });
        const fanHead = new THREE.Mesh(fanHeadGeo, fanHeadMat);
        fanHead.position.set(fanX, 4.5, fanZ);
        fanHead.rotation.x = Math.PI / 2;
        fanHead.rotation.z = Math.PI / 2;
        fanHead.castShadow = true;
        scene.add(fanHead);
        // 风扇网罩 (用线框圆柱体模拟)
        const wireframeGeo = new THREE.CylinderGeometry(1.6, 1.6, 0.6, 16);
        const wireframeMat = new THREE.MeshBasicMaterial({ color: 0xaaaaaa, wireframe: true });
        const wireframe = new THREE.Mesh(wireframeGeo, wireframeMat);
        wireframe.position.set(fanX, 4.5, fanZ);
        wireframe.rotation.x = Math.PI / 2;
        wireframe.rotation.z = Math.PI / 2;
        scene.add(wireframe);

        // --- 垃圾桶 (右侧) ---
        const trashGeo = new THREE.CylinderGeometry(0.8, 0.6, 1.5, 16);
        const trashMat = new THREE.MeshStandardMaterial({ color: 0x8fa3ad });
        const trash = new THREE.Mesh(trashGeo, trashMat);
        trash.position.set(8, 0.75, -4);
        trash.castShadow = true;
        scene.add(trash);

        // --- 床铺 (前景) ---
        // 床架/凉席
        const bedGeo = new THREE.BoxGeometry(18, 0.8, 7);
        const bedMat = new THREE.MeshStandardMaterial({ color: 0x9e5a38, roughness: 0.9 });
        const bed = new THREE.Mesh(bedGeo, bedMat);
        bed.position.set(0, 0.4, 6);
        bed.receiveShadow = true;
        scene.add(bed);
        // 床铺边缘
        createBox(18.2, 0.2, 7.2, 0xd3d3d3, 0, 0.9, 6, false, true);

        // --- 地上的蓝色圆圈 ---
        const ringGeo = new THREE.TorusGeometry(1, 0.1, 16, 32);
        const ringMat = new THREE.MeshStandardMaterial({ color: 0x4a90e2 });
        const ring = new THREE.Mesh(ringGeo, ringMat);
        ring.position.set(-7, 0.1, -1);
        ring.rotation.x = -Math.PI / 2;
        scene.add(ring);

        // --- 窗帘 (右侧) ---
        const curtainGeo = new THREE.PlaneGeometry(3, 12);
        const curtainMat = new THREE.MeshStandardMaterial({ color: 0xffffff, side: THREE.DoubleSide, transparent: true, opacity: 0.8 });
        const curtain = new THREE.Mesh(curtainGeo, curtainMat);
        curtain.position.set(9.8, 6, 2);
        curtain.rotation.y = -Math.PI / 2;
        scene.add(curtain);

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

        // 7. 窗口大小适配
        window.addEventListener('resize', () => {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        });

        // 启动
        animate();
    </script>
</body>
</html>

Game Source: 我的房间 - 3D 模型 (Three.js)

Creator: EpicCoder88

Libraries: three

Complexity: complex (233 lines, 9.4 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-three-js-epiccoder88" to link back to the original. Then publish at arcadelab.ai/publish.