I am using playcanvas standalone engine to upload a GLB file. This is a large GLB file of size 230 MB
here are the stats of the GLB file
- Stats:
- 379 draw calls
- 0 animations
- 122 materials
- 2359648 vertices
- 3362654 triangles
- Extensions:
- KHR_materials_specular
- KHR_materials_ior
- KHR_materials_anisotropy
- KHR_materials_transmission
- KHR_texture_transform
- KHR_materials_clearcoat
i am using the below code to import a GLB file and make its mesh colliders on the go.
assembleAndLoadModel4() {
if (this.modelAssembled) {
debugLog('Model already assembled. Skipping...');
return;
}
this.modelAssembled = true;
debugLog('Assembling model...');
const assembledBuffer = new ArrayBuffer(this.chunks.reduce((total, chunk) => total + chunk.byteLength, 0));
const assembledView = new Uint8Array(assembledBuffer);
let offset = 0;
this.chunks.forEach(chunk => {
assembledView.set(new Uint8Array(chunk), offset);
offset += chunk.byteLength;
});
this.chunks = [];
const modelBlob = new Blob([assembledBuffer], { type: 'model/gltf-binary' });
const modelUrl = URL.createObjectURL(modelBlob);
const asset = new Asset('assembled-model', 'container', { url: modelUrl });
asset.streaming = true;
this.app.assets.add(asset);
asset.on('load', () => {
URL.revokeObjectURL(modelUrl);
debugLog('Model fully loaded and assembled');
this.modelContainer.children.slice().forEach(child => child.destroy());
// Create the main entity
const mainEntity = new Entity('MainModel');
this.modelContainer.addChild(mainEntity);
if (asset.resource && asset.resource.model) {
mainEntity.addComponent('model', {
type: 'asset',
asset: asset.resource.model
});
debugLog('Added model component to main entity');
this.addMeshCollidersToModel(mainEntity, asset.resource);
} else {
debugLog('Error: No model resource found in the loaded asset');
return;
}
// Center the model in view
if (mainEntity.model && mainEntity.model.model && mainEntity.model.model.meshInstances) {
const aabb = new pc.BoundingBox();
mainEntity.model.model.meshInstances.forEach(function (meshInstance) {
aabb.add(meshInstance.aabb);
});
const center = aabb.center;
const min = aabb.getMin();
this.app.fire('model:loaded', {
position: new Vec3(center.x, min.y + CAMERA_DEFAULT_HEIGHT, center.z),
});
}
// this.logModelBoundingBox(mainEntity);
});
asset.on('error', (err) => {
debugLog('Error loading assembled model:', err);
});
this.app.assets.load(asset);
}
addMeshCollidersToModel(mainEntity, model) {
if (!model || !model.model.resource.meshInstances) {
debugLog('Error: Invalid model structure');
return;
}
const meshInstances = model.model.resource.meshInstances;
debugLog(`Adding colliders to ${meshInstances.length} mesh instances`);
for (let i = 0; i < meshInstances.length; i++) {
const meshInstance = meshInstances[i];
const meshEntity = new Entity(`MeshEntity_${i}`);
mainEntity.addChild(meshEntity);
meshEntity.setLocalPosition(meshInstance.node.getLocalPosition());
meshEntity.setLocalRotation(meshInstance.node.getLocalRotation());
meshEntity.setLocalScale(meshInstance.node.getLocalScale());
meshEntity.addComponent('render', {
meshInstances: [meshInstance]
});
this.addSimplifiedCollider(meshEntity, meshInstance, i);
meshEntity.addComponent('rigidbody', {
type: 'static',
restitution: 0.5,
friction: 0.3
});
// meshEntity.collision.on('collisionstart', (result) => {
// debugLog(`Collision started for MeshEntity_${i} with ${result.other.name}`);
// });
// meshEntity.collision.on('collisionend', (result) => {
// debugLog(`Collision ended for MeshEntity_${i} with ${result.other.name}`);
// });
debugLog(`Added collider to MeshEntity_${i}`);
}
debugLog(`Added colliders to ${meshInstances.length} mesh instances`);
}
addSimplifiedCollider(meshEntity, meshInstance, index) {
try {
meshEntity.addComponent('collision', {
type: 'mesh',
convex: true
});
var node = new GraphNode();
var collisionModel = new Model();
collisionModel.graph = node;
collisionModel.meshInstances.push(meshInstance);
meshEntity.collision.model = collisionModel;
debugLog(`Added simplified mesh collider to MeshEntity_${index}`);
} catch (error) {
debugLog(`Failed to add simplified mesh collider to MeshEntity_${index}. Error: ${error.message}`);
debugLog('Falling back to box collider');
// Remove the failed collision component if it was added
if (meshEntity.collision) {
meshEntity.removeComponent('collision');
}
// Calculate bounding box for the mesh instance
const aabb = new BoundingBox();
aabb.copy(meshInstance.aabb);
// Add a box collider based on the bounding box
meshEntity.addComponent('collision', {
type: 'box',
halfExtents: aabb.halfExtents
});
var node = new GraphNode();
var collisionModel = new Model();
collisionModel.graph = node;
collisionModel.meshInstances.push(meshInstance);
meshEntity.collision.model = collisionModel;
debugLog(`Added box collider to MeshEntity_${index} as fallback`);
}
}
I even added a catch statement with help of GPT to handle the error but after generating colliders for some mesh ammo goes oom
Below is the error statement
ammo.wasm.js:14 Uncaught RuntimeError: Aborted(OOM). Build with -sASSERTIONS for more info.
at oa (ammo.wasm.js:14:197)
at c (ammo.wasm.js:23:211)
at ammo.wasm.wasm:0xb8de
at ammo.wasm.wasm:0x1a2dd
at ammo.wasm.wasm:0x3dd2
at ammo.wasm.wasm:0x4018
at ammo.wasm.wasm:0x80f96
at ammo.wasm.wasm:0x2f7bd
at x.stepSimulation (ammo.wasm.js:578:204)
at RigidBodyComponentSystem.onUpdate (playcanvas.js?v=4e08f406:60799:24)
ammo.wasm.js:14 failed to initialize module=Ammo error=wasm module aborted.