62 lines
1.8 KiB
JavaScript
62 lines
1.8 KiB
JavaScript
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
|
|
|
|
/**
|
|
* Loads a single room (environment) GLB into the scene.
|
|
* Shares loader/pattern with objectLoader but applies room-specific tweaks:
|
|
* - fixDepth: per-mesh depthWrite / polygonOffset to suppress z-fighting
|
|
* (ported from client/reference/app-RIKOROOM.js)
|
|
* Works automatically in VR — the room lives in the same scene graph as the
|
|
* VR dolly and controllers.
|
|
*/
|
|
|
|
const loader = new GLTFLoader();
|
|
|
|
export async function loadRoom(scene, config) {
|
|
if (!config || !config.enabled || !config.url) return null;
|
|
|
|
try {
|
|
const gltf = await loader.loadAsync(config.url);
|
|
const model = gltf.scene;
|
|
|
|
const [px, py, pz] = config.position ?? [0, 0, 0];
|
|
const [rx, ry, rz] = config.rotation ?? [0, 0, 0];
|
|
const s = config.scale ?? [1, 1, 1];
|
|
const [sx, sy, sz] = Array.isArray(s) ? s : [s, s, s];
|
|
|
|
model.position.set(px, py, pz);
|
|
model.rotation.set(rx, ry, rz);
|
|
model.scale.set(sx, sy, sz);
|
|
model.name = 'room';
|
|
|
|
model.traverse((child) => {
|
|
if (!child.isMesh) return;
|
|
child.castShadow = false;
|
|
child.receiveShadow = true;
|
|
|
|
if (config.fixDepth) {
|
|
child.geometry.computeBoundingBox();
|
|
child.geometry.computeBoundingSphere();
|
|
child.geometry.computeVertexNormals();
|
|
|
|
if (child.material) {
|
|
child.material.depthWrite = true;
|
|
child.material.depthTest = true;
|
|
child.material.polygonOffset = true;
|
|
child.material.polygonOffsetFactor = -1;
|
|
child.material.polygonOffsetUnits = -1;
|
|
}
|
|
|
|
child.updateMatrix();
|
|
child.updateMatrixWorld(true);
|
|
}
|
|
});
|
|
|
|
scene.add(model);
|
|
console.log(`🏠 Room loaded: ${config.url}`);
|
|
return model;
|
|
} catch (err) {
|
|
console.error(`Failed to load room from ${config.url}:`, err);
|
|
return null;
|
|
}
|
|
}
|