3D 卧室场景重建
by TurboKoala83291 lines11.6 KB🛠️ Three.js (3D graphics)
<!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.