Ok, I improved some stuff about the physics, but the problem of the collision shapes is still here. It’s better, but still present (it’s not a rectangular box anymore, but the shapes are still incorrect).
I uploaded my project into an archive. I also translated some comments. The project uses “Vite.”
Link archive: Upload Files | Free File Upload and Transfer Up To 20 GB (you have to do “npm install” and “npm run dev” to run it)
You can press “G” or “F” to make the camera follow the main model, and use the arrows to move the model. You can also hold the left-click and then move your mouse to move the camera, or you can press CTRL + LEFT CLICK and then move the mouse to rotate the camera (this does not work if you have the “G” view activated because the camera is locked on the model).
The problem is probably coming from the function “createPhysicsBody” in the file “collisionWorker.js.” There is also a function “checkCollisions,” and I don’t know why but now it always says that the bodies are colliding even when they are not, while the function “setupCollisionDetection,” which uses “havokPlugin.onCollisionObservable.add,” does not detect anything.
(I haven’t finished synchronizing the model’s movements between both threads, so there’s no need to mention the unsmooth movements )
There is a new version of my “createPhysicsBody.” If you have any new suggestions I could try, but honestly, I have tried a lot of different things over the last 4 days and nothing worked. I also tried ChatGPT and Perplexity AI, they gave me a bunch of different solutions that i tried, but nothing solved the problem. I reduced the number of polygons/meshes with Cinema4D, but it didn’t improve anything.
Thank you to everyone for your help.
You can reach me by PM with a BNB (Binance Smart Chain) address or ETH (Ethereum main net) address to receive compensation if you succeed in solving my problem.
function createPhysicsBody(meshes, name) {
console.log(`Creating physics body for ${name}`);
if (!meshes || meshes.length === 0) {
console.error(`No valid meshes provided for ${name}`);
return null;
}
let compoundMesh;
// If there is only one mesh, no need to merge
if (meshes.length === 1) {
compoundMesh = meshes[0];
} else {
// Filter valid meshes
const validMeshes = meshes.filter(mesh =>
mesh && mesh.getVerticesData && mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind)
);
if (validMeshes.length === 0) {
console.error(`No valid meshes to merge for ${name}`);
return null;
}
// Attempt the merge
compoundMesh = BABYLON.Mesh.MergeMeshes(validMeshes, true, true, undefined, false, true);
}
if (!compoundMesh) {
console.error(`Failed to create compound mesh for ${name}`);
return null;
}
compoundMesh.name = name;
// Define initial position and rotation
let initialPosition, initialRotation, mass, motionType;
if (name === "SF_CockpitG") {
mass = 1; // A very low mass
initialPosition = new BABYLON.Vector3(0, 0, 0);
initialRotation = BABYLON.Quaternion.RotationYawPitchRoll(Math.PI, 0, 0);
motionType = BABYLON.PhysicsMotionType.DYNAMIC;
} else if (name === "Carrier_VX-8") {
mass = 100000; // A very high mass
initialPosition = new BABYLON.Vector3(3, 0, 0);
initialRotation = BABYLON.Quaternion.RotationYawPitchRoll(Math.PI, 0, 0);
motionType = BABYLON.PhysicsMotionType.DYNAMIC;
} else {
mass = 1000;
initialPosition = new BABYLON.Vector3(0, 0, 0);
initialRotation = BABYLON.Quaternion.Identity();
motionType = BABYLON.PhysicsMotionType.DYNAMIC;
}
// Apply initial position and rotation to the mesh
compoundMesh.position = initialPosition;
compoundMesh.rotationQuaternion = initialRotation;
console.log(compoundMesh)
// Create the physics body
const physicsBody = new BABYLON.PhysicsBody(compoundMesh, motionType, false, scene);
// Create the physics shape
const physicsShape = new BABYLON.PhysicsShapeMesh(compoundMesh, scene);
// Set the shape of the physics body
havokPlugin.setShape(physicsBody, physicsShape);
// Apply initial position and rotation directly to the physics body
physicsBody.transformNode.position = initialPosition;
physicsBody.transformNode.rotationQuaternion = initialRotation;
// Define mass properties
havokPlugin.setMassProperties(physicsBody, {
mass: mass,
inertia: new BABYLON.Vector3(mass * 100, mass * 100, mass * 100),
centerOfMass: new BABYLON.Vector3(0, 0, 0),
});
// Adjust friction and restitution properties
let friction, restitution;
if (name === "SF_CockpitG") {
friction = 0.1; // Low friction
restitution = 0.1; // Low bounce
} else if (name === "Carrier_VX-8") {
friction = 0.8; // High friction
restitution = 0.2; // Moderate bounce
} else {
friction = 0.5;
restitution = 0.5;
}
// Apply friction and restitution to the physics shape
physicsShape.material = {
friction: friction,
restitution: restitution
};
// Store the physics body in the physicsBodies object
physicsBodies[name] = physicsBody;
// Send mesh information to the main thread
const positions = compoundMesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
const indices = compoundMesh.getIndices();
self.postMessage({
type: 'meshCreated',
name: name,
meshData: {
positions: positions,
indices: indices
}
});
console.log(`Physics body created for ${name} at position:`, initialPosition);
}
function setupCollisionDetection() {
havokPlugin.onCollisionObservable.add((collisionEvent) => {
const bodyA = collisionEvent.collider;
const bodyB = collisionEvent.collidedAgainst;
// Filter specific collisions
if ((bodyA.transformNode.name === "SF_CockpitG" && bodyB.transformNode.name === "Carrier_VX-8") ||
(bodyA.transformNode.name === "Carrier_VX-8" && bodyB.transformNode.name === "SF_CockpitG")) {
console.log("Collision detected between SF_CockpitG and Carrier_VX-8");
}
});
}
function simulatePhysics() {
applyControls();
// Convert the physicsBodies object into an array of physics bodies
const physicsBodiesArray = Object.values(physicsBodies);
// Simulate physics
havokPlugin.executeStep(1 / fpsControl, physicsBodiesArray);
// Correct positions and rotations after simulation
const targetHeight = 1; // Use the same value as in applyControls
for (const body of physicsBodiesArray) {
// Maintain constant height
body.transformNode.position.y = targetHeight;
// Reset vertical velocity
const currentVelocity = new BABYLON.Vector3();
havokPlugin.getLinearVelocityToRef(body, currentVelocity);
currentVelocity.y = 0;
havokPlugin.setLinearVelocity(body, currentVelocity);
// Maintain vertical rotation (prevent tipping)
const currentRotation = body.transformNode.rotationQuaternion;
const eulerAngles = currentRotation.toEulerAngles();
const correctedRotation = BABYLON.Quaternion.RotationYawPitchRoll(
eulerAngles.y, // Preserve rotation around the Y-axis (yaw)
0, // Reset rotation around the X-axis (pitch) to 0
0 // Reset rotation around the Z-axis (roll) to 0
);
body.transformNode.rotationQuaternion = correctedRotation;
// Reset angular velocity
havokPlugin.setAngularVelocity(body, BABYLON.Vector3.Zero());
}
const positions = {};
for (const [name, body] of Object.entries(physicsBodies)) {
const position = body.transformNode.position;
const rotation = body.transformNode.rotationQuaternion;
positions[name] = {
x: position.x,
y: position.y,
z: position.z,
rotation: {
x: rotation.x,
y: rotation.y,
z: rotation.z,
w: rotation.w
}
};
}
self.postMessage({
type: 'positionUpdate',
positions: positions
});
checkCollisions();
}
function checkCollisions() {
const bodies = Object.values(physicsBodies);
const collisionStates = {};
for (let i = 0; i < bodies.length; i++) {
const body1 = bodies[i].transformNode;
collisionStates[body1.name] = false;
for (let j = i + 1; j < bodies.length; j++) {
const body2 = bodies[j].transformNode;
if (body1 instanceof BABYLON.Mesh && body2 instanceof BABYLON.Mesh) {
if (body1.intersectsMesh(body2, true)) { // Use 'true' to check for precise polygon intersections
collisionStates[body1.name] = true;
collisionStates[body2.name] = true;
console.log(`Collision detected between ${body1.name} and ${body2.name}`);
}
}
}
}
self.postMessage({
type: 'collisionUpdate',
collisionStates: collisionStates
});
}
@Deltakosh Ok, i’m sorry. I will do my best now.