From 027c93d4c7556ed9813de9e224d5d02263c9bd4a Mon Sep 17 00:00:00 2001 From: austin Date: Sat, 9 Mar 2024 17:40:40 -0500 Subject: [PATCH] Collision optimization --- docs/src/physics/collision.md | 4 +++- docs/src/progress/renderertodo.md | 5 ++-- pom.xml | 4 ++-- .../collision/CollisionBodyCreation.java | 24 +++++++++---------- .../collision/CollisionEngine.java | 19 +++++++++------ .../collision/PhysicsEntityUtils.java | 17 +++++++------ .../collision/collidable/Collidable.java | 18 ++++++++++++++ .../engine/assetmanager/AssetManager.java | 3 ++- .../types/collision/CollisionObjUtils.java | 12 +++++----- .../entity/types/tree/ProceduralTree.java | 6 +++-- 10 files changed, 71 insertions(+), 41 deletions(-) diff --git a/docs/src/physics/collision.md b/docs/src/physics/collision.md index 7dc81c71..5f05bdbf 100644 --- a/docs/src/physics/collision.md +++ b/docs/src/physics/collision.md @@ -1,7 +1,7 @@ @page collision Collision Engine - +[TOC] ## High Level Overview The goal of the collision engine system is to allow parallel collision detection of different classes of objects. @@ -109,6 +109,8 @@ Each client scene creates a collision engine for physics on connection. Each sce - Physics Entity - Dynamic Physics Entity - Collision Object - A collidable + - ODE Category - Ode has bits that control which 'categories' a given geometry falls in to. This is used to control behaviors applied to it. + - ODE Collision Bits - The mask of categories that a given geometry should collide with diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index 7193943a..d3d3e787 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -136,6 +136,8 @@ Ability to attach ambient audio emitters to entities Timekeeping class that defaults to gltf time and falls back to systemCurrentTimeMillis +Methods for sleeping physics bodies if nothing nearby them is dynamic (ie trees if there are no moving creatures near them) + - SAP2 space from ode4j specifically (ended up using BVH space instead) @@ -146,9 +148,6 @@ Timekeeping class that defaults to gltf time and falls back to systemCurrentTime # TODO -Methods for sleeping physics bodies if nothing nearby them is dynamic (ie trees if there are no moving creatures near them) - - SAP2 space from ode4j specifically - De-dupe render calls via doing mutations in render pipeline status and dont call setting variables to values they are already set to Clean up main method/class diff --git a/pom.xml b/pom.xml index 8bf0bb19..532ba9c8 100644 --- a/pom.xml +++ b/pom.xml @@ -128,7 +128,7 @@ - + @@ -136,7 +136,7 @@ org.ode4j core - 0.5.0 + 0.5.2 diff --git a/src/main/java/electrosphere/collision/CollisionBodyCreation.java b/src/main/java/electrosphere/collision/CollisionBodyCreation.java index 6c892cc9..c9611657 100644 --- a/src/main/java/electrosphere/collision/CollisionBodyCreation.java +++ b/src/main/java/electrosphere/collision/CollisionBodyCreation.java @@ -40,8 +40,8 @@ public class CollisionBodyCreation { * @param dimensions The dimensions of the plane * @return The DBody */ - public static DBody createPlaneBody(CollisionEngine collisionEngine, Vector3d dimensions){ - DBox geom = collisionEngine.createCubeGeom(new Vector3d(dimensions.x,PLANE_WIDTH,dimensions.z)); + public static DBody createPlaneBody(CollisionEngine collisionEngine, Vector3d dimensions, long categoryBits){ + DBox geom = collisionEngine.createCubeGeom(new Vector3d(dimensions.x,PLANE_WIDTH,dimensions.z),categoryBits); return collisionEngine.createDBody(geom); } @@ -51,8 +51,8 @@ public class CollisionBodyCreation { * @param dimensions The dimensions of the cube * @return The DBody */ - public static DBody createCubeBody(CollisionEngine collisionEngine, Vector3d dimensions){ - DBox geom = collisionEngine.createCubeGeom(new Vector3d(dimensions)); + public static DBody createCubeBody(CollisionEngine collisionEngine, Vector3d dimensions, long categoryBits){ + DBox geom = collisionEngine.createCubeGeom(new Vector3d(dimensions),categoryBits); return collisionEngine.createDBody(geom); } @@ -62,8 +62,8 @@ public class CollisionBodyCreation { * @param dimensions The dimensions of the cube * @return The DBody */ - public static DBody createCylinderBody(CollisionEngine collisionEngine, double radius, double length){ - DCylinder geom = collisionEngine.createCylinderGeom(radius,length); + public static DBody createCylinderBody(CollisionEngine collisionEngine, double radius, double length, long categoryBits){ + DCylinder geom = collisionEngine.createCylinderGeom(radius,length,categoryBits); DBody returnBody = collisionEngine.createDBody(geom); collisionEngine.setOffsetRotation(geom); //ode4j required geom to already be on body before rotating for some reason return returnBody; @@ -75,8 +75,8 @@ public class CollisionBodyCreation { * @param radius The radius of the sphere * @return The DBody */ - public static DBody createSphereBody(CollisionEngine collisionEngine, double radius){ - DSphere geom = collisionEngine.createSphereGeom(radius); + public static DBody createSphereBody(CollisionEngine collisionEngine, double radius, long categoryBits){ + DSphere geom = collisionEngine.createSphereGeom(radius,categoryBits); return collisionEngine.createDBody(geom); } @@ -86,7 +86,7 @@ public class CollisionBodyCreation { * @param data The terrain data * @return The DBody */ - public static DBody generateBodyFromTerrainData(CollisionEngine collisionEngine, TerrainChunkData data){ + public static DBody generateBodyFromTerrainData(CollisionEngine collisionEngine, TerrainChunkData data, long categoryBits){ DBody body = null; //create data @@ -110,7 +110,7 @@ public class CollisionBodyCreation { //create trimesh if(vertices.length > 0){ - DTriMesh triMesh = collisionEngine.createTrimeshGeom(vertices,indices); + DTriMesh triMesh = collisionEngine.createTrimeshGeom(vertices,indices,categoryBits); body = collisionEngine.createDBody(triMesh); } @@ -122,7 +122,7 @@ public class CollisionBodyCreation { * @param scene The AIScene to generate a rigid body off of * @return A rigid body based on the AIScene */ - public static DBody generateRigidBodyFromAIScene(CollisionEngine collisionEngine, AIScene scene){ + public static DBody generateRigidBodyFromAIScene(CollisionEngine collisionEngine, AIScene scene, long categoryBits){ DBody body = collisionEngine.createDBody(null); @@ -161,7 +161,7 @@ public class CollisionBodyCreation { indicesPos++; } } - DTriMesh meshGeom = collisionEngine.createTrimeshGeom(verts, indices); + DTriMesh meshGeom = collisionEngine.createTrimeshGeom(verts, indices,categoryBits); meshGeom.setBody(body); } diff --git a/src/main/java/electrosphere/collision/CollisionEngine.java b/src/main/java/electrosphere/collision/CollisionEngine.java index 4ff7b220..6d308049 100644 --- a/src/main/java/electrosphere/collision/CollisionEngine.java +++ b/src/main/java/electrosphere/collision/CollisionEngine.java @@ -72,7 +72,7 @@ public class CollisionEngine { private DJointGroup contactgroup; private static final int MAX_CONTACTS = 1; // maximum number of contact points per body - + //The list of dbodies ode should be tracking List bodies = new ArrayList(); @@ -90,7 +90,7 @@ public class CollisionEngine { public CollisionEngine(){ world = OdeHelper.createWorld(); - space = OdeHelper.createHashSpace(); + space = OdeHelper.createBHVSpace(Collidable.TYPE_STATIC_BIT); contactgroup = OdeHelper.createJointGroup(); } @@ -545,11 +545,12 @@ public class CollisionEngine { * @param indices The indices * @return The DTriMesh */ - protected DTriMesh createTrimeshGeom(float[] verts, int[] indices){ + protected DTriMesh createTrimeshGeom(float[] verts, int[] indices, long categoryBits){ spaceLock.acquireUninterruptibly(); DTriMeshData data = OdeHelper.createTriMeshData(); data.build(verts, indices); DTriMesh rVal = OdeHelper.createTriMesh(getSpace(), data); + rVal.setCategoryBits(categoryBits); spaceLock.release(); return rVal; } @@ -559,9 +560,10 @@ public class CollisionEngine { * @param dimensions The dimensions of the box * @return The DBox */ - protected DBox createCubeGeom(Vector3d dimensions){ + protected DBox createCubeGeom(Vector3d dimensions, long categoryBits){ spaceLock.acquireUninterruptibly(); DBox boxGeom = OdeHelper.createBox(space, dimensions.x, dimensions.y, dimensions.z); + boxGeom.setCategoryBits(categoryBits); spaceLock.release(); return boxGeom; } @@ -571,9 +573,10 @@ public class CollisionEngine { * @param dimensions The dimensions of the cylinder. X is the radius, y is the total height. * @return The cylinder geometry */ - protected DCylinder createCylinderGeom(double radius, double length){ + protected DCylinder createCylinderGeom(double radius, double length, long categoryBits){ spaceLock.acquireUninterruptibly(); DCylinder cylinderGeom = OdeHelper.createCylinder(space, radius, length); + cylinderGeom.setCategoryBits(categoryBits); spaceLock.release(); return cylinderGeom; } @@ -583,9 +586,10 @@ public class CollisionEngine { * @param radius The radius of the sphere * @return The sphere geometry */ - protected DSphere createSphereGeom(double radius){ + protected DSphere createSphereGeom(double radius, long categoryBits){ spaceLock.acquireUninterruptibly(); DSphere sphereGeom = OdeHelper.createSphere(space, radius); + sphereGeom.setCategoryBits(categoryBits); spaceLock.release(); return sphereGeom; } @@ -596,9 +600,10 @@ public class CollisionEngine { * @param length The length of the capsule * @return The capsule geometry */ - protected DCapsule createCapsuleGeom(double radius, double length){ + protected DCapsule createCapsuleGeom(double radius, double length, long categoryBits){ spaceLock.acquireUninterruptibly(); DCapsule capsuleGeom = OdeHelper.createCapsule(space, radius, length); + capsuleGeom.setCategoryBits(categoryBits); spaceLock.release(); return capsuleGeom; } diff --git a/src/main/java/electrosphere/collision/PhysicsEntityUtils.java b/src/main/java/electrosphere/collision/PhysicsEntityUtils.java index 33fff991..340a3bad 100644 --- a/src/main/java/electrosphere/collision/PhysicsEntityUtils.java +++ b/src/main/java/electrosphere/collision/PhysicsEntityUtils.java @@ -41,7 +41,8 @@ public class PhysicsEntityUtils { rigidBody = CollisionBodyCreation.createCylinderBody( Globals.clientSceneWrapper.getCollisionEngine(), physicsTemplate.getDimension1(), - physicsTemplate.getDimension2() + physicsTemplate.getDimension2(), + Collidable.TYPE_CREATURE_BIT ); collidable = new Collidable(rVal, Collidable.TYPE_CREATURE); ClientCollidableTree tree = new ClientCollidableTree(rVal,collidable,rigidBody); @@ -72,7 +73,8 @@ public class PhysicsEntityUtils { case "CUBE": { rigidBody = CollisionBodyCreation.createCubeBody( Globals.clientSceneWrapper.getCollisionEngine(), - new Vector3d(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3()) + new Vector3d(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3()), + Collidable.TYPE_CREATURE_BIT ); collidable = new Collidable(rVal, Collidable.TYPE_CREATURE); ClientCollidableTree tree = new ClientCollidableTree(rVal,collidable,rigidBody); @@ -119,7 +121,8 @@ public class PhysicsEntityUtils { rigidBody = CollisionBodyCreation.createCylinderBody( realm.getCollisionEngine(), physicsTemplate.getDimension1(), - physicsTemplate.getDimension2() + physicsTemplate.getDimension2(), + Collidable.TYPE_CREATURE_BIT ); collidable = new Collidable(rVal, Collidable.TYPE_CREATURE); ServerCollidableTree tree = new ServerCollidableTree(rVal,collidable,rigidBody); @@ -143,7 +146,7 @@ public class PhysicsEntityUtils { ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.COLLIDABLE); } break; case "CUBE": { - rigidBody = CollisionBodyCreation.createCubeBody(realm.getCollisionEngine(),new Vector3d(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3())); + rigidBody = CollisionBodyCreation.createCubeBody(realm.getCollisionEngine(),new Vector3d(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3()),Collidable.TYPE_CREATURE_BIT); collidable = new Collidable(rVal, Collidable.TYPE_CREATURE); ServerCollidableTree tree = new ServerCollidableTree(rVal,collidable,rigidBody); rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY, rigidBody); @@ -234,7 +237,7 @@ public class PhysicsEntityUtils { } } - DTriMesh triMesh = collisionEngine.createTrimeshGeom(vertices,indices); + DTriMesh triMesh = collisionEngine.createTrimeshGeom(vertices,indices,Collidable.TYPE_STATIC_BIT); DBody body = collisionEngine.createDBody(triMesh); Globals.clientSceneWrapper.getCollisionEngine().registerCollisionObject(body, new Collidable(terrain,Collidable.TYPE_TERRAIN)); @@ -252,7 +255,7 @@ public class PhysicsEntityUtils { */ public static DBody clientAttachTerrainChunkRigidBody(Entity terrain, TerrainChunkData data){ Vector3d position = EntityUtils.getPosition(terrain); - DBody terrainBody = CollisionBodyCreation.generateBodyFromTerrainData(Globals.clientSceneWrapper.getCollisionEngine(), data); + DBody terrainBody = CollisionBodyCreation.generateBodyFromTerrainData(Globals.clientSceneWrapper.getCollisionEngine(), data,Collidable.TYPE_STATIC_BIT); Globals.clientSceneWrapper.getCollisionEngine().registerCollisionObject(terrainBody, new Collidable(terrain,Collidable.TYPE_TERRAIN)); @@ -271,7 +274,7 @@ public class PhysicsEntityUtils { public static DBody serverAttachTerrainChunkRigidBody(Entity terrain, TerrainChunkData data){ Vector3d position = EntityUtils.getPosition(terrain); Realm terrainRealm = Globals.realmManager.getEntityRealm(terrain); - DBody terrainBody = CollisionBodyCreation.generateBodyFromTerrainData(terrainRealm.getCollisionEngine(),data); + DBody terrainBody = CollisionBodyCreation.generateBodyFromTerrainData(terrainRealm.getCollisionEngine(),data,Collidable.TYPE_STATIC_BIT); terrainRealm.getCollisionEngine().registerCollisionObject(terrainBody, new Collidable(terrain,Collidable.TYPE_TERRAIN)); terrain.putData(EntityDataStrings.PHYSICS_COLLISION_BODY, terrainBody); diff --git a/src/main/java/electrosphere/collision/collidable/Collidable.java b/src/main/java/electrosphere/collision/collidable/Collidable.java index bcaa162d..ca61cd30 100644 --- a/src/main/java/electrosphere/collision/collidable/Collidable.java +++ b/src/main/java/electrosphere/collision/collidable/Collidable.java @@ -26,13 +26,31 @@ public class Collidable { //The impulses to be applied to this collidable List impulses = new CopyOnWriteArrayList(); + //these should have corresponding category bits along with them + public static final String TYPE_STATIC = "static"; + public static final long TYPE_STATIC_BIT = 0x1; + public static final String TYPE_TERRAIN = "terrain"; + public static final long TYPE_TERRAIN_BIT = 0x2; + public static final String TYPE_CREATURE = "creature"; + public static final long TYPE_CREATURE_BIT = 0x4; + public static final String TYPE_STRUCTURE = "structure"; + public static final long TYPE_STRUCTURE_BIT = 0x8; + public static final String TYPE_ITEM = "item"; + public static final long TYPE_ITEM_BIT = 0x10; + public static final String TYPE_FORCE = "force"; + public static final long TYPE_FORCE_BIT = 0x20; + public static final String TYPE_OBJECT = "object"; + public static final long TYPE_OBJECT_BIT = 0x40; + public static final String TYPE_FOLIAGE_STATIC = "foliageStatic"; + public static final long TYPE_FOLIAGE_BIT = 0x80; + public Collidable(Entity parent, String type){ diff --git a/src/main/java/electrosphere/engine/assetmanager/AssetManager.java b/src/main/java/electrosphere/engine/assetmanager/AssetManager.java index 2bb56fd7..9924a28e 100644 --- a/src/main/java/electrosphere/engine/assetmanager/AssetManager.java +++ b/src/main/java/electrosphere/engine/assetmanager/AssetManager.java @@ -4,6 +4,7 @@ import electrosphere.audio.AudioBuffer; import electrosphere.collision.CollisionBodyCreation; import electrosphere.collision.CollisionEngine; import electrosphere.collision.PhysicsUtils; +import electrosphere.collision.collidable.Collidable; import electrosphere.renderer.Mesh; import electrosphere.renderer.Model; import electrosphere.renderer.ShaderProgram; @@ -78,7 +79,7 @@ public class AssetManager { physicsMeshesToLoad.remove(physicsMeshQueueItem); physicsMeshesLoadedIntoMemory.put( getCollisionMeshMapKey(physicsMeshQueueItem.collisionEngine,currentPath), - CollisionBodyCreation.generateRigidBodyFromAIScene(physicsMeshQueueItem.collisionEngine,aiScene) + CollisionBodyCreation.generateRigidBodyFromAIScene(physicsMeshQueueItem.collisionEngine,aiScene,Collidable.TYPE_STATIC_BIT) ); } } diff --git a/src/main/java/electrosphere/entity/types/collision/CollisionObjUtils.java b/src/main/java/electrosphere/entity/types/collision/CollisionObjUtils.java index a122fcc4..d807f3a1 100644 --- a/src/main/java/electrosphere/entity/types/collision/CollisionObjUtils.java +++ b/src/main/java/electrosphere/entity/types/collision/CollisionObjUtils.java @@ -29,7 +29,7 @@ public class CollisionObjUtils { float mass = 1.0f; - DBody planeObject = CollisionBodyCreation.createPlaneBody(Globals.clientSceneWrapper.getCollisionEngine(),new Vector3d(scale)); + DBody planeObject = CollisionBodyCreation.createPlaneBody(Globals.clientSceneWrapper.getCollisionEngine(),new Vector3d(scale),Collidable.TYPE_STATIC_BIT); PhysicsUtils.setRigidBodyTransform(Globals.clientSceneWrapper.getCollisionEngine(), position, rotation, planeObject); Collidable collidable = new Collidable(rVal, Collidable.TYPE_STRUCTURE); Globals.clientSceneWrapper.getCollisionEngine().registerCollisionObject(planeObject, collidable); @@ -55,7 +55,7 @@ public class CollisionObjUtils { float mass = 1.0f; - DBody planeObject = CollisionBodyCreation.createPlaneBody(realm.getCollisionEngine(),new Vector3d(scale)); + DBody planeObject = CollisionBodyCreation.createPlaneBody(realm.getCollisionEngine(),new Vector3d(scale),Collidable.TYPE_STATIC_BIT); PhysicsUtils.setRigidBodyTransform(realm.getCollisionEngine(), position, rotation, planeObject); Collidable collidable = new Collidable(rVal, Collidable.TYPE_STRUCTURE); realm.getCollisionEngine().registerCollisionObject(planeObject, collidable); @@ -82,7 +82,7 @@ public class CollisionObjUtils { float mass = 1.0f; - DBody cubeObject = CollisionBodyCreation.createCubeBody(Globals.clientSceneWrapper.getCollisionEngine(),new Vector3d(scale)); + DBody cubeObject = CollisionBodyCreation.createCubeBody(Globals.clientSceneWrapper.getCollisionEngine(),new Vector3d(scale),Collidable.TYPE_STATIC_BIT); PhysicsUtils.setRigidBodyTransform(Globals.clientSceneWrapper.getCollisionEngine(), position, rotation, cubeObject); Collidable collidable = new Collidable(rVal, Collidable.TYPE_STRUCTURE); Globals.clientSceneWrapper.getCollisionEngine().registerCollisionObject(cubeObject, collidable); @@ -108,7 +108,7 @@ public class CollisionObjUtils { float mass = 1.0f; - DBody cubeObject = CollisionBodyCreation.createCubeBody(realm.getCollisionEngine(),new Vector3d(scale)); + DBody cubeObject = CollisionBodyCreation.createCubeBody(realm.getCollisionEngine(),new Vector3d(scale),Collidable.TYPE_STATIC_BIT); PhysicsUtils.setRigidBodyTransform(realm.getCollisionEngine(), position, rotation, cubeObject); Collidable collidable = new Collidable(rVal, Collidable.TYPE_STRUCTURE); realm.getCollisionEngine().registerCollisionObject(cubeObject, collidable); @@ -133,7 +133,7 @@ public class CollisionObjUtils { Entity rVal = EntityCreationUtils.createClientSpatialEntity(); float mass = 1.0f; - DBody cubeObject = CollisionBodyCreation.createCylinderBody(Globals.clientSceneWrapper.getCollisionEngine(),scale.x,scale.y); + DBody cubeObject = CollisionBodyCreation.createCylinderBody(Globals.clientSceneWrapper.getCollisionEngine(),scale.x,scale.y,Collidable.TYPE_STATIC_BIT); PhysicsUtils.setRigidBodyTransform(Globals.clientSceneWrapper.getCollisionEngine(), position, rotation, cubeObject); Collidable collidable = new Collidable(rVal, Collidable.TYPE_STRUCTURE); Globals.clientSceneWrapper.getCollisionEngine().registerCollisionObject(cubeObject, collidable); @@ -161,7 +161,7 @@ public class CollisionObjUtils { Entity rVal = EntityCreationUtils.createServerEntity(realm, new Vector3d(position)); float mass = 1.0f; - DBody cubeObject = CollisionBodyCreation.createCylinderBody(realm.getCollisionEngine(),scale.x,scale.y); + DBody cubeObject = CollisionBodyCreation.createCylinderBody(realm.getCollisionEngine(),scale.x,scale.y,Collidable.TYPE_STATIC_BIT); PhysicsUtils.setRigidBodyTransform(realm.getCollisionEngine(), position, rotation, cubeObject); Collidable collidable = new Collidable(rVal, Collidable.TYPE_STRUCTURE); realm.getCollisionEngine().registerCollisionObject(cubeObject, collidable); diff --git a/src/main/java/electrosphere/entity/types/tree/ProceduralTree.java b/src/main/java/electrosphere/entity/types/tree/ProceduralTree.java index 920b8210..1145bab2 100644 --- a/src/main/java/electrosphere/entity/types/tree/ProceduralTree.java +++ b/src/main/java/electrosphere/entity/types/tree/ProceduralTree.java @@ -121,7 +121,8 @@ public class ProceduralTree { DBody rigidBody = CollisionBodyCreation.createCylinderBody( Globals.clientSceneWrapper.getCollisionEngine(), treeModel.getPhysicsBody().getDimension1(), - treeModel.getPhysicsBody().getDimension2() + treeModel.getPhysicsBody().getDimension2(), + Collidable.TYPE_STATIC_BIT ); Collidable collidable = new Collidable(trunkChild, Collidable.TYPE_OBJECT); trunkChild.putData(EntityDataStrings.PHYSICS_COLLISION_BODY, rigidBody); @@ -379,7 +380,8 @@ public class ProceduralTree { DBody rigidBody = CollisionBodyCreation.createCylinderBody( realm.getCollisionEngine(), treeModel.getPhysicsBody().getDimension1(), - treeModel.getPhysicsBody().getDimension2() + treeModel.getPhysicsBody().getDimension2(), + Collidable.TYPE_STATIC_BIT ); Collidable collidable = new Collidable(trunkChild, Collidable.TYPE_FOLIAGE_STATIC); trunkChild.putData(EntityDataStrings.PHYSICS_COLLISION_BODY, rigidBody);