Playcanvas seems to currently only use btBvhTriangleMeshShape as mesh colliders, which can be concave but they are less performant and they can’t collide with each other.
I’ve written a script I’d like to share with you which instead uses btConvexHullShape for all mesh colliders, so if you have this script in your project, your rigidbodies with mesh colliders will collide with each other and performance and stability of the simulation should be better too.
HOWEVER: It replaces all your mesh colliders with their convex hulls, so make sure you understand what that means! If you want to use concave meshes with it, you should first create a convex decomposition and store the convex parts as different submeshes, then this should work too.
If you want to use both btBvhTriangleMeshShape and btConvexHullShape I guess you can relatively easily extend this script to only use convexHull shapes for meshcolliders that you specifically mark.
I also have a question though: This is my first week with javascript and I still try to get the hang on it. Would there be a more elegant way of doing this (especially in relation to the type of script !function(){}(); and replacing the createPhysicalShape function of the private system implementation through the proto object)?
The script was written against 1.4.0-dev, so might not work with newer versions:
!(function() {
pc.CollisionComponentSystem.prototype.overrideMeshShapeCreation = function() {
this._createImplementation('mesh');
this.implementations['mesh'].__proto__.createPhysicalShape = function (entity, data) {
if (typeof Ammo !== 'undefined' && data.model) {
var model = data.model;
var shape = new Ammo.btCompoundShape();
var i, j, t;
for (i = 0; i < model.meshInstances.length; i++) {
var meshInstance = model.meshInstances[i];
var mesh = meshInstance.mesh;
var ib = mesh.indexBuffer[pc.RENDERSTYLE_SOLID];
var vb = mesh.vertexBuffer;
var format = vb.getFormat();
var stride = format.size / 4;
var positions;
for (j = 0; j < format.elements.length; j++) {
var element = format.elements[j];
if (element.name === pc.SEMANTIC_POSITION) {
positions = new Float32Array(vb.lock(), element.offset);
}
}
var indices = new Uint16Array(ib.lock());
var numTriangles = mesh.primitive[0].count / 3;
var convexHullShape = new Ammo.btConvexHullShape();
var seen = {};
var p = new Ammo.btVector3();
var base = mesh.primitive[0].base;
for (j = 0; j < numTriangles; j++) {
for(t=0; t < 3; t++) {
var idx = indices[base + j * 3 + t] * stride;
if(!seen.hasOwnProperty[idx]) {
seen[idx] = true;
p.setValue(positions[idx], positions[idx + 1], positions[idx + 2]);
convexHullShape.addPoint(p, true);
}
}
}
var wtm = meshInstance.node.getWorldTransform();
var scl = wtm.getScale();
convexHullShape.setLocalScaling(new Ammo.btVector3(scl.x, scl.y, scl.z));
var pos = meshInstance.node.getPosition();
var rot = meshInstance.node.getRotation();
var transform = new Ammo.btTransform();
transform.setIdentity();
transform.getOrigin().setValue(pos.x, pos.y, pos.z);
var ammoQuat = new Ammo.btQuaternion();
ammoQuat.setValue(rot.x, rot.y, rot.z, rot.w);
transform.setRotation(ammoQuat);
shape.addChildShape(transform, convexHullShape);
}
var entityTransform = entity.getWorldTransform();
var scale = entityTransform.getScale();
var vec = new Ammo.btVector3();
vec.setValue(scale.x, scale.y, scale.z);
shape.setLocalScaling(vec);
return shape;
}
return undefined;
}
};
pc.CollisionComponentSystem.prototype.recreateAllShapes = function() {
var components = this.store;
for (var id in components) {
this.recreatePhysicalShapes(components[id]);
}
};
pc.Application.getApplication().systems.collision.overrideMeshShapeCreation();
pc.Application.getApplication().systems.collision.recreateAllShapes();
})();