我的房间 - 全景 3D 还原
by EpicCoder88474 lines22.8 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, maximum-scale=1.0, user-scalable=no">
<title>我的房间 - 全景 3D 还原</title>
<style>
body { margin: 0; overflow: hidden; background-color: #1a1a1a; }
canvas { display: block; }
#info {
position: absolute; bottom: 20px; left: 20px;
color: rgba(255,255,255,0.7); font-family: sans-serif; font-size: 12px;
pointer-events: none; background: rgba(0,0,0,0.5); padding: 10px; border-radius: 5px;
}
</style>
</head>
<body>
<div id="info">鼠标左键旋转 | 滚轮缩放 | 右键平移<br>提示:本次更新增加了右侧飘窗、左侧衣柜及床边角落</div>
<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);
scene.fog = new THREE.Fog(0xf0f4f8, 25, 60);
const camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 100);
// 调整相机位置,展示整个房间
camera.position.set(16, 12, 22);
camera.lookAt(0, 4, 0);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1.1;
document.body.appendChild(renderer.domElement);
const controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.target.set(0, 4, 0);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
controls.maxPolarAngle = Math.PI / 2; // 限制不能钻到地板下面
// ==========================================
// 2. 精细光照
// ==========================================
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);
// 主光源:模拟窗外自然光,从右前方照射
const dirLight = new THREE.DirectionalLight(0xfff5e6, 1.2);
dirLight.position.set(15, 15, 10);
dirLight.castShadow = true;
dirLight.shadow.mapSize.width = 2048;
dirLight.shadow.mapSize.height = 2048;
dirLight.shadow.camera.near = 1;
dirLight.shadow.camera.far = 50;
dirLight.shadow.camera.left = -20;
dirLight.shadow.camera.right = 20;
dirLight.shadow.camera.top = 20;
dirLight.shadow.camera.bottom = -20;
dirLight.shadow.bias = -0.0005;
scene.add(dirLight);
// 补光
const fillLight = new THREE.DirectionalLight(0xffffff, 0.3);
fillLight.position.set(-10, 10, -10);
scene.add(fillLight);
// ==========================================
// 3. 工具函数与纹理生成
// ==========================================
const createMat = (color, roughness = 0.8, metalness = 0.0, map = null) => {
return new THREE.MeshStandardMaterial({ color, roughness, metalness, map });
};
// 生成水渍纹理
function createStainTexture() {
const canvas = document.createElement('canvas');
canvas.width = 512; canvas.height = 512;
const ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, 512, 512);
// 绘制不规则的褐色水渍
ctx.fillStyle = 'rgba(180, 150, 110, 0.4)';
for(let i=0; i<20; i++) {
ctx.beginPath();
ctx.arc(256 + Math.random()*100 - 50, 256 + Math.random()*100 - 50, 50 + Math.random()*100, 0, Math.PI*2);
ctx.fill();
}
const texture = new THREE.CanvasTexture(canvas);
return texture;
}
// 生成凉席纹理
function createMatTexture() {
const canvas = document.createElement('canvas');
canvas.width = 256; canvas.height = 256;
const ctx = canvas.getContext('2d');
ctx.fillStyle = '#a05a38'; ctx.fillRect(0, 0, 256, 256);
ctx.strokeStyle = '#7a4225'; ctx.lineWidth = 1;
for (let i = 0; i <= 256; i += 8) {
ctx.beginPath(); ctx.moveTo(i, 0); ctx.lineTo(i, 256); ctx.stroke();
ctx.beginPath(); ctx.moveTo(0, i); ctx.lineTo(256, i); ctx.stroke();
}
const texture = new THREE.CanvasTexture(canvas);
texture.wrapS = THREE.RepeatWrapping; texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set(4, 4);
return texture;
}
const matTexture = createMatTexture();
// ==========================================
// 4. 房间基础结构
// ==========================================
// 地板
const floorMat = createMat(0xdcdfe3, 0.6, 0.1);
const floor = new THREE.Mesh(new THREE.PlaneGeometry(30, 30), floorMat);
floor.rotation.x = -Math.PI / 2;
floor.receiveShadow = true;
scene.add(floor);
// 墙壁
const wallMat = createMat(0xfdfaf7, 0.9);
const wallThickness = 0.5;
// 左侧墙 (x = -15)
const leftWall = new THREE.Mesh(new THREE.BoxGeometry(wallThickness, 15, 30), wallMat);
leftWall.position.set(-15, 7.5, 0);
leftWall.receiveShadow = true; scene.add(leftWall);
// 后侧墙 (z = -15)
const backWall = new THREE.Mesh(new THREE.BoxGeometry(30, 15, wallThickness), wallMat);
backWall.position.set(0, 7.5, -15);
backWall.receiveShadow = true; scene.add(backWall);
// 右侧墙 (x = 15)
const rightWall = new THREE.Mesh(new THREE.BoxGeometry(wallThickness, 15, 30), wallMat);
rightWall.position.set(15, 7.5, 0);
rightWall.receiveShadow = true; scene.add(rightWall);
// 墙面水渍 (后墙)
const stainMat = new THREE.MeshStandardMaterial({ map: createStainTexture(), transparent: true, opacity: 0.8, depthWrite: false });
const stainBack = new THREE.Mesh(new THREE.PlaneGeometry(6, 8), stainMat);
stainBack.position.set(8, 4, -14.7);
stainBack.rotation.y = Math.PI;
scene.add(stainBack);
// 墙面水渍 (右墙飘窗下方)
const stainRight = new THREE.Mesh(new THREE.PlaneGeometry(8, 6), stainMat);
stainRight.position.set(14.7, 2.5, 2);
stainRight.rotation.y = -Math.PI / 2;
scene.add(stainRight);
// 地脚线
const baseboardMat = createMat(0x333333, 0.8);
const baseboardBack = new THREE.Mesh(new THREE.BoxGeometry(30, 0.6, 0.2), baseboardMat);
baseboardBack.position.set(0, 0.3, -14.9);
scene.add(baseboardBack);
const baseboardRight = new THREE.Mesh(new THREE.BoxGeometry(0.2, 0.6, 30), baseboardMat);
baseboardRight.position.set(14.9, 0.3, 0);
scene.add(baseboardRight);
// ==========================================
// 5. 核心家具重建 (书桌、空调、风扇、椅子)
// ==========================================
// --- 壁挂空调 ---
const acGroup = new THREE.Group();
const acBody = new THREE.Mesh(new THREE.BoxGeometry(4, 1.2, 0.8), createMat(0xffffff, 0.4));
acBody.castShadow = true; acBody.receiveShadow = true;
acGroup.add(acBody);
const acVent = new THREE.Mesh(new THREE.BoxGeometry(3.6, 0.15, 0.1), createMat(0xdddddd, 0.2));
acVent.position.set(0, -0.45, 0.35); acGroup.add(acVent);
// 管道
const pipeCurve = new THREE.CatmullRomCurve3([
new THREE.Vector3(2, -0.2, 0), new THREE.Vector3(4, -0.8, 0.5),
new THREE.Vector3(6, -4, 0.5), new THREE.Vector3(6, -8, 0.5)
]);
const pipe = new THREE.Mesh(new THREE.TubeGeometry(pipeCurve, 20, 0.05, 8, false), createMat(0xeeeeee, 0.8));
acGroup.add(pipe);
acGroup.position.set(0, 11, -14.6);
scene.add(acGroup);
// --- 右侧书桌 (带抽屉和电脑) ---
const deskGroup = new THREE.Group();
const deskX = 8, deskY = 2.5, deskZ = -12;
const deskTop = new THREE.Mesh(new THREE.BoxGeometry(6, 0.2, 2.5), createMat(0x8b5a2b, 0.6));
deskTop.castShadow = true; deskTop.receiveShadow = true;
deskGroup.add(deskTop);
// 抽屉
const drawerBody = new THREE.Mesh(new THREE.BoxGeometry(2, 3.8, 2.3), createMat(0x754a22, 0.7));
drawerBody.position.set(-2, -2, 0); drawerBody.castShadow = true; drawerBody.receiveShadow = true;
deskGroup.add(drawerBody);
// 显示器
const monitorBase = new THREE.Mesh(new THREE.CylinderGeometry(0.5, 0.7, 0.2, 16), createMat(0x222222, 0.4));
monitorBase.position.set(1.5, 0.2, 0); deskGroup.add(monitorBase);
const monitorStand = new THREE.Mesh(new THREE.CylinderGeometry(0.08, 0.08, 1, 8), createMat(0x333333, 0.4));
monitorStand.position.set(1.5, 0.7, 0); deskGroup.add(monitorStand);
const screen = new THREE.Mesh(new THREE.BoxGeometry(2, 1.3, 0.1), createMat(0x111111, 0.2));
screen.position.set(1.5, 1.5, 0); screen.castShadow = true; deskGroup.add(screen);
// 电脑主机
const pcTower = new THREE.Mesh(new THREE.BoxGeometry(1, 2.5, 1.8), createMat(0x1a1a1a, 0.3, 0.5));
pcTower.position.set(2.5, -1.25, 0.5); pcTower.castShadow = true; pcTower.receiveShadow = true;
deskGroup.add(pcTower);
deskGroup.position.set(deskX, deskY, deskZ);
scene.add(deskGroup);
// --- 粉色转椅 ---
const chairGroup = new THREE.Group();
const backGeo = new THREE.CylinderGeometry(1.1, 1.1, 2, 32, 1, false, 0, Math.PI);
const chairMat = createMat(0xf4b6c2, 0.6);
const chairBack = new THREE.Mesh(backGeo, chairMat);
chairBack.rotation.y = Math.PI; chairBack.position.set(0, 1.2, -0.7);
chairBack.scale.set(1, 1, 0.6); chairBack.castShadow = true; chairGroup.add(chairBack);
const cushion = new THREE.Mesh(new THREE.BoxGeometry(1.8, 0.4, 1.8), chairMat);
cushion.castShadow = true; chairGroup.add(cushion);
const pole = new THREE.Mesh(new THREE.CylinderGeometry(0.15, 0.15, 1.5, 12), createMat(0xcccccc, 0.2, 0.8));
pole.position.set(0, -0.8, 0); chairGroup.add(pole);
const base = new THREE.Mesh(new THREE.CylinderGeometry(1.3, 1.3, 0.1, 32), createMat(0xffffff, 0.3));
base.position.set(0, -1.5, 0); base.castShadow = true; chairGroup.add(base);
const wheelMat = createMat(0x333333, 0.5);
for(let i=0; i<5; i++) {
const angle = (i / 5) * Math.PI * 2;
const wheel = new THREE.Mesh(new THREE.CylinderGeometry(0.12, 0.12, 0.1, 16), wheelMat);
wheel.rotation.z = Math.PI / 2;
wheel.position.set(Math.cos(angle) * 1.2, -1.6, Math.sin(angle) * 1.2);
chairGroup.add(wheel);
}
chairGroup.position.set(6, 2.5, -9);
scene.add(chairGroup);
// ==========================================
// 6. 新增区域:右侧飘窗与窗户
// ==========================================
const windowX = 14.7, windowZ = 2;
// 窗台(飘窗台面)
const windowSillMat = createMat(0xffffff, 0.7);
const windowSill = new THREE.Mesh(new THREE.BoxGeometry(2.5, 0.5, 10), windowSillMat);
windowSill.position.set(windowX - 1.25, 2, windowZ);
windowSill.receiveShadow = true; scene.add(windowSill);
// 飘窗毛绒垫(绿色)
const rugMat = createMat(0x7ec850, 1.0);
const rug = new THREE.Mesh(new THREE.BoxGeometry(2.3, 0.1, 9.5), rugMat);
rug.position.set(windowX - 1.25, 2.3, windowZ);
rug.receiveShadow = true; scene.add(rug);
// 窗户边框(绿色)
const frameMat = createMat(0x2e8b57, 0.6);
const frameTop = new THREE.Mesh(new THREE.BoxGeometry(0.2, 0.3, 10), frameMat);
frameTop.position.set(windowX, 6.5, windowZ); scene.add(frameTop);
const frameBottom = new THREE.Mesh(new THREE.BoxGeometry(0.2, 0.3, 10), frameMat);
frameBottom.position.set(windowX, 2.5, windowZ); scene.add(frameBottom);
const frameLeft = new THREE.Mesh(new THREE.BoxGeometry(0.2, 4, 0.3), frameMat);
frameLeft.position.set(windowX, 4.5, windowZ - 4.85); scene.add(frameLeft);
const frameRight = new THREE.Mesh(new THREE.BoxGeometry(0.2, 4, 0.3), frameMat);
frameRight.position.set(windowX, 4.5, windowZ + 4.85); scene.add(frameRight);
// 窗户玻璃
const glassMat = new THREE.MeshStandardMaterial({ color: 0xaaccff, transparent: true, opacity: 0.2, roughness: 0.1, metalness: 0.1 });
const glass = new THREE.Mesh(new THREE.PlaneGeometry(9.5, 4), glassMat);
glass.position.set(windowX, 4.5, windowZ);
glass.rotation.y = -Math.PI / 2;
scene.add(glass);
// 防盗网(简化为细圆柱体)
const barMat = createMat(0xaaaaaa, 0.5, 0.8);
for(let i = -4; i <= 4; i+=1) {
const bar = new THREE.Mesh(new THREE.CylinderGeometry(0.04, 0.04, 4, 8), barMat);
bar.position.set(windowX - 0.1, 4.5, windowZ + i * 1.1);
scene.add(bar);
}
// 飘窗上的被子(用不规则的几何体模拟)
const quiltMat = createMat(0xbbccee, 0.9);
const quilt = new THREE.Mesh(new THREE.BoxGeometry(1.8, 0.8, 3), quiltMat);
quilt.position.set(windowX - 1, 2.8, windowZ - 1);
quilt.rotation.z = 0.1; quilt.castShadow = true;
scene.add(quilt);
// 飘窗上的枕头
const pillowMat = createMat(0xffee88, 0.9);
const pillow = new THREE.Mesh(new THREE.BoxGeometry(1.5, 0.6, 1.2), pillowMat);
pillow.position.set(windowX - 1.2, 2.8, windowZ + 3.5);
pillow.rotation.y = 0.5; pillow.castShadow = true;
scene.add(pillow);
// 窗帘(波浪形)
const curtainMat = createMat(0xfdfaf7, 0.9, 0.0, createMatTextureWithPattern());
function createMatTextureWithPattern() {
const canvas = document.createElement('canvas');
canvas.width = 256; canvas.height = 256;
const ctx = canvas.getContext('2d');
ctx.fillStyle = '#fdfaf7'; ctx.fillRect(0, 0, 256, 256);
ctx.fillStyle = '#fce4ec'; // 淡粉色花纹
for(let i=0; i<256; i+=32) {
ctx.beginPath(); ctx.arc(i, 64, 10, 0, Math.PI*2); ctx.fill();
ctx.beginPath(); ctx.arc(i+16, 192, 10, 0, Math.PI*2); ctx.fill();
}
const tex = new THREE.CanvasTexture(canvas);
tex.wrapS = THREE.RepeatWrapping; tex.wrapT = THREE.RepeatWrapping;
tex.repeat.set(2, 4);
return tex;
}
const curtainGeo = new THREE.PlaneGeometry(2.5, 12, 20, 20);
const curtain = new THREE.Mesh(curtainGeo, curtainMat);
const posAttr = curtain.geometry.attributes.position;
for (let i = 0; i < posAttr.count; i++) {
const y = posAttr.getY(i);
posAttr.setZ(i, Math.sin(y * 2) * 0.2);
}
curtain.geometry.computeVertexNormals();
curtain.position.set(windowX - 0.5, 7, windowZ - 4);
curtain.rotation.y = -Math.PI / 2;
scene.add(curtain);
// 帷幔(顶部装饰)
const valance = new THREE.Mesh(new THREE.BoxGeometry(0.5, 1.5, 10), curtainMat);
valance.position.set(windowX - 0.5, 10, windowZ);
scene.add(valance);
// ==========================================
// 7. 新增区域:左侧衣柜与烘干机
// ==========================================
const wardrobeX = -12, wardrobeZ = -7;
// 衣柜主体(木色)
const wardrobeMat = createMat(0x8b5a2b, 0.7);
const wardrobeBody = new THREE.Mesh(new THREE.BoxGeometry(6, 10, 4), wardrobeMat);
wardrobeBody.position.set(wardrobeX, 5, wardrobeZ);
wardrobeBody.castShadow = true; wardrobeBody.receiveShadow = true;
scene.add(wardrobeBody);
// 衣柜门(磨砂玻璃)
const doorMat = new THREE.MeshStandardMaterial({ color: 0xcce0cc, transparent: true, opacity: 0.5, roughness: 0.1 });
const wardrobeDoor = new THREE.Mesh(new THREE.BoxGeometry(0.2, 9.5, 3.5), doorMat);
wardrobeDoor.position.set(wardrobeX + 3, 4.8, wardrobeZ);
scene.add(wardrobeDoor);
// 衣柜内部隔板
const shelfMat = createMat(0x654321, 0.8);
for(let y = 2; y <= 8; y += 2) {
const shelf = new THREE.Mesh(new THREE.BoxGeometry(5.5, 0.2, 3.5), shelfMat);
shelf.position.set(wardrobeX - 0.2, y, wardrobeZ);
scene.add(shelf);
}
// --- 蓝色便携烘干机 ---
const dryerX = -6, dryerZ = -11;
const dryerBody = new THREE.Mesh(new THREE.BoxGeometry(3, 6, 3), createMat(0x5bbce4, 0.7));
dryerBody.position.set(dryerX, 3, dryerZ);
dryerBody.castShadow = true; dryerBody.receiveShadow = true;
scene.add(dryerBody);
// 烘干机拉链口(用深色平面模拟)
const dryerZip = new THREE.Mesh(new THREE.PlaneGeometry(1.5, 3), createMat(0x1a6a99, 0.5));
dryerZip.position.set(dryerX, 3, dryerZ + 1.51);
scene.add(dryerZip);
// 烘干机底座
const dryerBase = new THREE.Mesh(new THREE.BoxGeometry(3.2, 0.5, 3.2), createMat(0xffffff, 0.5));
dryerBase.position.set(dryerX, 0.25, dryerZ);
scene.add(dryerBase);
// --- 木制衣帽架 ---
const rackX = -3, rackZ = -12;
const rackPole = new THREE.Mesh(new THREE.CylinderGeometry(0.15, 0.15, 9, 12), wardrobeMat);
rackPole.position.set(rackX, 4.5, rackZ);
rackPole.castShadow = true; scene.add(rackPole);
// 挂钩
for(let i=0; i<4; i++) {
const angle = (i / 4) * Math.PI * 2;
const hook = new THREE.Mesh(new THREE.CylinderGeometry(0.05, 0.05, 1.5, 8), wardrobeMat);
hook.rotation.z = Math.PI / 2;
hook.position.set(rackX + Math.cos(angle)*0.75, 8, rackZ + Math.sin(angle)*0.75);
hook.rotation.y = angle;
scene.add(hook);
}
// 挂着的衣服(简化为不同颜色的方块)
const clothMat1 = createMat(0xffffff, 0.9); // 白色衬衫
const cloth1 = new THREE.Mesh(new THREE.BoxGeometry(0.8, 2.5, 0.1), clothMat1);
cloth1.position.set(rackX, 7, rackZ + 0.5); cloth1.rotation.y = 0.2; scene.add(cloth1);
const clothMat2 = createMat(0x444444, 0.9); // 黑色外套
const cloth2 = new THREE.Mesh(new THREE.BoxGeometry(1, 2.8, 0.2), clothMat2);
cloth2.position.set(rackX - 0.5, 6.5, rackZ - 0.5); cloth2.rotation.y = -0.3; scene.add(cloth2);
// ==========================================
// 8. 新增区域:床边角落(床头柜、藤椅)
// ==========================================
// 白色小床头柜
const tableX = 11, tableZ = 8;
const nightstand = new THREE.Mesh(new THREE.BoxGeometry(2, 3, 2), createMat(0xf0f0f0, 0.8));
nightstand.position.set(tableX, 1.5, tableZ);
nightstand.castShadow = true; nightstand.receiveShadow = true;
scene.add(nightstand);
// 床头柜上的纸张
const paper = new THREE.Mesh(new THREE.PlaneGeometry(1.5, 1), createMat(0xffffff, 0.9));
paper.rotation.x = -Math.PI / 2; paper.position.set(tableX, 3.01, tableZ);
scene.add(paper);
// 藤编圆椅(用棕色圆环和圆柱模拟)
const rattanX = 14, rattanZ = 8;
const rattanBase = new THREE.Mesh(new THREE.CylinderGeometry(1.2, 1.2, 0.2, 16), createMat(0xa0522d, 0.9));
rattanBase.position.set(rattanX, 1, rattanZ); rattanBase.castShadow = true;
scene.add(rattanBase);
const rattanBack = new THREE.Mesh(new THREE.TorusGeometry(1, 0.1, 8, 20, Math.PI), createMat(0xa0522d, 0.9));
rattanBack.position.set(rattanX, 2, rattanZ); rattanBack.rotation.y = Math.PI/2; rattanBack.rotation.x = Math.PI/4;
scene.add(rattanBack);
// 黄色卡通抱枕(简化为黄色球体+白色球体组合)
const plushYellow = new THREE.Mesh(new THREE.SphereGeometry(0.8, 16, 16), createMat(0xffcc00, 0.8));
plushYellow.position.set(rattanX, 1.8, rattanZ); plushYellow.scale.set(1, 0.8, 1); plushYellow.castShadow = true;
scene.add(plushYellow);
const plushWhite = new THREE.Mesh(new THREE.SphereGeometry(0.5, 16, 16), createMat(0xffffff, 0.8));
plushWhite.position.set(rattanX, 2.2, rattanZ - 0.2); plushWhite.castShadow = true;
scene.add(plushWhite);
// ==========================================
// 9. 前景床铺 (凉席)
// ==========================================
const bedBase = new THREE.Mesh(new THREE.BoxGeometry(20, 0.8, 10), createMat(0x9e5a38, 0.9, 0.0, matTexture));
bedBase.position.set(0, 0.4, 12);
bedBase.receiveShadow = true;
scene.add(bedBase);
// 床铺白边
const bedEdgeMat = createMat(0xd3d3d3, 0.8);
const bedFrontEdge = new THREE.Mesh(new THREE.BoxGeometry(20.2, 0.2, 0.5), bedEdgeMat);
bedFrontEdge.position.set(0, 0.9, 16.75); bedFrontEdge.receiveShadow = true; scene.add(bedFrontEdge);
const bedLeftEdge = new THREE.Mesh(new THREE.BoxGeometry(0.5, 0.2, 10), bedEdgeMat);
bedLeftEdge.position.set(-9.85, 0.9, 12); bedLeftEdge.receiveShadow = true; scene.add(bedLeftEdge);
const bedRightEdge = bedLeftEdge.clone(); bedRightEdge.position.x = 9.85; scene.add(bedRightEdge);
// 床上的紫色花纹抱枕
const pillowPatternMat = createMat(0xd8bfd8, 0.9);
const bedPillow = new THREE.Mesh(new THREE.BoxGeometry(3, 0.8, 1.5), pillowPatternMat);
bedPillow.position.set(-4, 1.3, 14); bedPillow.rotation.y = 0.2;
scene.add(bedPillow);
// ==========================================
// 10. 动画与渲染循环
// ==========================================
function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
}
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
animate();
</script>
</body>
</html>Game Source: 我的房间 - 全景 3D 还原
Creator: EpicCoder88
Libraries: three
Complexity: complex (474 lines, 22.8 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-epiccoder88" to link back to the original. Then publish at arcadelab.ai/publish.