Here is my scene loading function:
//////////////////////////////////////////////////////////////
/////////////////////////// LOAD SCENE////////////////////////
// Function to load scene
async function loadScene(roomData) {
try {
clearCurrentScene();
// Object to store panel positions and meshes
let panelData = {};
// Dispose of the background mesh
if (backgroundMesh) {
backgroundMesh.dispose();
backgroundMesh = null;
}
// Create a transform node to hold the GLB meshes
const glbTransformNode = new BABYLON.TransformNode("glbTransformNode", scene);
// Load the new splat mesh
const splatMesh = await loadSplatMesh(roomData.urls[0]);
if (splatMesh) {
currentSplatMeshes.push(splatMesh);
// Position the GLB transform node at the splat mesh position
glbTransformNode.position = splatMesh.position;
} else {
console.warn(`Failed to load SPLAT mesh for room: ${roomData.name}`);
}
// Store panel data
scene.metadata = scene.metadata || {};
scene.metadata.panelData = panelData;
console.log("Panel data stored:", panelData);
// Load GLB models
await loadGLBModel(roomData.urls[1], glbTransformNode, roomData);
console.log("GLB model loaded successfully");
// Play the entry audio
if (roomData.entryaudio) {
const audioArrayBuffer = await loadLargeFile(roomData.entryaudio);
if (audioArrayBuffer) {
const audioBlob = new Blob([audioArrayBuffer], { type: 'audio/mpeg' });
await playAudio(URL.createObjectURL(audioBlob));
console.log("Entry audio started playing");
} else {
console.warn("Failed to load entry audio");
}
}
} catch (error) {
console.error("Error loading scene:", error);
}
}
async function loadSplatMesh(url) {
const splatScale = 1.5;
try {
console.log(`Starting to load SPLAT mesh from: ${url}`);
const splatArrayBuffer = await loadLargeFile(url);
if (!splatArrayBuffer) {
console.warn(`Failed to load SPLAT mesh from: ${url}`);
return null; // Return null instead of throwing an error
}
console.log(`SPLAT file size: ${splatArrayBuffer.byteLength} bytes`);
if (splatArrayBuffer.byteLength % 4 !== 0) {
console.warn(`Invalid SPLAT file size: ${splatArrayBuffer.byteLength} bytes (not a multiple of 4)`);
return null; // Return null instead of throwing an error
}
const splatMesh = new BABYLON.GaussianSplattingMesh("SplatLevel", null, scene);
await new Promise((resolve, reject) => {
try {
splatMesh._loadData(splatArrayBuffer);
resolve();
} catch (error) {
console.warn(`Error loading SPLAT data: ${error.message}`);
reject(error);
}
});
console.log("SPLAT mesh loaded successfully");
splatMesh.position = new BABYLON.Vector3(0, 1.7, 0);
splatMesh.scaling = new BABYLON.Vector3(splatScale, splatScale, splatScale);
splatMesh.isPickable = false;
return splatMesh;
} catch (error) {
console.error("Error loading SPLAT mesh:", error);
return null; // Return null instead of throwing an error
}
}
async function loadGLBModel(url, glbTransformNode, roomData) {
let assetContainer;
let neonMaterial;
try {
console.log("Starting to load GLB from:", url);
const glbArrayBuffer = await loadLargeFile(url);
if (!glbArrayBuffer) {
throw new Error("Failed to load GLB file");
}
console.log("GLB file fetched from cache or network");
// Ensure we're working with an ArrayBuffer
const arrayBuffer = glbArrayBuffer instanceof ArrayBuffer ? glbArrayBuffer : await glbArrayBuffer.arrayBuffer();
// Create a Blob from the ArrayBuffer
const blob = new Blob([arrayBuffer], { type: 'model/gltf-binary' });
const blobUrl = URL.createObjectURL(blob);
return new Promise((resolve, reject) => {
BABYLON.SceneLoader.LoadAssetContainer(
"",
blobUrl,
scene,
function (container) {
URL.revokeObjectURL(blobUrl);
assetContainer = container;
console.log("GLB loaded successfully", assetContainer);
// Log material information for debugging
container.meshes.forEach(mesh => {
if (mesh.material) {
console.log(`Material for mesh ${mesh.name}:`, mesh.material);
}
});
let panelData = {};
let teleporterMeshes = [];
neonMaterial = new BABYLON.StandardMaterial("neonMaterial", scene);
neonMaterial.emissiveColor = new BABYLON.Color3(0.35, 0.96, 0.88);
neonMaterial.alpha = 0.9;
neonMaterial.alphaMode = BABYLON.Constants.ALPHA_ADD;
assetContainer.addAllToScene();
processMeshes(assetContainer.meshes, glbTransformNode, neonMaterial, panelData, roomData, teleporterMeshes);
glbTransformNode.position = new BABYLON.Vector3(0, 1.7, 0);
glbTransformNode.scaling = new BABYLON.Vector3(-1, 1, 1);
handleTeleporters(teleporterMeshes);
console.log("Starting to load panels...");
loadPanels(roomData);
console.log("Finished loading panels");
resolve();
},
function (event) {
if (event.lengthComputable) {
const progress = event.loaded / event.total * 100;
console.log(`Loading progress: ${progress.toFixed(2)}%`);
}
},
function (scene, message, exception) {
URL.revokeObjectURL(blobUrl);
console.error(`Error loading GLB: ${message}`, exception);
reject(new Error(message));
},
".glb"
);
});
} catch (error) {
console.error("Error loading GLB:", error);
console.error("Stack trace:", error.stack);
if (assetContainer) {
assetContainer.dispose();
}
if (neonMaterial) {
neonMaterial.dispose();
}
throw error;
}
}
function processMeshes(meshes, glbTransformNode, neonMaterial, panelData, roomData, teleporterMeshes) {
console.log(`Processing ${meshes.length} meshes...`);
for (const mesh of meshes) {
try {
console.log(`Processing mesh: ${mesh.name}`);
mesh.parent = glbTransformNode;
mesh.isPickable = true;
mesh.renderingGroupId = 1;
if (mesh.name.toLowerCase().includes("collider")) {
mesh.visibility = 0;
mesh.isPickable = false;
mesh.checkCollisions = true;
console.log("Collider mesh found:", mesh.name);
}
new TeleportTarget(mesh, scene);
currentGLBMeshes.push(mesh);
if (mesh.name.toLowerCase().includes("teleport")) {
teleporterMeshes.push(mesh);
mesh.material = neonMaterial;
}
if (mesh.name.toLowerCase().includes("panel")) {
mesh.setEnabled(false);
scene.metadata.panelData[mesh.name] = {
position: mesh.getAbsolutePosition().clone(),
mesh: null
};
}
console.log("Mesh processed:", mesh.name);
} catch (error) {
console.error(`Error processing mesh ${mesh.name}:`, error);
}
}
console.log("All meshes processed");
}
function loadPanels(roomData) {
let locationData = buttonsData.find(location =>
location.rooms.some(room => room.name === roomData.name)
);
if (locationData && locationData.panels) {
locationData.panels.forEach(panelInfo => {
let panelData = scene.metadata.panelData[panelInfo.name];
if (panelData) {
loadPanelGLB(panelInfo, panelData.position)
.then(panelRoot => {
panelData.mesh = panelRoot;
})
.catch(error => console.error(`Failed to load panel: ${panelInfo.name}`, error));
}
});
}
}
async function loadPanelGLB(panelInfo, position) {
try {
console.log(`Loading panel GLB from: ${panelInfo.glbUrl}`);
const arrayBuffer = await loadLargeFile(panelInfo.glbUrl);
if (!arrayBuffer) {
throw new Error("Failed to load panel GLB file");
}
return new Promise((resolve, reject) => {
const blob = new Blob([arrayBuffer], { type: 'application/octet-stream' });
const url = URL.createObjectURL(blob);
BABYLON.SceneLoader.ImportMesh("", "", url, scene, function(panelMeshes) {
URL.revokeObjectURL(url);
console.log(`Panel GLB loaded, meshes:`, panelMeshes);
if (panelMeshes.length === 0) {
reject(new Error("No meshes were imported from the GLB file"));
return;
}
let panelRoot = new BABYLON.TransformNode("panelRoot", scene);
let importedRoot = panelMeshes[0];
while (importedRoot.parent && panelMeshes.includes(importedRoot.parent)) {
importedRoot = importedRoot.parent;
}
importedRoot.parent = panelRoot;
panelRoot.position = position;
panelRoot.scaling = new BABYLON.Vector3(1, 1, 1);
setupPanelMesh(importedRoot, panelInfo);
panelRoot.setEnabled(true);
console.log(`Panel loaded and positioned at ${panelRoot.position}`);
resolve(panelRoot);
}, null, function(scene, message, exception) {
URL.revokeObjectURL(url);
console.error(`Error loading panel GLB: ${message}`, exception);
reject(new Error(`Failed to load panel GLB: ${message}`));
}, ".glb");
});
} catch (error) {
console.error(`Error loading panel GLB: ${error}`);
throw error;
}
}
function setupPanelMesh(node, panelInfo) {
if (node instanceof BABYLON.AbstractMesh) {
node.isPickable = true;
node.renderingGroupId = 1;
// Create and apply the ClickPanelBehavior
const clickBehavior = new ClickPanelBehavior(node, 3, panelInfo.audioUrl);
// Convert the material
clickBehavior.convertToStandardMaterial();
// Preserve the original material
if (node.material) {
node.material.freeze();
}
}
node.getChildMeshes().forEach(childMesh => setupPanelMesh(childMesh, panelInfo));
}
function handleTeleporters(teleporterMeshes) {
if (teleporterMeshes.length === 0) {
console.log("No teleporter found in the imported GLB");
} else {
console.log("Teleporters found:", teleporterMeshes.length);
let firstTeleporter = teleporterMeshes[0];
console.log("First teleporter found:", firstTeleporter.getAbsolutePosition());
// Create a TeleportTarget for the first teleporter
const teleportTarget = new TeleportTarget(firstTeleporter, scene);
// Teleport the camera after a short delay
setTimeout(() => {
teleportTarget.teleportCamera();
}, 100); // 100ms delay, adjust as needed
}
}
// Function to clear the cache (useful for updating assets)
async function clearCache() {
const cache = await caches.open('large-file-cache');
const keys = await cache.keys();
for (const key of keys) {
await cache.delete(key);
}
console.log("Cache cleared");
}
/////////////////////////// LOAD SCENE////////////////////////
//////////////////////////////////////////////////////////////