physics work
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit

This commit is contained in:
austin 2025-06-05 11:00:34 -04:00
parent e57658467b
commit 8bc8fb464b
9 changed files with 233 additions and 30 deletions

View File

@ -2119,6 +2119,7 @@ Fix projection matrix being sent to light manager
(06/05/2025)
voxel tests
Physics work

View File

@ -7,6 +7,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
import org.joml.Matrix4d;
import org.joml.Quaterniond;
@ -135,6 +136,12 @@ public class CollisionEngine {
*/
protected static final int MAX_CONTACTS = 64;
/**
* <p> Maximum number of contact points per geom-geom collision </p>
* <p><b> Note: </b></p>
*/
protected static final int MIN_CONTACTS = 4;
/**
* The list of dbodies ode should be tracking
*/
@ -265,13 +272,13 @@ public class CollisionEngine {
case Collidable.TYPE_CREATURE: {
switch(impactor.getType()){
case Collidable.TYPE_STATIC: {
receiver.addImpulse(new Impulse(normal, localPosition, worldPos, magnitude * 2, Collidable.TYPE_STATIC));
receiver.addImpulse(normal, localPosition, worldPos, magnitude * 2, Collidable.TYPE_STATIC);
} break;
case Collidable.TYPE_CREATURE: {
receiver.addImpulse(new Impulse(normal, localPosition, worldPos, magnitude, Collidable.TYPE_CREATURE));
receiver.addImpulse(normal, localPosition, worldPos, magnitude, Collidable.TYPE_CREATURE);
} break;
case Collidable.TYPE_OBJECT: {
receiver.addImpulse(new Impulse(normal, localPosition, worldPos, magnitude, Collidable.TYPE_OBJECT));
receiver.addImpulse(normal, localPosition, worldPos, magnitude, Collidable.TYPE_OBJECT);
} break;
}
} break;
@ -1608,12 +1615,15 @@ public class CollisionEngine {
* @return The status of the collision engine
*/
public String getStatus(){
CollisionEngine.lockOde();
String message = "" +
"Name: " + this.name + "\n" +
"Bodies: " + this.bodies.size() + "\n" +
"Body Ptrs: " + this.bodyPointerMap.size() + "\n" +
"Geom Ptrs: " + this.geomPointerMap.size() + "\n" +
"Collidables: " + this.collidableList.size() + "\n" +
" (Static) Collidables: " + this.collidableList.stream().filter((Collidable collidable) -> collidable.getType().matches(Collidable.TYPE_STATIC)).collect(Collectors.toList()).size() + "\n" +
" (Creature) Collidables: " + this.collidableList.stream().filter((Collidable collidable) -> collidable.getType().matches(Collidable.TYPE_CREATURE)).collect(Collectors.toList()).size() + "\n" +
"Space geom count: " + this.space.getNumGeoms() + "\n" +
"Tracked geom count: " + this.geomCount + "\n" +
"Floating origin: " + this.floatingOrigin.x + "," + this.floatingOrigin.y + "," + this.floatingOrigin.z + "\n" +
@ -1621,6 +1631,7 @@ public class CollisionEngine {
"Final Collision Count: " + this.finalCollisionCount + "\n" +
""
;
CollisionEngine.unlockOde();
return message;
}

View File

@ -25,6 +25,11 @@ public class PhysicsCallback implements DNearCallback {
*/
protected CollisionEngine engine;
/**
* Enables geom-geom collisions between non-statics
*/
private boolean enableGeomGeom = false;
/**
* Constructor
*/
@ -43,7 +48,13 @@ public class PhysicsCallback implements DNearCallback {
}
//if neither are bodies
if(o1.getBody() == null && o2.getBody() == null){
if(
o1.getBody() == null && o2.getBody() == null &&
(
!this.enableGeomGeom ||
(o1.getCategoryBits() == Collidable.TYPE_STATIC_BIT && o2.getCategoryBits() == Collidable.TYPE_STATIC_BIT)
)
){
return;
}
@ -91,6 +102,16 @@ public class PhysicsCallback implements DNearCallback {
throw new Error(message);
}
//Controls whether we should grab MAX_CONTACTS or MIN_CONTACTS
boolean isGeomGeomCollision = o1.getBody() == null && o2.getBody() == null;
//Number of contacts to poll for
int contactCount = CollisionEngine.MAX_CONTACTS;
if(isGeomGeomCollision && this.enableGeomGeom){
contactCount = CollisionEngine.MIN_CONTACTS;
}
Globals.profiler.beginAggregateCpuSample("CollisionEngine.nearCallback - Full collision phase");
try {
Globals.profiler.beginAggregateCpuSample("CollisionEngine.nearCallback - setup");
@ -101,7 +122,7 @@ public class PhysicsCallback implements DNearCallback {
if(c2 != null){
surfaceParams2 = c2.getSurfaceParams();
}
for (int i=0; i< CollisionEngine.MAX_CONTACTS; i++) {
for (int i=0; i< contactCount; i++) {
DContact contact = engine.contacts.get(i);
contact.surface.mode = surfaceParams1.getMode();
contact.surface.mu = surfaceParams1.getMu();
@ -144,7 +165,7 @@ public class PhysicsCallback implements DNearCallback {
Globals.profiler.endCpuSample();
//calculate collisions
Globals.profiler.beginAggregateCpuSample("CollisionEngine.nearCallback - OdeHelper.collide");
int numc = OdeHelper.collide(o1,o2,CollisionEngine.MAX_CONTACTS,engine.contacts.getGeomBuffer());
int numc = OdeHelper.collide(o1,o2,contactCount,engine.contacts.getGeomBuffer());
Globals.profiler.endCpuSample();
//create DContacts based on each collision that occurs
Globals.profiler.beginAggregateCpuSample("CollisionEngine.nearCallback - contact iterations");
@ -160,18 +181,20 @@ public class PhysicsCallback implements DNearCallback {
}
//
//add contact to contact group
DJoint c = OdeHelper.createContactJoint(engine.world,engine.contactgroup,contact);
if(b1 == null){
if(b2 == null){
//add contact to contact group - don't create contacts for non-geom collisions
if(!isGeomGeomCollision){
DJoint c = OdeHelper.createContactJoint(engine.world,engine.contactgroup,contact);
if(b1 == null){
if(b2 == null){
} else {
c.attach(null,b2);
}
} else {
c.attach(null,b2);
}
} else {
if(b2 == null){
c.attach(b1,null);
} else {
c.attach(b1,b2);
if(b2 == null){
c.attach(b1,null);
} else {
c.attach(b1,b2);
}
}
}

View File

@ -4,14 +4,20 @@ import electrosphere.entity.Entity;
import electrosphere.entity.state.collidable.Impulse;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import org.joml.Vector3d;
/**
* Stores the type of the collidable object as well as the impulses currently applied to it
*/
public class Collidable {
/**
* Max impulses that can be applied to a collidable
*/
public static final int MAX_IMPULSES = 5;
/**
* The entity this collidable is attached to
@ -31,7 +37,12 @@ public class Collidable {
/**
* The impulses to be applied to this collidable
*/
private List<Impulse> impulses = new LinkedList<Impulse>();
private Impulse[] impulses = new Impulse[MAX_IMPULSES];
/**
* The number of impulses stored in the collidable
*/
private int impulseCount = 0;
/**
* The params for the surface of this collidable when a collision occurs
@ -78,6 +89,9 @@ public class Collidable {
this.type = type;
this.parentTracksCollidable = parentTracksCollidable;
this.surfaceParams = new SurfaceParams();
for(int i = 0; i < MAX_IMPULSES; i++){
this.impulses[i] = new Impulse();
}
}
/**
@ -96,12 +110,42 @@ public class Collidable {
return this.surfaceParams;
}
public List<Impulse> getImpulses() {
/**
* Gets the array of impulses
* @return The array of impulses
*/
public Impulse[] getImpulses() {
return impulses;
}
/**
* Adds an impulse the collidable
* @param impulse The impulse
*/
public void addImpulse(Impulse impulse) {
impulses.add(impulse);
if(this.impulseCount < MAX_IMPULSES){
impulses[this.impulseCount].setCollisionPoint(impulse.getCollisionPoint());
impulses[this.impulseCount].setDirection(impulse.getDirection());
impulses[this.impulseCount].setWorldPoint(impulse.getWorldPoint());
impulses[this.impulseCount].setType(impulse.getType());
impulses[this.impulseCount].setForce(impulse.getForce());
this.impulseCount++;
}
}
/**
* Adds an impulse the collidable
* @param impulse The impulse
*/
public void addImpulse(Vector3d direction, Vector3d collisionPoint, Vector3d worldPoint, double force, String type){
if(this.impulseCount < MAX_IMPULSES){
impulses[this.impulseCount].setCollisionPoint(collisionPoint);
impulses[this.impulseCount].setDirection(direction);
impulses[this.impulseCount].setWorldPoint(worldPoint);
impulses[this.impulseCount].setType(type);
impulses[this.impulseCount].setForce(force);
this.impulseCount++;
}
}
public Entity getParent() {
@ -124,8 +168,14 @@ public class Collidable {
this.type = type;
}
/**
* Clears the impulses
*/
public void clear(){
impulses.clear();
for(int i = 0; i < MAX_IMPULSES; i++){
impulses[i].clear();
}
this.impulseCount = 0;
}
/**
@ -144,6 +194,14 @@ public class Collidable {
this.ready = ready;
}
/**
* Gets the number of impulses stored in the collidable
* @return The number of impulses
*/
public int getImpulseCount(){
return this.impulseCount;
}

View File

@ -21,25 +21,109 @@ public class Impulse {
this.worldPoint = worldPoint;
}
/**
* Constructor for collidable work
*/
public Impulse(){
this.direction = new Vector3d();
this.collisionPoint = new Vector3d();
this.worldPoint = new Vector3d();
this.force = 0;
this.type = null;
}
/**
* Gets the direction of the impulse
* @return The direction of the impulse
*/
public Vector3d getDirection() {
return direction;
}
/**
* Gets the force of the impulse
* @return The force of the impulse
*/
public double getForce() {
return force;
}
/**
* Gets the type of the impulse
* @return The type of the impulse
*/
public String getType() {
return type;
}
/**
* Gets the collision point of the impulse
* @return The collision point of the impulse
*/
public Vector3d getCollisionPoint() {
return collisionPoint;
}
/**
* Gets the world point of the impulse
* @return The world point of the impulse
*/
public Vector3d getWorldPoint(){
return worldPoint;
}
/**
* Sets the direction of the impulse
* @param direction The direction of the impulse
*/
public void setDirection(Vector3d direction) {
this.direction = direction;
}
/**
* Sets the collision point of the impulse
* @param collisionPoint The collision point of the impulse
*/
public void setCollisionPoint(Vector3d collisionPoint) {
this.collisionPoint = collisionPoint;
}
/**
* Sets the world point of the impulse
* @param worldPoint The world point of the impulse
*/
public void setWorldPoint(Vector3d worldPoint) {
this.worldPoint = worldPoint;
}
/**
* Sets the force of the impulse
* @param force The force of the impulse
*/
public void setForce(double force) {
this.force = force;
}
/**
* Sets the type of the impulse
* @param type The type of the impulse
*/
public void setType(String type) {
this.type = type;
}
/**
* Clears the data in the impulse
*/
public void clear(){
this.direction.set(0,0,0);
this.collisionPoint.set(0,0,0);
this.worldPoint.set(0,0,0);
this.force = 0;
this.type = null;
}
}

View File

@ -3,10 +3,13 @@ package electrosphere.entity.state.collidable;
import electrosphere.collision.collidable.Collidable;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.ServerEntityUtils;
import electrosphere.entity.btree.BehaviorTree;
import electrosphere.entity.state.gravity.ServerGravityTree;
import electrosphere.entity.state.movement.fall.ServerFallTree;
import org.joml.Vector3d;
import org.ode4j.ode.DBody;
import org.ode4j.ode.DGeom;
@ -25,6 +28,11 @@ public class ServerCollidableTree implements BehaviorTree {
*/
protected DBody body;
/**
* The geom
*/
protected DGeom geom;
/**
* The collidable
*/
@ -52,6 +60,7 @@ public class ServerCollidableTree implements BehaviorTree {
public ServerCollidableTree(Entity e, Collidable collidable, DGeom geom){
parent = e;
this.collidable = collidable;
this.geom = geom;
}
/**
@ -61,16 +70,22 @@ public class ServerCollidableTree implements BehaviorTree {
public void simulate(float deltaTime){
//have we hit a terrain impulse?
//handle impulses
for(Impulse impulse : collidable.getImpulses()){
if(impulse.type.matches(Collidable.TYPE_CREATURE)){
Impulse[] impulses = collidable.getImpulses();
Vector3d pos = EntityUtils.getPosition(parent);
for(int i = 0; i < collidable.getImpulseCount(); i++){
if(impulses[i].type.matches(Collidable.TYPE_CREATURE)){
if(ServerGravityTree.getServerGravityTree(parent)!=null){
ServerGravityTree.getServerGravityTree(parent).start();
}
}
if(impulse.type.matches(Collidable.TYPE_WORLD_BOUND) || impulse.type.matches(Collidable.TYPE_STATIC)){
if(impulses[i].type.matches(Collidable.TYPE_WORLD_BOUND) || impulses[i].type.matches(Collidable.TYPE_STATIC)){
this.resetGravityFall();
pos.add(impulses[i].getDirection().mul(impulses[i].getForce()));
}
}
if(geom != null){
ServerEntityUtils.repositionEntity(parent, pos);
}
collidable.setReady(true);

View File

@ -119,7 +119,9 @@ public class ClientGravityTree implements BehaviorTree {
public boolean hadGroundCollision(){
boolean rVal = false;
for(Impulse impulse : collidable.getImpulses()){
Impulse[] impulses = collidable.getImpulses();
for(int i = 0; i < collidable.getImpulseCount(); i++){
Impulse impulse = impulses[i];
if(impulse.getType().equals(Collidable.TYPE_STATIC)){
rVal = true;
break;
@ -142,7 +144,9 @@ public class ClientGravityTree implements BehaviorTree {
public boolean hadEntityCollision(){
boolean rVal = false;
for(Impulse impulse : collidable.getImpulses()){
Impulse[] impulses = collidable.getImpulses();
for(int i = 0; i < collidable.getImpulseCount(); i++){
Impulse impulse = impulses[i];
if(impulse.getType().equals(Collidable.TYPE_CREATURE)){
rVal = true;
break;

View File

@ -138,7 +138,9 @@ public class ServerGravityTree implements BehaviorTree {
*/
public boolean hadGroundCollision(){
boolean rVal = false;
for(Impulse impulse : collidable.getImpulses()){
Impulse[] impulses = collidable.getImpulses();
for(int i = 0; i < collidable.getImpulseCount(); i++){
Impulse impulse = impulses[i];
if(impulse.getType().equals(Collidable.TYPE_STATIC)){
rVal = true;
break;
@ -165,7 +167,9 @@ public class ServerGravityTree implements BehaviorTree {
*/
public boolean hadEntityCollision(){
boolean rVal = false;
for(Impulse impulse : collidable.getImpulses()){
Impulse[] impulses = collidable.getImpulses();
for(int i = 0; i < collidable.getImpulseCount(); i++){
Impulse impulse = impulses[i];
if(impulse.getType().equals(Collidable.TYPE_CREATURE)){
rVal = true;
break;

View File

@ -141,7 +141,10 @@ public class ClientFallTree implements BehaviorTree {
public boolean hadGroundCollision(){
boolean rVal = false;
if(PhysicsEntityUtils.getCollidable(parent) != null){
for(Impulse impulse : PhysicsEntityUtils.getCollidable(parent).getImpulses()){
Collidable collidable = PhysicsEntityUtils.getCollidable(parent);
Impulse[] impulses = collidable.getImpulses();
for(int i = 0; i < collidable.getImpulseCount(); i++){
Impulse impulse = impulses[i];
if(impulse.getType().equals(Collidable.TYPE_STATIC)){
rVal = true;
break;