From aa0956477d639c755adae62ac2eb4178deda7a25 Mon Sep 17 00:00:00 2001 From: austin Date: Wed, 4 Jun 2025 11:53:42 -0400 Subject: [PATCH] physics performance work --- .../electrosphere/client/ClientState.java | 3 +- .../collision/CollisionBodyCreation.java | 2 +- .../collision/CollisionEngine.java | 211 +++++++++++++---- .../collision/PhysicsCallback.java | 221 ++++++++++++++++++ .../collision/PhysicsEntityUtils.java | 23 +- .../electrosphere/collision/PhysicsUtils.java | 9 + .../collision/RayCastCallback.java | 4 +- .../entity/collidable/CollidableTemplate.java | 22 ++ .../server/datacell/RealmManager.java | 10 +- .../gridded/GriddedDataCellManager.java | 6 + .../datacell/physics/PhysicsDataCell.java | 6 +- .../CollisionEngineStaticSpaceTests.java | 78 +++++++ 12 files changed, 526 insertions(+), 69 deletions(-) create mode 100644 src/main/java/electrosphere/collision/PhysicsCallback.java create mode 100644 src/test/java/electrosphere/collision/CollisionEngineStaticSpaceTests.java diff --git a/src/main/java/electrosphere/client/ClientState.java b/src/main/java/electrosphere/client/ClientState.java index 1d5b9d7f..a64f7462 100644 --- a/src/main/java/electrosphere/client/ClientState.java +++ b/src/main/java/electrosphere/client/ClientState.java @@ -16,6 +16,7 @@ import electrosphere.client.terrain.cells.ClientDrawCellManager; import electrosphere.client.terrain.foliage.FoliageCellManager; import electrosphere.client.terrain.manager.ClientTerrainManager; import electrosphere.collision.CollisionEngine; +import electrosphere.collision.PhysicsCallback; import electrosphere.data.entity.common.CommonEntityType; import electrosphere.data.voxel.VoxelType; import electrosphere.engine.Globals; @@ -189,7 +190,7 @@ public class ClientState { * Constructor */ public ClientState(){ - this.clientSceneWrapper = new ClientSceneWrapper(this.clientScene, new CollisionEngine("clientPhysics"), CollisionEngine.create("clientChem", new ClientChemistryCollisionCallback()), new CollisionEngine("clientInteraction")); + this.clientSceneWrapper = new ClientSceneWrapper(this.clientScene, CollisionEngine.create("clientPhysics", new PhysicsCallback()), CollisionEngine.create("clientChem", new ClientChemistryCollisionCallback()), new CollisionEngine("clientInteraction")); this.clientTemporalService = (ClientTemporalService)Globals.engineState.serviceManager.registerService(new ClientTemporalService()); } diff --git a/src/main/java/electrosphere/collision/CollisionBodyCreation.java b/src/main/java/electrosphere/collision/CollisionBodyCreation.java index 09042e07..32172698 100644 --- a/src/main/java/electrosphere/collision/CollisionBodyCreation.java +++ b/src/main/java/electrosphere/collision/CollisionBodyCreation.java @@ -264,7 +264,7 @@ public class CollisionBodyCreation { * @param geom the geometry */ public static void destroyShape(CollisionEngine collisionEngine, DGeom geom){ - collisionEngine.destroyGeom(geom); + collisionEngine.destroyDGeom(geom); } /** diff --git a/src/main/java/electrosphere/collision/CollisionEngine.java b/src/main/java/electrosphere/collision/CollisionEngine.java index f382af42..770bc2e4 100644 --- a/src/main/java/electrosphere/collision/CollisionEngine.java +++ b/src/main/java/electrosphere/collision/CollisionEngine.java @@ -26,7 +26,6 @@ import org.ode4j.ode.DGeom.DNearCallback; import org.ode4j.ode.DJoint; import org.ode4j.ode.DJointGroup; import org.ode4j.ode.DMass; -import org.ode4j.ode.DPlane; import org.ode4j.ode.DRay; import org.ode4j.ode.DSpace; import org.ode4j.ode.DSphere; @@ -114,12 +113,17 @@ public class CollisionEngine { /** * The world object */ - private DWorld world; + protected DWorld world; /** * The main space in the world */ - private DBhvSpace space; + protected DBhvSpace space; + + /** + * Space for storing static geoms + */ + protected DSpace staticGeomSpace; /** * Lock for thread-safeing all ODE calls @@ -129,7 +133,7 @@ public class CollisionEngine { /** * The contact group for caching collisions between collision and physics calls */ - private DJointGroup contactgroup; + protected DJointGroup contactgroup; /** *

Maximum number of contact points per body

@@ -139,27 +143,27 @@ public class CollisionEngine { * I used a value of 10 for a long time and found that cubes were sinking into TriMeshes. *

*/ - private static final int MAX_CONTACTS = 64; + protected static final int MAX_CONTACTS = 64; /** * The list of dbodies ode should be tracking */ - private List bodies = new ArrayList(); + protected List bodies = new ArrayList(); /** * This is used to relate DBody's back to their collidables so that when the library detects a collision, the callback can know which collidables are involved. */ - private Map bodyPointerMap = new HashMap(); + protected Map bodyPointerMap = new HashMap(); /** * This is used to relate DGeom's back to their collidables so that when the library detects a collision, the callback can know which collidables are involved. */ - private Map geomPointerMap = new HashMap(); + protected Map geomPointerMap = new HashMap(); /** * The list of all collidables the engine is currently tracking */ - private List collidableList = new ArrayList(); + protected List collidableList = new ArrayList(); /** * Dynamic spatial offset applied to all operations on the space. @@ -183,16 +187,21 @@ public class CollisionEngine { */ private DNearCallback nearCallback; - /** - * The base plane of the physics engine - */ - private DPlane basePlane = null; - /** * Number of geometries */ private int geomCount = 0; + /** + * The near collision count + */ + protected int nearCollisionCount = 0; + + /** + * The number of collisions that make it all the way to creating impulses + */ + protected int finalCollisionCount = 0; + /** * Tracks whether the engine has rebased or not */ @@ -202,12 +211,12 @@ public class CollisionEngine { /** * buffer for storing potential collisions */ - private DContactBuffer contacts = new DContactBuffer(MAX_CONTACTS); + protected DContactBuffer contacts = new DContactBuffer(MAX_CONTACTS); /** * The name of the collision engine */ - private final String name; + protected final String name; /** * Constructor @@ -222,9 +231,6 @@ public class CollisionEngine { // world.setContactSurfaceLayer(0.001); // world.setCFM(1e-10); - //base plane - basePlane = OdeHelper.createPlane(space, 0, 1, 0, 0); - contactgroup = OdeHelper.createJointGroup(); this.nearCallback = new DNearCallback() { @Override @@ -243,6 +249,18 @@ public class CollisionEngine { return rVal; } + /** + * Creates a collision engine with a specified callback + */ + public static CollisionEngine create(String name, PhysicsCallback callback){ + CollisionEngine rVal = new CollisionEngine(name); + rVal.nearCallback = callback; + callback.engine = rVal; + rVal.staticGeomSpace = OdeHelper.createBHVSpace(Collidable.TYPE_STATIC_BIT); + rVal.staticGeomSpace.setCategoryBits(Collidable.TYPE_STATIC_BIT); + return rVal; + } + /** * Resolves collisions in the engine @@ -333,6 +351,9 @@ public class CollisionEngine { public void simulatePhysics(){ Globals.profiler.beginCpuSample("physics"); spaceLock.lock(); + //reset tracking + this.nearCollisionCount = 0; + this.finalCollisionCount = 0; // remove all contact joints contactgroup.empty(); //main simulation @@ -340,7 +361,6 @@ public class CollisionEngine { Globals.profiler.beginCpuSample("collide"); OdeHelper.spaceCollide(space, 0, nearCallback); Globals.profiler.endCpuSample(); - // space.collide2(space, collisionWorldData, nearCallback); //simulate physics Globals.profiler.beginCpuSample("step physics"); @@ -378,8 +398,16 @@ public class CollisionEngine { * @param o2 the second collision body */ private void nearCallback(Object data, DGeom o1, DGeom o2){ + if(this.name.equals("serverPhysics")){ + this.nearCollisionCount++; + } // if (o1->body && o2->body) return; + //ie if both are in static space + if(o1 == o2){ + return; + } + //if the collision is static-on-static, skip if(o1.getCategoryBits() == Collidable.TYPE_STATIC_BIT && o2.getCategoryBits() == Collidable.TYPE_STATIC_BIT){ return; @@ -400,11 +428,6 @@ public class CollisionEngine { return; } - //check if we're colliding against the base plane - if(o1 == this.basePlane || o2 == this.basePlane){ - return; - } - //get the collidables for each geom Collidable c1 = null; if(b1 != null){ @@ -444,59 +467,118 @@ public class CollisionEngine { Globals.profiler.beginAggregateCpuSample("CollisionEngine.nearCallback - Full collision phase"); try { + Globals.profiler.beginAggregateCpuSample("CollisionEngine.nearCallback - setup"); //null out the contact buffer contacts.nullify(); SurfaceParams surfaceParams1 = c1.getSurfaceParams(); - SurfaceParams surfaceParams2 = c2.getSurfaceParams(); + SurfaceParams surfaceParams2 = null; + if(c2 != null){ + surfaceParams2 = c2.getSurfaceParams(); + } for (int i=0; i