physics work
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit
This commit is contained in:
parent
e57658467b
commit
8bc8fb464b
@ -2119,6 +2119,7 @@ Fix projection matrix being sent to light manager
|
||||
|
||||
(06/05/2025)
|
||||
voxel tests
|
||||
Physics work
|
||||
|
||||
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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,7 +181,8 @@ public class PhysicsCallback implements DNearCallback {
|
||||
}
|
||||
|
||||
//
|
||||
//add contact to contact group
|
||||
//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){
|
||||
@ -174,6 +196,7 @@ public class PhysicsCallback implements DNearCallback {
|
||||
c.attach(b1,b2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Use the default collision resolution
|
||||
CollisionEngine.resolveCollision(
|
||||
|
||||
@ -4,15 +4,21 @@ 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user