Debugging Physics
Visualize and debug physics to diagnose issues:
// Enable physics debug visualization
const physicsViewer = new BABYLON.PhysicsViewer(scene);
// Show impostors for specific objects
physicsViewer.showImpostor(box.physicsImpostor, box);
physicsViewer.showImpostor(sphere.physicsImpostor, sphere);
// Visualize all physics impostors in the scene
scene.meshes.forEach(mesh => {
if (mesh.physicsImpostor) {
physicsViewer.showImpostor(mesh.physicsImpostor, mesh);
}
});
// Add debugging UI
const debugLayer = new BABYLON.GUI.AdvancedDynamicTexture.CreateFullscreenUI("UI");
const panel = new BABYLON.GUI.StackPanel();
panel.width = "220px";
panel.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_RIGHT;
panel.verticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_TOP;
debugLayer.addControl(panel);
// Button to toggle physics debug visibility
const showPhysicsButton = BABYLON.GUI.Button.CreateSimpleButton("showPhysics", "Toggle Physics Debug");
showPhysicsButton.width = "200px";
showPhysicsButton.height = "40px";
showPhysicsButton.color = "white";
showPhysicsButton.background = "green";
showPhysicsButton.onPointerUpObservable.add(() => {
// Toggle all impostor renderers
physicsViewer.isEnabled = !physicsViewer.isEnabled;
});
panel.addControl(showPhysicsButton);
// Button to pause/resume physics
const pausePhysicsButton = BABYLON.GUI.Button.CreateSimpleButton("pausePhysics", "Pause Physics");
pausePhysicsButton.width = "200px";
pausePhysicsButton.height = "40px";
pausePhysicsButton.color = "white";
pausePhysicsButton.background = "blue";
let physicsEnabled = true;
pausePhysicsButton.onPointerUpObservable.add(() => {
if (physicsEnabled) {
// Pause physics
scene.getPhysicsEngine().setTimeStep(0);
pausePhysicsButton.textBlock.text = "Resume Physics";
} else {
// Resume physics
scene.getPhysicsEngine().setTimeStep(1/60);
pausePhysicsButton.textBlock.text = "Pause Physics";
}
physicsEnabled = !physicsEnabled;
});
panel.addControl(pausePhysicsButton);
// Button to reset all physics objects
const resetPhysicsButton = BABYLON.GUI.Button.CreateSimpleButton("resetPhysics", "Reset Physics");
resetPhysicsButton.width = "200px";
resetPhysicsButton.height = "40px";
resetPhysicsButton.color = "white";
resetPhysicsButton.background = "red";
resetPhysicsButton.onPointerUpObservable.add(() => {
// Reset all dynamic objects to their original positions
scene.meshes.forEach(mesh => {
if (mesh.physicsImpostor && mesh.physicsImpostor.mass > 0) {
// Reset position and rotation
if (mesh._originalPosition) {
mesh.position = mesh._originalPosition.clone();
mesh.rotationQuaternion = mesh._originalRotation ?
mesh._originalRotation.clone() : new BABYLON.Quaternion();
// Reset velocities
mesh.physicsImpostor.setLinearVelocity(BABYLON.Vector3.Zero());
mesh.physicsImpostor.setAngularVelocity(BABYLON.Vector3.Zero());
}
}
});
});
panel.addControl(resetPhysicsButton);
// Store original positions for reset functionality
scene.meshes.forEach(mesh => {
if (mesh.physicsImpostor) {
mesh._originalPosition = mesh.position.clone();
mesh._originalRotation = mesh.rotationQuaternion ?
mesh.rotationQuaternion.clone() : null;
}
});
// Log physics activity
let collisionCount = 0;
scene.meshes.forEach(mesh => {
if (mesh.physicsImpostor) {
mesh.physicsImpostor.onCollideEvent = (collider, collidedWith) => {
collisionCount++;
console.log(`Collision #${collisionCount}: ${collider.object.name} hit ${collidedWith.object.name}`);
// Get collision velocity
const relVelocity = collider.getLinearVelocity().subtract(
collidedWith.getLinearVelocity()
).length();
console.log(`Impact velocity: ${relVelocity.toFixed(2)}`);
};
}
});