server-side geom colliders
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good

This commit is contained in:
austin 2025-05-21 18:52:41 -04:00
parent 639fdde8fa
commit cbd5c98e0a
6 changed files with 470 additions and 237 deletions

View File

@ -1928,6 +1928,7 @@ Fix town placement structure-road intersection test
(05/21/2025)
Kinematic collision templates now use geoms instead of setting kinematic (on client)
Geom-only collidables on server

View File

@ -25,6 +25,7 @@ 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;
@ -94,16 +95,31 @@ public class CollisionEngine {
*/
public static final double DEFAULT_INTERACT_DISTANCE = 5.0;
//world data that the collision engine leverages for position correction and the like
CollisionWorldData collisionWorldData;
/**
* world data that the collision engine leverages for position correction and the like
*/
private CollisionWorldData collisionWorldData;
//Ode-specific stuff
/**
* The world object
*/
private DWorld world;
/**
* The main space in the world
*/
private DSpace space;
/**
* Lock for thread-safeing all ODE calls
*/
private static ReentrantLock spaceLock = new ReentrantLock();
/**
* The contact group for caching collisions between collision and physics calls
*/
private DJointGroup contactgroup;
// maximum number of contact points per body
/**
* <p> Maximum number of contact points per body </p>
* <p><b> Note: </b></p>
@ -114,38 +130,57 @@ public class CollisionEngine {
*/
private static final int MAX_CONTACTS = 64;
//The list of dbodies ode should be tracking
List<DBody> bodies = new ArrayList<DBody>();
/**
* The list of dbodies ode should be tracking
*/
private List<DBody> bodies = new ArrayList<DBody>();
//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.
Map<DBody,Collidable> bodyPointerMap = new HashMap<DBody,Collidable>();
/**
* 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<DBody,Collidable> bodyPointerMap = new HashMap<DBody,Collidable>();
//The list of all collidables the engine is currently tracking
List<Collidable> collidableList = new ArrayList<Collidable>();
/**
* 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<DGeom,Collidable> geomPointerMap = new HashMap<DGeom,Collidable>();
/**
* The list of all collidables the engine is currently tracking
*/
private List<Collidable> collidableList = new ArrayList<Collidable>();
/**
* Dynamic spatial offset applied to all operations on the space.
* This is used for world origin rebasing.
* This makes physics behave more consistently by moving far out objects to center around 0,0,0.
*/
Vector3d floatingOrigin = new Vector3d(0,0,0);
private Vector3d floatingOrigin = new Vector3d(0,0,0);
//callbacks for collision check
RayCastCallback rayCastCallback = new RayCastCallback();
/**
* callbacks for collision check
*/
private RayCastCallback rayCastCallback = new RayCastCallback();
//the collision resolution callback
CollisionResolutionCallback collisionResolutionCallback;
//buffer for collisions
DContactBuffer contacts = null;
/**
* the collision resolution callback
*/
private CollisionResolutionCallback collisionResolutionCallback;
/**
* The body that contains all static shapes
*/
DBody staticBody;
private DBody staticBody;
// Callback for any near collisions in the broadphase of the collision check
/**
* Callback for any near collisions in the broadphase of the collision check
*/
private DNearCallback nearCallback;
/**
* The base plane of the physics engine
*/
private DPlane basePlane = null;
/**
* Constructor
@ -160,7 +195,7 @@ public class CollisionEngine {
// world.setCFM(1e-10);
//base plane
OdeHelper.createPlane(space, 0, 1, 0, 0);
basePlane = OdeHelper.createPlane(space, 0, 1, 0, 0);
//static body
staticBody = this.createDBody();
@ -271,6 +306,9 @@ public class CollisionEngine {
public void simulatePhysics(float time){
Globals.profiler.beginCpuSample("physics");
spaceLock.lock();
// remove all contact joints
contactgroup.empty();
//main simulation
for(int i = 0; i < PHYSICS_SIMULATION_RESOLUTION; i++){
Globals.profiler.beginCpuSample("collide");
OdeHelper.spaceCollide(space, 0, nearCallback);
@ -295,6 +333,7 @@ public class CollisionEngine {
public void collide(){
Globals.profiler.beginCpuSample("physics");
spaceLock.lock();
contactgroup.empty();
Globals.profiler.beginCpuSample("collide");
OdeHelper.spaceCollide(space, 0, nearCallback);
Globals.profiler.endCpuSample();
@ -336,19 +375,52 @@ public class CollisionEngine {
}
//if collision is between static and disabled, skip
if(o1.getCategoryBits() == Collidable.TYPE_STATIC_BIT && !b2.isEnabled()){
if(o1.getCategoryBits() == Collidable.TYPE_STATIC_BIT && b2 != null && !b2.isEnabled()){
return;
}
if(o2.getCategoryBits() == Collidable.TYPE_STATIC_BIT && !b1.isEnabled()){
if(o2.getCategoryBits() == Collidable.TYPE_STATIC_BIT && b1 != null && !b1.isEnabled()){
return;
}
Collidable c1 = bodyPointerMap.get(b1);
Collidable c2 = bodyPointerMap.get(b2);
if(c1 == null || c2 == null){
//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){
c1 = bodyPointerMap.get(b1);
} else if(o1.getBody() == null) {
c1 = geomPointerMap.get(o1);
}
Collidable c2 = null;
if(b2 != null){
c2 = bodyPointerMap.get(b2);
} else if(o2.getBody() == null) {
c2 = geomPointerMap.get(o2);
}
//make sure we have collidables for both
if(c1 == null || c2 == null){
String message = "Collidable is undefined!\n" +
o1 + " \n" +
o2 + " \n" +
b1 + " \n" +
b2 + " \n" +
c1 + " \n" +
c2 + " \n" +
"Obj 1 pointers:\n" +
this.bodyPointerMap.get(b1) + " \n" +
this.geomPointerMap.get(o1) + " \n" +
"Obj 2 pointers:\n" +
this.bodyPointerMap.get(b2) + " \n" +
this.geomPointerMap.get(o2) + " \n" +
""
;
throw new Error(message);
}
Globals.profiler.beginAggregateCpuSample("CollisionEngine.nearCallback - try collisions");
try {
//creates a buffer to store potential collisions
@ -415,14 +487,20 @@ public class CollisionEngine {
//
//add contact to contact group
DJoint c = OdeHelper.createContactJoint(world,contactgroup,contact);
c.attach(b1,b2);
if(b1 == null){
c.attach(b2,null);
} else if(b2 == null){
c.attach(b1,null);
} else {
c.attach(b1,b2);
}
// Use the default collision resolution
if(collisionResolutionCallback == null) {
CollisionEngine.resolveCollision(
contact.geom,
bodyPointerMap.get(o1.getBody()),
bodyPointerMap.get(o2.getBody()),
c1,
c2,
PhysicsUtils.odeVecToJomlVec(contact.geom.normal).mul(-1.0),
PhysicsUtils.odeVecToJomlVec(contact.fdir1).mul(-1.0),
PhysicsUtils.odeVecToJomlVec(contact.geom.pos),
@ -430,8 +508,8 @@ public class CollisionEngine {
);
CollisionEngine.resolveCollision(
contact.geom,
bodyPointerMap.get(o2.getBody()),
bodyPointerMap.get(o1.getBody()),
c1,
c2,
PhysicsUtils.odeVecToJomlVec(contact.geom.normal),
PhysicsUtils.odeVecToJomlVec(contact.fdir1),
PhysicsUtils.odeVecToJomlVec(contact.geom.pos),
@ -443,8 +521,8 @@ public class CollisionEngine {
contact.geom,
o1,
o2,
bodyPointerMap.get(o1.getBody()),
bodyPointerMap.get(o2.getBody()),
c1,
c2,
PhysicsUtils.odeVecToJomlVec(contact.geom.normal).mul(-1.0),
PhysicsUtils.odeVecToJomlVec(contact.fdir1).mul(-1.0),
PhysicsUtils.odeVecToJomlVec(contact.geom.pos),
@ -454,8 +532,8 @@ public class CollisionEngine {
contact.geom,
o2,
o1,
bodyPointerMap.get(o2.getBody()),
bodyPointerMap.get(o1.getBody()),
c2,
c1,
PhysicsUtils.odeVecToJomlVec(contact.geom.normal),
PhysicsUtils.odeVecToJomlVec(contact.fdir1),
PhysicsUtils.odeVecToJomlVec(contact.geom.pos),
@ -566,6 +644,14 @@ public class CollisionEngine {
newRotation = PhysicsUtils.getRigidBodyRotation(rigidBody);
} else {
newRotation = PhysicsUtils.getGeomRotation(geom);
if(geom instanceof DCylinder || geom instanceof DCapsule){
newRotation.rotateX(-Math.PI/2.0);
}
}
if(geom != null){
CollidableTemplate template = PhysicsEntityUtils.getPhysicsTemplate(physicsEntity);
suggestedPosition.sub(template.getOffsetX(),template.getOffsetY(),template.getOffsetZ());
newRotation.mul(new Quaterniond(template.getRotX(),template.getRotY(),template.getRotZ(),template.getRotW()).invert());
}
EntityUtils.getPosition(physicsEntity).set(suggestedPosition);
EntityUtils.getRotation(physicsEntity).set(newRotation);
@ -612,6 +698,11 @@ public class CollisionEngine {
Vector3d existingPosition = PhysicsUtils.odeVecToJomlVec(rigidBody.getPosition());
rigidBody.setPosition(PhysicsUtils.jomlVecToOdeVec(existingPosition.add(delta)));
}
DGeom geom = PhysicsEntityUtils.getDGeom(physicsEntity);
if(geom != null){
Vector3d existingPosition = PhysicsUtils.odeVecToJomlVec(geom.getPosition());
geom.setPosition(PhysicsUtils.jomlVecToOdeVec(existingPosition.add(delta)));
}
}
}
spaceLock.unlock();
@ -624,6 +715,9 @@ public class CollisionEngine {
* @param collidable The corresponding collidable
*/
public void registerCollisionObject(DBody body, Collidable collidable){
if(collidable == null){
throw new Error("Collidable is null!");
}
spaceLock.lock();
this.registerPhysicsObject(body);
bodyPointerMap.put(body,collidable);
@ -631,6 +725,21 @@ public class CollisionEngine {
spaceLock.unlock();
}
/**
* Registers a collision object with the server
* @param geom The geom
* @param collidable The corresponding collidable
*/
public void registerCollisionObject(DGeom geom, Collidable collidable){
if(collidable == null){
throw new Error("Collidable is null!");
}
spaceLock.lock();
geomPointerMap.put(geom,collidable);
collidableList.add(collidable);
spaceLock.unlock();
}
/**
* Deregisters a collidable from the physics engine
* @param collidable The collidable
@ -765,7 +874,6 @@ public class CollisionEngine {
while(geomIterator.hasNext()){
DGeom geom = geomIterator.next();
space.remove(geom);
geom.DESTRUCTOR();
geom.destroy();
}
//destroy all joints
@ -1102,8 +1210,12 @@ public class CollisionEngine {
*/
protected void setGeomTransform(DGeom geom, Vector3d position, Quaterniond rotation){
spaceLock.lock();
geom.setPosition(position.x, position.y, position.z);
geom.setQuaternion(PhysicsUtils.jomlQuatToOdeQuat(rotation));
geom.setPosition(position.x - this.floatingOrigin.x, position.y - this.floatingOrigin.y, position.z - this.floatingOrigin.z);
if(geom instanceof DCylinder || geom instanceof DCapsule){
geom.setQuaternion(PhysicsUtils.jomlQuatToOdeQuat(new Quaterniond(rotation).rotateX(Math.PI/2.0)));
} else {
geom.setQuaternion(PhysicsUtils.jomlQuatToOdeQuat(rotation));
}
spaceLock.unlock();
}

View File

@ -58,8 +58,6 @@ public class PhysicsEntityUtils {
* @param physicsTemplate The collidable template
*/
public static void clientAttachCollidableTemplate(Entity rVal, CollidableTemplate physicsTemplate){
DBody rigidBody = null;
DGeom geom = null;
Collidable collidable;
double mass = 1.0f;
CollisionEngine engine = Globals.clientState.clientSceneWrapper.getCollisionEngine();
@ -71,6 +69,7 @@ public class PhysicsEntityUtils {
categoryBit = Collidable.TYPE_STATIC_BIT;
}
if(physicsTemplate.getKinematic()){
DGeom geom = null;
switch(physicsTemplate.getType()){
case CollidableTemplate.COLLIDABLE_TYPE_CYLINDER: {
@ -97,8 +96,8 @@ public class PhysicsEntityUtils {
rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_TRANSFORM, offsetTransform);
rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate);
Globals.clientState.clientSceneWrapper.getCollisionEngine().registerCollisionObject(rigidBody, collidable);
Globals.clientState.clientScene.registerEntityToTag(rVal, EntityTags.COLLIDABLE);
engine.registerCollisionObject(geom, collidable);
} break;
case CollidableTemplate.COLLIDABLE_TYPE_CUBE: {
//
@ -125,8 +124,8 @@ public class PhysicsEntityUtils {
rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate);
rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable);
Globals.clientState.clientSceneWrapper.getCollisionEngine().registerCollisionObject(rigidBody, collidable);
Globals.clientState.clientScene.registerEntityToTag(rVal, EntityTags.COLLIDABLE);
engine.registerCollisionObject(geom, collidable);
} break;
case CollidableTemplate.COLLIDABLE_TYPE_CAPSULE: {
//
@ -156,11 +155,12 @@ public class PhysicsEntityUtils {
rVal.putData(EntityDataStrings.PHYSICS_MASS, mass);
Globals.clientState.clientSceneWrapper.getCollisionEngine().registerCollisionObject(rigidBody, collidable);
Globals.clientState.clientScene.registerEntityToTag(rVal, EntityTags.COLLIDABLE);
engine.registerCollisionObject(geom, collidable);
} break;
}
} else {
DBody rigidBody = null;
switch(physicsTemplate.getType()){
case CollidableTemplate.COLLIDABLE_TYPE_CYLINDER: {
@ -359,10 +359,10 @@ public class PhysicsEntityUtils {
Globals.clientState.clientScene.registerEntityToTag(rVal, EntityTags.COLLIDABLE);
} break;
}
}
//if we successfully attached the body, add a sync tree
if(rigidBody != null){
ClientPhysicsSyncTree.attachTree(rVal);
//if we successfully attached the body, add a sync tree
if(rigidBody != null){
ClientPhysicsSyncTree.attachTree(rVal);
}
}
}
@ -374,7 +374,6 @@ public class PhysicsEntityUtils {
* @param physicsTemplate The collidable template
*/
public static void serverAttachCollidableTemplate(Realm realm, Entity rVal, CollidableTemplate physicsTemplate){
DBody rigidBody = null;
Collidable collidable;
double mass = 1.0f;
if(physicsTemplate.getMass() != null){
@ -384,208 +383,308 @@ public class PhysicsEntityUtils {
if(physicsTemplate.getKinematic()){
categoryBit = Collidable.TYPE_STATIC_BIT;
}
switch(physicsTemplate.getType()){
case CollidableTemplate.COLLIDABLE_TYPE_CYLINDER: {
if(physicsTemplate.getKinematic()){
DGeom geom = null;
switch(physicsTemplate.getType()){
case CollidableTemplate.COLLIDABLE_TYPE_CYLINDER: {
//
//create dbody
rigidBody = CollisionBodyCreation.createCylinderBody(
realm.getCollisionEngine(),
physicsTemplate.getDimension1(),
physicsTemplate.getDimension2(),
categoryBit
);
if(physicsTemplate.getMass() != null){
CollisionBodyCreation.setCylinderMass(
//
//create dbody
geom = CollisionBodyCreation.createCylinderShape(
realm.getCollisionEngine(),
rigidBody,
mass,
physicsTemplate.getDimension1(),
physicsTemplate.getDimension2(),
new Vector3d(physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ()),
new Quaterniond(physicsTemplate.getRotX(), physicsTemplate.getRotY(), physicsTemplate.getRotZ(), physicsTemplate.getRotW())
categoryBit
);
}
CollisionBodyCreation.setAutoDisable(realm.getCollisionEngine(), rigidBody, true, LINEAR_THRESHOLD, ANGULAR_THRESHOLD, STEP_THRESHOLD);
//
//set offset from entity center
CollisionBodyCreation.setOffsetPosition(
realm.getCollisionEngine(),
rigidBody,
new Vector3d(physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ())
);
//
//create collidable and attach tracking
collidable = new Collidable(rVal, Collidable.TYPE_CREATURE, true);
PhysicsEntityUtils.setDGeom(rVal, geom);
//
//create collidable and attach tracking
collidable = new Collidable(rVal, Collidable.TYPE_CREATURE, true);
if(physicsTemplate.getLinearFriction() != null){
collidable.getSurfaceParams().setLinearFriction(physicsTemplate.getLinearFriction());
}
if(physicsTemplate.getRollingFriction() != null){
collidable.getSurfaceParams().setRollingFriction(physicsTemplate.getRollingFriction());
}
ServerCollidableTree tree = new ServerCollidableTree(rVal,collidable,rigidBody);
PhysicsEntityUtils.setDBody(rVal,rigidBody);
//
//store data
Matrix4d offsetTransform = new Matrix4d().translationRotateScale(
physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ(), //translate
physicsTemplate.getRotX(), physicsTemplate.getRotY(), physicsTemplate.getRotZ(), physicsTemplate.getRotW(), //rotate
1, 1, 1 //scale
);
rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_TRANSFORM, offsetTransform);
rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate);
rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable);
//
//store data
Matrix4d offsetTransform = new Matrix4d().translationRotateScale(
physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ(), //translate
physicsTemplate.getRotX(), physicsTemplate.getRotY(), physicsTemplate.getRotZ(), physicsTemplate.getRotW(), //rotate
1, 1, 1 //scale
);
if(physicsTemplate.isAngularlyStatic()){
realm.getCollisionEngine().setAngularlyStatic(rigidBody, true);
}
if(physicsTemplate.getKinematic()){
Globals.clientState.clientSceneWrapper.getCollisionEngine().setKinematic(rigidBody);
rigidBody.disable();
}
rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_TRANSFORM, offsetTransform);
rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate);
rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable);
rVal.putData(EntityDataStrings.SERVER_COLLIDABLE_TREE, tree);
rVal.putData(EntityDataStrings.PHYSICS_MASS, mass);
rVal.putData(EntityDataStrings.PHYSICS_MASS, mass);
realm.getCollisionEngine().registerCollisionObject(rigidBody, collidable);
ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.COLLIDABLE);
} break;
case CollidableTemplate.COLLIDABLE_TYPE_CUBE: {
//
//create dbody
rigidBody = CollisionBodyCreation.createCubeBody(
realm.getCollisionEngine(),
new Vector3d(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3()),
categoryBit
);
if(physicsTemplate.getMass() != null){
CollisionBodyCreation.setBoxMass(
ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.COLLIDABLE);
realm.getCollisionEngine().registerCollisionObject(geom, collidable);
} break;
case CollidableTemplate.COLLIDABLE_TYPE_CUBE: {
//
//create dbody
geom = CollisionBodyCreation.createCubeShape(
realm.getCollisionEngine(),
rigidBody,
mass,
new Vector3d(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3()),
new Vector3d(physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ()),
new Quaterniond(physicsTemplate.getRotX(), physicsTemplate.getRotY(), physicsTemplate.getRotZ(), physicsTemplate.getRotW())
categoryBit
);
}
CollisionBodyCreation.setAutoDisable(realm.getCollisionEngine(), rigidBody, true, LINEAR_THRESHOLD, ANGULAR_THRESHOLD, STEP_THRESHOLD);
//
//set offset from entity center
CollisionBodyCreation.setOffsetPosition(
realm.getCollisionEngine(),
rigidBody,
new Vector3d(physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ())
);
//
//create collidable and attach tracking
collidable = new Collidable(rVal, Collidable.TYPE_CREATURE, true);
PhysicsEntityUtils.setDGeom(rVal, geom);
//
//create collidable and attach tracking
collidable = new Collidable(rVal, Collidable.TYPE_CREATURE, true);
if(physicsTemplate.getLinearFriction() != null){
collidable.getSurfaceParams().setLinearFriction(physicsTemplate.getLinearFriction());
}
if(physicsTemplate.getRollingFriction() != null){
collidable.getSurfaceParams().setRollingFriction(physicsTemplate.getRollingFriction());
}
ServerCollidableTree tree = new ServerCollidableTree(rVal,collidable,rigidBody);
PhysicsEntityUtils.setDBody(rVal,rigidBody);
//
//store data
Matrix4d offsetTransform = new Matrix4d().translationRotateScale(
physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ(), //translate
physicsTemplate.getRotX(), physicsTemplate.getRotY(), physicsTemplate.getRotZ(), physicsTemplate.getRotW(), //rotate
1, 1, 1 //scale
);
rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_TRANSFORM, offsetTransform);
rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate);
rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable);
//
//store data
Matrix4d offsetTransform = new Matrix4d().translationRotateScale(
physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ(), //translate
physicsTemplate.getRotX(), physicsTemplate.getRotY(), physicsTemplate.getRotZ(), physicsTemplate.getRotW(), //rotate
1, 1, 1 //scale
);
if(physicsTemplate.isAngularlyStatic()){
realm.getCollisionEngine().setAngularlyStatic(rigidBody, true);
}
if(physicsTemplate.getKinematic()){
Globals.clientState.clientSceneWrapper.getCollisionEngine().setKinematic(rigidBody);
rigidBody.disable();
}
rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_TRANSFORM, offsetTransform);
rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate);
rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable);
rVal.putData(EntityDataStrings.SERVER_COLLIDABLE_TREE, tree);
rVal.putData(EntityDataStrings.PHYSICS_MASS, mass);
rVal.putData(EntityDataStrings.PHYSICS_MASS, mass);
realm.getCollisionEngine().registerCollisionObject(rigidBody, collidable);
ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.COLLIDABLE);
} break;
case CollidableTemplate.COLLIDABLE_TYPE_CAPSULE: {
//
//create dbody
rigidBody = CollisionBodyCreation.createCapsuleBody(
realm.getCollisionEngine(),
physicsTemplate.getDimension1(),
physicsTemplate.getDimension2(),
categoryBit
);
if(physicsTemplate.getMass() != null){
CollisionBodyCreation.setCapsuleMass(
ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.COLLIDABLE);
realm.getCollisionEngine().registerCollisionObject(geom, collidable);
} break;
case CollidableTemplate.COLLIDABLE_TYPE_CAPSULE: {
//
//create dbody
geom = CollisionBodyCreation.createCapsuleShape(
realm.getCollisionEngine(),
rigidBody,
mass,
physicsTemplate.getDimension1(),
physicsTemplate.getDimension2(),
new Vector3d(physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ()),
new Quaterniond(physicsTemplate.getRotX(), physicsTemplate.getRotY(), physicsTemplate.getRotZ(), physicsTemplate.getRotW())
categoryBit
);
}
CollisionBodyCreation.setAutoDisable(realm.getCollisionEngine(), rigidBody, true, LINEAR_THRESHOLD, ANGULAR_THRESHOLD, STEP_THRESHOLD);
//
//set offset from entity center
CollisionBodyCreation.setOffsetPosition(
realm.getCollisionEngine(),
rigidBody,
new Vector3d(physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ())
);
//
//create collidable and attach tracking
collidable = new Collidable(rVal, Collidable.TYPE_CREATURE, true);
PhysicsEntityUtils.setDGeom(rVal, geom);
//
//create collidable and attach tracking
collidable = new Collidable(rVal, Collidable.TYPE_CREATURE, true);
if(physicsTemplate.getLinearFriction() != null){
collidable.getSurfaceParams().setLinearFriction(physicsTemplate.getLinearFriction());
}
if(physicsTemplate.getRollingFriction() != null){
collidable.getSurfaceParams().setRollingFriction(physicsTemplate.getRollingFriction());
}
ServerCollidableTree tree = new ServerCollidableTree(rVal,collidable,rigidBody);
PhysicsEntityUtils.setDBody(rVal,rigidBody);
//
//store data
Matrix4d offsetTransform = new Matrix4d().translationRotateScale(
physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ(), //translate
physicsTemplate.getRotX(), physicsTemplate.getRotY(), physicsTemplate.getRotZ(), physicsTemplate.getRotW(), //rotate
1, 1, 1 //scale
);
rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_TRANSFORM, offsetTransform);
rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate);
rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable);
//
//store data
Matrix4d offsetTransform = new Matrix4d().translationRotateScale(
physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ(), //translate
physicsTemplate.getRotX(), physicsTemplate.getRotY(), physicsTemplate.getRotZ(), physicsTemplate.getRotW(), //rotate
1, 1, 1 //scale
);
if(physicsTemplate.isAngularlyStatic()){
realm.getCollisionEngine().setAngularlyStatic(rigidBody, true);
}
if(physicsTemplate.getKinematic()){
Globals.clientState.clientSceneWrapper.getCollisionEngine().setKinematic(rigidBody);
rigidBody.disable();
}
rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_TRANSFORM, offsetTransform);
rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate);
rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable);
rVal.putData(EntityDataStrings.SERVER_COLLIDABLE_TREE, tree);
rVal.putData(EntityDataStrings.PHYSICS_MASS, mass);
rVal.putData(EntityDataStrings.PHYSICS_MASS, mass);
ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.COLLIDABLE);
realm.getCollisionEngine().registerCollisionObject(geom, collidable);
} break;
}
} else {
DBody rigidBody = null;
switch(physicsTemplate.getType()){
case CollidableTemplate.COLLIDABLE_TYPE_CYLINDER: {
realm.getCollisionEngine().registerCollisionObject(rigidBody, collidable);
ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.COLLIDABLE);
} break;
}
//if we successfully attached the body, add a sync tree
if(rigidBody != null){
ServerPhysicsSyncTree.attachTree(rVal);
//
//create dbody
rigidBody = CollisionBodyCreation.createCylinderBody(
realm.getCollisionEngine(),
physicsTemplate.getDimension1(),
physicsTemplate.getDimension2(),
categoryBit
);
if(physicsTemplate.getMass() != null){
CollisionBodyCreation.setCylinderMass(
realm.getCollisionEngine(),
rigidBody,
mass,
physicsTemplate.getDimension1(),
physicsTemplate.getDimension2(),
new Vector3d(physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ()),
new Quaterniond(physicsTemplate.getRotX(), physicsTemplate.getRotY(), physicsTemplate.getRotZ(), physicsTemplate.getRotW())
);
}
CollisionBodyCreation.setAutoDisable(realm.getCollisionEngine(), rigidBody, true, LINEAR_THRESHOLD, ANGULAR_THRESHOLD, STEP_THRESHOLD);
//
//set offset from entity center
CollisionBodyCreation.setOffsetPosition(
realm.getCollisionEngine(),
rigidBody,
new Vector3d(physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ())
);
//
//create collidable and attach tracking
collidable = new Collidable(rVal, Collidable.TYPE_CREATURE, true);
if(physicsTemplate.getLinearFriction() != null){
collidable.getSurfaceParams().setLinearFriction(physicsTemplate.getLinearFriction());
}
if(physicsTemplate.getRollingFriction() != null){
collidable.getSurfaceParams().setRollingFriction(physicsTemplate.getRollingFriction());
}
ServerCollidableTree tree = new ServerCollidableTree(rVal,collidable,rigidBody);
PhysicsEntityUtils.setDBody(rVal,rigidBody);
//
//store data
Matrix4d offsetTransform = new Matrix4d().translationRotateScale(
physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ(), //translate
physicsTemplate.getRotX(), physicsTemplate.getRotY(), physicsTemplate.getRotZ(), physicsTemplate.getRotW(), //rotate
1, 1, 1 //scale
);
if(physicsTemplate.isAngularlyStatic()){
realm.getCollisionEngine().setAngularlyStatic(rigidBody, true);
}
if(physicsTemplate.getKinematic()){
Globals.clientState.clientSceneWrapper.getCollisionEngine().setKinematic(rigidBody);
rigidBody.disable();
}
rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_TRANSFORM, offsetTransform);
rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate);
rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable);
rVal.putData(EntityDataStrings.SERVER_COLLIDABLE_TREE, tree);
rVal.putData(EntityDataStrings.PHYSICS_MASS, mass);
realm.getCollisionEngine().registerCollisionObject(rigidBody, collidable);
ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.COLLIDABLE);
} break;
case CollidableTemplate.COLLIDABLE_TYPE_CUBE: {
//
//create dbody
rigidBody = CollisionBodyCreation.createCubeBody(
realm.getCollisionEngine(),
new Vector3d(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3()),
categoryBit
);
if(physicsTemplate.getMass() != null){
CollisionBodyCreation.setBoxMass(
realm.getCollisionEngine(),
rigidBody,
mass,
new Vector3d(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3()),
new Vector3d(physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ()),
new Quaterniond(physicsTemplate.getRotX(), physicsTemplate.getRotY(), physicsTemplate.getRotZ(), physicsTemplate.getRotW())
);
}
CollisionBodyCreation.setAutoDisable(realm.getCollisionEngine(), rigidBody, true, LINEAR_THRESHOLD, ANGULAR_THRESHOLD, STEP_THRESHOLD);
//
//set offset from entity center
CollisionBodyCreation.setOffsetPosition(
realm.getCollisionEngine(),
rigidBody,
new Vector3d(physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ())
);
//
//create collidable and attach tracking
collidable = new Collidable(rVal, Collidable.TYPE_CREATURE, true);
if(physicsTemplate.getLinearFriction() != null){
collidable.getSurfaceParams().setLinearFriction(physicsTemplate.getLinearFriction());
}
if(physicsTemplate.getRollingFriction() != null){
collidable.getSurfaceParams().setRollingFriction(physicsTemplate.getRollingFriction());
}
ServerCollidableTree tree = new ServerCollidableTree(rVal,collidable,rigidBody);
PhysicsEntityUtils.setDBody(rVal,rigidBody);
//
//store data
Matrix4d offsetTransform = new Matrix4d().translationRotateScale(
physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ(), //translate
physicsTemplate.getRotX(), physicsTemplate.getRotY(), physicsTemplate.getRotZ(), physicsTemplate.getRotW(), //rotate
1, 1, 1 //scale
);
if(physicsTemplate.isAngularlyStatic()){
realm.getCollisionEngine().setAngularlyStatic(rigidBody, true);
}
if(physicsTemplate.getKinematic()){
Globals.clientState.clientSceneWrapper.getCollisionEngine().setKinematic(rigidBody);
rigidBody.disable();
}
rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_TRANSFORM, offsetTransform);
rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate);
rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable);
rVal.putData(EntityDataStrings.SERVER_COLLIDABLE_TREE, tree);
rVal.putData(EntityDataStrings.PHYSICS_MASS, mass);
realm.getCollisionEngine().registerCollisionObject(rigidBody, collidable);
ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.COLLIDABLE);
} break;
case CollidableTemplate.COLLIDABLE_TYPE_CAPSULE: {
//
//create dbody
rigidBody = CollisionBodyCreation.createCapsuleBody(
realm.getCollisionEngine(),
physicsTemplate.getDimension1(),
physicsTemplate.getDimension2(),
categoryBit
);
if(physicsTemplate.getMass() != null){
CollisionBodyCreation.setCapsuleMass(
realm.getCollisionEngine(),
rigidBody,
mass,
physicsTemplate.getDimension1(),
physicsTemplate.getDimension2(),
new Vector3d(physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ()),
new Quaterniond(physicsTemplate.getRotX(), physicsTemplate.getRotY(), physicsTemplate.getRotZ(), physicsTemplate.getRotW())
);
}
CollisionBodyCreation.setAutoDisable(realm.getCollisionEngine(), rigidBody, true, LINEAR_THRESHOLD, ANGULAR_THRESHOLD, STEP_THRESHOLD);
//
//set offset from entity center
CollisionBodyCreation.setOffsetPosition(
realm.getCollisionEngine(),
rigidBody,
new Vector3d(physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ())
);
//
//create collidable and attach tracking
collidable = new Collidable(rVal, Collidable.TYPE_CREATURE, true);
if(physicsTemplate.getLinearFriction() != null){
collidable.getSurfaceParams().setLinearFriction(physicsTemplate.getLinearFriction());
}
if(physicsTemplate.getRollingFriction() != null){
collidable.getSurfaceParams().setRollingFriction(physicsTemplate.getRollingFriction());
}
ServerCollidableTree tree = new ServerCollidableTree(rVal,collidable,rigidBody);
PhysicsEntityUtils.setDBody(rVal,rigidBody);
//
//store data
Matrix4d offsetTransform = new Matrix4d().translationRotateScale(
physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ(), //translate
physicsTemplate.getRotX(), physicsTemplate.getRotY(), physicsTemplate.getRotZ(), physicsTemplate.getRotW(), //rotate
1, 1, 1 //scale
);
if(physicsTemplate.isAngularlyStatic()){
realm.getCollisionEngine().setAngularlyStatic(rigidBody, true);
}
if(physicsTemplate.getKinematic()){
Globals.clientState.clientSceneWrapper.getCollisionEngine().setKinematic(rigidBody);
rigidBody.disable();
}
rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_TRANSFORM, offsetTransform);
rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate);
rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable);
rVal.putData(EntityDataStrings.SERVER_COLLIDABLE_TREE, tree);
rVal.putData(EntityDataStrings.PHYSICS_MASS, mass);
realm.getCollisionEngine().registerCollisionObject(rigidBody, collidable);
ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.COLLIDABLE);
} break;
}
//if we successfully attached the body, add a sync tree
if(rigidBody != null){
ServerPhysicsSyncTree.attachTree(rVal);
}
}
}

View File

@ -9,6 +9,7 @@ import electrosphere.collision.CollisionEngine;
import electrosphere.collision.PhysicsEntityUtils;
import electrosphere.collision.PhysicsUtils;
import electrosphere.collision.collidable.Collidable;
import electrosphere.data.entity.collidable.CollidableTemplate;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings;
@ -75,10 +76,20 @@ public class CollisionObjUtils {
EntityUtils.getPosition(e).set(position);
Quaterniond rotation = EntityUtils.getRotation(e);
DBody body = PhysicsEntityUtils.getDBody(e);
DGeom geom = PhysicsEntityUtils.getDGeom(e);
CollisionEngine collisionEngine = Globals.serverState.realmManager.getEntityRealm(e).getCollisionEngine();
if(body != null){
PhysicsUtils.setRigidBodyTransform(collisionEngine, position, rotation, body);
}
if(geom != null){
CollidableTemplate template = PhysicsEntityUtils.getPhysicsTemplate(e);
PhysicsUtils.setGeomTransform(
collisionEngine,
new Vector3d(position).add(template.getOffsetX(),template.getOffsetY(),template.getOffsetZ()),
rotation,
geom
);
}
}
/**
@ -95,7 +106,13 @@ public class CollisionObjUtils {
}
DGeom geom = PhysicsEntityUtils.getDGeom(e);
if(geom != null){
PhysicsUtils.setGeomTransform(Globals.clientState.clientSceneWrapper.getCollisionEngine(), position, rotation, geom);
CollidableTemplate template = PhysicsEntityUtils.getPhysicsTemplate(e);
PhysicsUtils.setGeomTransform(
Globals.clientState.clientSceneWrapper.getCollisionEngine(),
new Vector3d(position).add(template.getOffsetX(),template.getOffsetY(),template.getOffsetZ()),
rotation,
geom
);
}
}

View File

@ -33,43 +33,45 @@ public class ServerHitboxResolutionCallback implements CollisionResolutionCallba
//basic error checking
if(impactorEntity == null){
throw new IllegalStateException("Impactor's entity is null");
throw new Error("Impactor's entity is null");
}
if(receiverEntity == null){
throw new IllegalStateException("Receiver's entity is null");
throw new Error("Receiver's entity is null");
}
if(!HitboxCollectionState.hasHitboxState(impactorEntity)){
throw new IllegalStateException("Impactor state is null");
throw new Error("Impactor state is null");
}
if(!HitboxCollectionState.hasHitboxState(receiverEntity)){
throw new IllegalStateException("Receiver state is null");
throw new Error("Receiver state is null");
}
if(impactorGeom == null){
throw new IllegalStateException("Impactor geom is null");
throw new Error("Impactor geom is null");
}
if(receiverGeom == null){
throw new IllegalStateException("Receiver geom is null");
throw new Error("Receiver geom is null");
}
if(!impactorState.getGeometries().contains(impactorGeom)){
boolean receiverStateContainsGeom = receiverState.getGeometries().contains(impactorGeom);
String message = "Impactor geom has wrong parent assigned!\n" +
"Problem geom: " + impactorGeom + "\n" +
"All geometries tracked: " + impactorState.getGeometries() + "n\""
"All geometries tracked: " + impactorState.getGeometries() + "\n" +
"Receiver contains impactor: " + receiverStateContainsGeom + "\n"
;
throw new IllegalStateException(message);
throw new Error(message);
}
if(impactorShapeStatus == null){
String message = "Impactor shape status is null\n" +
"Problem geom: " + impactorGeom + "\n" +
"All geometries tracked: " + impactorState.getGeometries() + "n\""
;
throw new IllegalStateException(message);
throw new Error(message);
}
if(receiverShapeStatus == null){
String message = "Receiver shape status is null\n" +
"Problem geom: " + receiverGeom + "\n" +
"All geometries tracked: " + receiverState.getGeometries() + "n\""
;
throw new IllegalStateException(message);
throw new Error(message);
}

View File

@ -64,7 +64,9 @@ public class MicroSimulation {
//sum collidable impulses
Set<Entity> collidables = dataCell.getScene().getEntitiesWithTag(EntityTags.COLLIDABLE);
for(Entity collidable : collidables){
ServerCollidableTree.getServerCollidableTree(collidable).simulate((float)Globals.engineState.timekeeper.getSimFrameTime());
if(ServerCollidableTree.hasServerCollidableTree(collidable)){
ServerCollidableTree.getServerCollidableTree(collidable).simulate((float)Globals.engineState.timekeeper.getSimFrameTime());
}
}
//update actor transform caches
poseableEntities = dataCell.getScene().getEntitiesWithTag(EntityTags.POSEABLE);