From 711ef047fccf77ae07104ffa86e7b68ff948caee Mon Sep 17 00:00:00 2001 From: Edouard DUPIN Date: Fri, 18 Dec 2020 11:30:03 +0100 Subject: [PATCH] [DEV] last development of the 3 physic engine (next step is migration to a generic engine) --- .../components/ComponentPhysics.java | 20 ++- .../gameengine/engines/EnginePhysics.java | 16 +++ .../gameengine/physics/ColisionPoints.java | 1 - .../gameengine/physics/Collision.java | 17 +++ .../gameengine/physics/PhysicBox.java | 27 +++- .../gameengine/physics/PhysicMapVoxel.java | 1 + .../gameengine/physics/PhysicShape.java | 16 ++- .../physics/ToolCollisionOBBWithOBB.java | 120 +++++++++++------- .../samples/LoxelEngine/LoxelApplication.java | 20 +++ .../gameengine/samples/lowPoly/Main.java | 2 +- 10 files changed, 177 insertions(+), 63 deletions(-) create mode 100644 src/org/atriasoft/gameengine/physics/Collision.java diff --git a/src/org/atriasoft/gameengine/components/ComponentPhysics.java b/src/org/atriasoft/gameengine/components/ComponentPhysics.java index 91b5fcf..32da1a0 100644 --- a/src/org/atriasoft/gameengine/components/ComponentPhysics.java +++ b/src/org/atriasoft/gameengine/components/ComponentPhysics.java @@ -117,12 +117,12 @@ public class ComponentPhysics extends Component { return; } for (ComponentPhysics elem : narrowIntersection) { - for (PhysicShape shapeCurrent : shapes) { + for (PhysicShape shapeCurrent : this.shapes) { //TODO Do a better method we do this many times ... if (elem.checkCollide(shapeCurrent) == false) { continue; } - elem.getCollidePoints(shapeCurrent); + elem.getCollidePoints(shapeCurrent, this.staticObject); } } } @@ -173,13 +173,13 @@ public class ComponentPhysics extends Component { } return false; } - private void getCollidePoints(PhysicShape shapeCurrent) { + private void getCollidePoints(PhysicShape shapeCurrent, boolean isStatic) { if (shapeCurrent instanceof PhysicBox) { PhysicBox shape111 = (PhysicBox)shapeCurrent; - for (PhysicShape shape : shapes) { + for (PhysicShape shape : this.shapes) { if (shape instanceof PhysicBox) { PhysicBox shape222 = (PhysicBox)shape; - ToolCollisionOBBWithOBB.getCollidePoints(shape111, shape222); + ToolCollisionOBBWithOBB.getCollidePoints(shape111, isStatic, shape222, this.staticObject); } else if (shape instanceof PhysicSphere) { } else if (shape instanceof PhysicMapVoxel) { @@ -189,7 +189,7 @@ public class ComponentPhysics extends Component { } } } else if (shapeCurrent instanceof PhysicSphere) { - for (PhysicShape shape : shapes) { + for (PhysicShape shape : this.shapes) { if (shape instanceof PhysicBox) { } else if (shape instanceof PhysicSphere) { @@ -201,7 +201,7 @@ public class ComponentPhysics extends Component { } } } else if (shapeCurrent instanceof PhysicMapVoxel) { - for (PhysicShape shape : shapes) { + for (PhysicShape shape : this.shapes) { if (shape instanceof PhysicBox) { } else if (shape instanceof PhysicSphere) { @@ -294,6 +294,12 @@ public class ComponentPhysics extends Component { this.aabbIntersection.clear(); } public void addIntersection(ComponentPhysics component) { + // do not add multiple times + for (ComponentPhysics elem : this.aabbIntersection) { + if (elem == component) { + return; + } + } this.aabbIntersection.add(component); } public List getAabbIntersection() { diff --git a/src/org/atriasoft/gameengine/engines/EnginePhysics.java b/src/org/atriasoft/gameengine/engines/EnginePhysics.java index 8c25c81..31c3bec 100644 --- a/src/org/atriasoft/gameengine/engines/EnginePhysics.java +++ b/src/org/atriasoft/gameengine/engines/EnginePhysics.java @@ -63,11 +63,19 @@ public class EnginePhysics extends Engine { it.applyForces(TIME_STEP, gravity); } } + /** + * Collision detection STEP 1: Upadte the AABB positioning of each elements + * @param timeStep Delta time since the last check + */ private void updateAABB(float timeStep) { for (ComponentPhysics it: components) { it.updateAABB(); } } + /** + * Collision Detection STEP 2: update the list of each element that collide together in the AABB Boxs (update is done between each boxes) + * @param timeStep Delta time since the last check + */ private void updateCollisionsAABB(float timeStep) { // clear all object intersection for (ComponentPhysics it: components) { @@ -86,6 +94,10 @@ public class EnginePhysics extends Engine { } } } + /** + * Collision Detection STEP 3: Narrow phase: process the collision between every OBB boxes (or other..) + * @param timeStep Delta time since the last check + */ private void updateCollisionsNarrowPhase(float timeStep) { // clear all object intersection for (ComponentPhysics it: components) { @@ -103,6 +115,10 @@ public class EnginePhysics extends Engine { current.narrowCollisionCreateContactAndForce(); } } + /** + * Collision Detection STEP 4: apply all calculated forces (with containts) + * @param timeStep + */ private void generateResultCollisionsForces(float timeStep) { } diff --git a/src/org/atriasoft/gameengine/physics/ColisionPoints.java b/src/org/atriasoft/gameengine/physics/ColisionPoints.java index 9037cb3..9a70a00 100644 --- a/src/org/atriasoft/gameengine/physics/ColisionPoints.java +++ b/src/org/atriasoft/gameengine/physics/ColisionPoints.java @@ -7,7 +7,6 @@ public class ColisionPoints { public Vector3f force; public ColisionPoints(Vector3f position, Vector3f force) { - super(); this.position = position; this.force = force; } diff --git a/src/org/atriasoft/gameengine/physics/Collision.java b/src/org/atriasoft/gameengine/physics/Collision.java new file mode 100644 index 0000000..d91bab9 --- /dev/null +++ b/src/org/atriasoft/gameengine/physics/Collision.java @@ -0,0 +1,17 @@ +package org.atriasoft.gameengine.physics; + +public class Collision { + public final ColisionPoints[] colisionPointLocal; + public final PhysicShape shapeRemote; + public final ColisionPoints[] colisionPointRemote; + public final boolean staticRemote; + public Collision(ColisionPoints[] colisionPointLocal, PhysicShape shapeRemote, + ColisionPoints[] colisionPointRemote, boolean staticRemote) { + super(); + this.colisionPointLocal = colisionPointLocal; + this.shapeRemote = shapeRemote; + this.colisionPointRemote = colisionPointRemote; + this.staticRemote = staticRemote; + } + +} diff --git a/src/org/atriasoft/gameengine/physics/PhysicBox.java b/src/org/atriasoft/gameengine/physics/PhysicBox.java index 31719bc..d513263 100644 --- a/src/org/atriasoft/gameengine/physics/PhysicBox.java +++ b/src/org/atriasoft/gameengine/physics/PhysicBox.java @@ -1,10 +1,14 @@ package org.atriasoft.gameengine.physics; +import java.util.ArrayList; +import java.util.List; + import org.atriasoft.etk.Color; import org.atriasoft.etk.math.Matrix4f; import org.atriasoft.etk.math.Transform3D; import org.atriasoft.etk.math.Vector3f; import org.atriasoft.gale.resource.ResourceColored3DObject; +import org.atriasoft.gameengine.internal.Log; public class PhysicBox extends PhysicShape { // Box size property in X, Y and Z @@ -26,6 +30,7 @@ public class PhysicBox extends PhysicShape { public void updateAABB(Transform3D transformGlobal, PhysicCollisionAABB aabb) { // store it, many time usefull... this.transformGlobal = transformGlobal; + this.colisionPoints.clear(); // TODO Auto-generated method stub aabb.update(transformGlobal.multiply(this.transform.multiply(new Vector3f(this.size.x * 0.5f, this.size.y * 0.5f, this.size.z * 0.5f)))); aabb.update(transformGlobal.multiply(this.transform.multiply(new Vector3f(-this.size.x * 0.5f, this.size.y * 0.5f, this.size.z * 0.5f)))); @@ -56,7 +61,7 @@ public class PhysicBox extends PhysicShape { private void renderPoint(Vector3f subPosition, Transform3D transformGlobal, ResourceColored3DObject debugDrawProperty) { Matrix4f transformation = transformGlobal.getOpenGLMatrix().multiplyNew(this.transform.getOpenGLMatrix()).multiply(Matrix4f.createMatrixTranslate(subPosition)); - debugDrawProperty.drawSquare(new Vector3f(0.1f, 0.1f, 0.1f), transformation, new Color(0, 0, 1, 1)); + debugDrawProperty.drawSquare(new Vector3f(0.08f, 0.08f, 0.08f), transformation, new Color(0, 0, 1, 1)); } private void renderPoint2(Vector3f subPosition, Transform3D transformGlobal, ResourceColored3DObject debugDrawProperty) { @@ -71,9 +76,12 @@ public class PhysicBox extends PhysicShape { } - private void renderPoint4(Vector3f subPosition, ResourceColored3DObject debugDrawProperty) { + private void renderPoint4(Vector3f subPosition, Vector3f force, ResourceColored3DObject debugDrawProperty) { debugDrawProperty.drawSquare(new Vector3f(0.1f, 0.1f, 0.1f), Matrix4f.identity().multiply(Matrix4f.createMatrixTranslate(subPosition)), new Color(1, 0, 0, 1)); - + List tmp = new ArrayList<>(); + tmp.add(new Vector3f(0,0,0)); + tmp.add(force); + debugDrawProperty.drawLine(tmp, new Color(1, 0, 0, 1), Matrix4f.identity().multiply(Matrix4f.createMatrixTranslate(subPosition)), true, false); } @Override @@ -88,10 +96,17 @@ public class PhysicBox extends PhysicShape { renderPoint(new Vector3f(-dimention.x, +dimention.y, -dimention.z), transformGlobal, debugDrawProperty); renderPoint(new Vector3f(+dimention.x, -dimention.y, -dimention.z), transformGlobal, debugDrawProperty); renderPoint3(new Vector3f(-dimention.x, -dimention.y, -dimention.z), transformGlobal, debugDrawProperty); - if (this.colisionPointTest != null) { - for (int iii = 0; iii < this.colisionPointTest.length; iii++) { - renderPoint4(this.colisionPointTest[iii].position, debugDrawProperty); + for (Collision elem: this.colisionPoints) { + if (elem != null) { + if (elem.colisionPointLocal == null) { + Log.error("colision point must be set !!!"); + continue; + } + for (int iii = 0; iii < elem.colisionPointLocal.length; iii++) { + renderPoint4(elem.colisionPointLocal[iii].position, elem.colisionPointLocal[iii].force, debugDrawProperty); + } } } } + } diff --git a/src/org/atriasoft/gameengine/physics/PhysicMapVoxel.java b/src/org/atriasoft/gameengine/physics/PhysicMapVoxel.java index 415db93..16db627 100644 --- a/src/org/atriasoft/gameengine/physics/PhysicMapVoxel.java +++ b/src/org/atriasoft/gameengine/physics/PhysicMapVoxel.java @@ -17,6 +17,7 @@ public class PhysicMapVoxel extends PhysicShape { if (this.chunk == null) { return; } + this.colisionPoints.clear(); aabb.update(new Vector3f(this.chunk.getPosition().x,this.chunk.getPosition().y,this.chunk.getPosition().z)); aabb.update(new Vector3f( this.chunk.getPosition().x + VoxelChunk.VOXEL_CHUNK_SIZE, diff --git a/src/org/atriasoft/gameengine/physics/PhysicShape.java b/src/org/atriasoft/gameengine/physics/PhysicShape.java index 4ee032c..4057f2d 100644 --- a/src/org/atriasoft/gameengine/physics/PhysicShape.java +++ b/src/org/atriasoft/gameengine/physics/PhysicShape.java @@ -1,12 +1,21 @@ package org.atriasoft.gameengine.physics; +import java.util.ArrayList; +import java.util.List; + import org.atriasoft.etk.math.Quaternion; import org.atriasoft.etk.math.Transform3D; import org.atriasoft.etk.math.Vector3f; import org.atriasoft.gale.resource.ResourceColored3DObject; + + + public abstract class PhysicShape { - public ColisionPoints[] colisionPointTest; + + + + protected List colisionPoints = new ArrayList<>(); // protected Quaternion quaternion; // protected Vector3f origin; protected Transform3D transform; @@ -78,6 +87,11 @@ public abstract class PhysicShape { return type; } + public void addColision(Collision colision) { + colisionPoints.add(colision); + } + + public abstract void updateAABB(Transform3D transform, PhysicCollisionAABB aabb); public abstract void updateForNarrowCollision(Transform3D transform); diff --git a/src/org/atriasoft/gameengine/physics/ToolCollisionOBBWithOBB.java b/src/org/atriasoft/gameengine/physics/ToolCollisionOBBWithOBB.java index 24603a2..ca8acc3 100644 --- a/src/org/atriasoft/gameengine/physics/ToolCollisionOBBWithOBB.java +++ b/src/org/atriasoft/gameengine/physics/ToolCollisionOBBWithOBB.java @@ -44,42 +44,42 @@ public class ToolCollisionOBBWithOBB { || getSeparatingPlane(rPos, box1.axisZ.cross(box2.axisZ), box1, box2); return !ret; } - - // a quick test to see the code working - public static void main(String[] args) { - // create two obbs - OBB aaa = new OBB(); - OBB bbb = new OBB(); - - // set the first obb's properties - aaa.position = new Vector3f(0.0f, 0.0f, 0.0f); // set its center position - - // set the half size - aaa.halfSize = new Vector3f(10.0f, 1.0f, 1.0f); - - // set the axes orientation - aaa.axisX = new Vector3f(1.0f, 0.0f, 0.0f); - aaa.axisY = new Vector3f(0.0f, 1.0f, 0.0f); - aaa.axisZ = new Vector3f(0.0f, 0.0f, 1.0f); - - // set the second obb's properties - bbb.position = new Vector3f(20.0f, 0.0f, 0.0f); // set its center position - - // set the half size - bbb.halfSize = new Vector3f(10.0f, 1.0f, 1.0f); - - // set the axes orientation - bbb.axisX = new Vector3f(1.0f, 0.0f, 0.0f); - bbb.axisY = new Vector3f(0.0f, 1.0f, 0.0f); - bbb.axisZ = new Vector3f(0.0f, 0.0f, 1.0f); - - // run the code and get the result as a message - if (getCollision(aaa, bbb)) { - Log.info("Collision!!!"); - } else { - Log.info("NO Collision!!!"); - } - } +// +// // a quick test to see the code working +// public static void main(String[] args) { +// // create two obbs +// OBB aaa = new OBB(); +// OBB bbb = new OBB(); +// +// // set the first obb's properties +// aaa.position = new Vector3f(0.0f, 0.0f, 0.0f); // set its center position +// +// // set the half size +// aaa.halfSize = new Vector3f(10.0f, 1.0f, 1.0f); +// +// // set the axes orientation +// aaa.axisX = new Vector3f(1.0f, 0.0f, 0.0f); +// aaa.axisY = new Vector3f(0.0f, 1.0f, 0.0f); +// aaa.axisZ = new Vector3f(0.0f, 0.0f, 1.0f); +// +// // set the second obb's properties +// bbb.position = new Vector3f(20.0f, 0.0f, 0.0f); // set its center position +// +// // set the half size +// bbb.halfSize = new Vector3f(10.0f, 1.0f, 1.0f); +// +// // set the axes orientation +// bbb.axisX = new Vector3f(1.0f, 0.0f, 0.0f); +// bbb.axisY = new Vector3f(0.0f, 1.0f, 0.0f); +// bbb.axisZ = new Vector3f(0.0f, 0.0f, 1.0f); +// +// // run the code and get the result as a message +// if (getCollision(aaa, bbb)) { +// Log.info("Collision!!!"); +// } else { +// Log.info("NO Collision!!!"); +// } +// } // check if there's a separating plane in between the selected axes private static boolean getSeparatingPlane222(Vector3f rPos, Vector3f plane, PhysicBox box1, PhysicBox box2) { @@ -107,7 +107,7 @@ public class ToolCollisionOBBWithOBB { return !ret; } - public static void getCollidePoints(PhysicBox box1, PhysicBox box2) { + public static void getCollidePoints(PhysicBox box1, boolean isStatic1, PhysicBox box2, boolean isStatic2) { // Log.info("Try to calculare reverse force ........"); Vector3f rPos1 = box1.narrowPhaseGlobalPos.lessNew(box2.narrowPhaseGlobalPos); Vector3f rPos2 = box2.narrowPhaseGlobalPos.lessNew(box1.narrowPhaseGlobalPos); @@ -143,11 +143,11 @@ public class ToolCollisionOBBWithOBB { // fonctionne quand le block est trourner de 90% petit pb de positionnement en hauteur.... // getCollidePointsAABBCenteredWithOBB(box2.narrowPhaseHalfSize, box1.narrowPhaseHalfSize, quatTransfer2, quat2.multiply(rPos2)); ColisionPoints[] collide1 = getCollidePointsAABBCenteredWithOBB(box2.narrowPhaseHalfSize, box1.narrowPhaseHalfSize, quatTransfer2, quat2.inverseNew().getMatrix4().multiply(rPos1)); - box1.colisionPointTest = collide1; // transfer detection point collision in global environement: if (collide1 != null) { for (int iii = 0; iii < collide1.length; iii++) { collide1[iii].position = quat1.multiply(collide1[iii].position).add(box1.narrowPhaseGlobalPos); + collide1[iii].force = quat2.multiply(collide1[iii].force);//.add(box1.narrowPhaseGlobalPos); } } /* res = trensfert in generic plan the new res ... */ @@ -157,12 +157,21 @@ public class ToolCollisionOBBWithOBB { LoxelApplication.box1HalfSize = box1.narrowPhaseHalfSize; LoxelApplication.box2HalfSize = box2.narrowPhaseHalfSize; ColisionPoints[] collide2 = getCollidePointsAABBCenteredWithOBB(box1.narrowPhaseHalfSize, box2.narrowPhaseHalfSize, quatTransfer1, quat1.inverseNew().getMatrix4().multiply(rPos2)); - box2.colisionPointTest = collide2; if (collide2 != null) { for (int iii = 0; iii < collide2.length; iii++) { collide2[iii].position = quat2.multiply(collide2[iii].position).add(box2.narrowPhaseGlobalPos); + collide2[iii].force = quat1.multiply(collide2[iii].force);//.add(box2.narrowPhaseGlobalPos); } } + // add only if NOT static, when static no colision is performed + if (true) { //!isStatic1) { + Collision colision = new Collision(collide1, box2, collide2, isStatic2); + box1.addColision(colision); + } + if (true) { //!isStatic1) { + Collision colision = new Collision(collide2, box1, collide1, isStatic1); + box2.addColision(colision); + } } @@ -273,13 +282,15 @@ public class ToolCollisionOBBWithOBB { } if (count != 0) { // Find a point inside the BOX ... + /* Log.info("Detect point inside ... " + insideTopBackRight + " " + insideTopBackLeft + " " + insideTopFrontRight + " " + insideTopFrontLeft + " " + insideBottomBackRight + " " + insideBottomBackLeft + " " + insideBottomFrontRight + " " + insideBottomFrontLeft); - + */ return out; } // line in AABB - Log.info("Need to detect line inside ..."); + // TODO: + // Log.info("Need to detect line inside ..."); // pas tot a fait... si ca colisione déja avec un point de l'autre ... return null; } @@ -294,46 +305,61 @@ public class ToolCollisionOBBWithOBB { Vector3f out = new Vector3f(); if (point.x < 0) { if (point.x > -halfSize.x) { - out.x = -halfSize.x + point.x; + + out.x = -(halfSize.x + point.x); + + //out.x = -halfSize.x - point.x; + //out.x = -halfSize.x + point.x; + //out.x = + point.x; } else { return null; } } else { if (point.x < halfSize.x) { + //out.x = halfSize.x + point.x; out.x = halfSize.x - point.x; + //out.x = - point.x; } else { return null; } } if (point.y < 0) { if (point.y > -halfSize.y) { - out.y = -halfSize.y + point.y; + out.y = -halfSize.y - point.y; + //out.y = -halfSize.y + point.y; + //out.y = point.y; } else { return null; } } else { if (point.y < halfSize.y) { + //out.y = halfSize.y + point.y; out.y = halfSize.y - point.y; + //out.y = - point.y; } else { return null; } } if (point.z < 0) { if (point.z > -halfSize.z) { - out.z = -halfSize.z + point.z; + out.z = -halfSize.z - point.z; + //out.z = -halfSize.z + point.z; + //out.z = + point.z; } else { return null; } } else { if (point.z < halfSize.z) { + //out.z = halfSize.z + point.z; out.z = halfSize.z - point.z; + //out.z = - point.z; } else { return null; } } - if (out.x < out.y) { + if (Math.abs(out.x) < Math.abs(out.y)) { out.y = 0; - if (out.x < out.z) { + if (Math.abs(out.x) < Math.abs(out.z)) { out.z = 0; return out; } @@ -341,7 +367,7 @@ public class ToolCollisionOBBWithOBB { return out; } out.x = 0; - if (out.y < out.z) { + if (Math.abs(out.y) < Math.abs(out.z)) { out.z = 0; return out; } diff --git a/src/org/atriasoft/gameengine/samples/LoxelEngine/LoxelApplication.java b/src/org/atriasoft/gameengine/samples/LoxelEngine/LoxelApplication.java index ecfacc5..bf012c4 100644 --- a/src/org/atriasoft/gameengine/samples/LoxelEngine/LoxelApplication.java +++ b/src/org/atriasoft/gameengine/samples/LoxelEngine/LoxelApplication.java @@ -184,6 +184,26 @@ public class LoxelApplication extends Application { Entity localBox = new Entity(this.env); Quaternion transform = new Quaternion(0.5f,0.2f,0.4f,1); transform.normalize(); + localBox.addComponent(new ComponentPosition(new Transform3D(new Vector3f(15,15,14), transform))); + localBox.addComponent(new ComponentStaticMesh(new Uri("RES", "cube-one.obj"))); + localBox.addComponent(new ComponentTexture(new Uri("DATA", "blocks/clay.png"))); + localBox.addComponent(new ComponentRenderTexturedStaticMesh( + new Uri("DATA", "basic.vert"), + new Uri("DATA", "basic.frag"))); + ComponentPhysics physics2 = new ComponentPhysics(true); + PhysicBox box2 = new PhysicBox(); + box2.setSize(new Vector3f(8,8,8)); + box2.setOrigin(new Vector3f(0,0,0)); + box2.setMass(1); + physics2.addShape(box2); + localBox.addComponent(physics2); + env.addEntity(localBox); + } + { + // add a cube to test collision ... + Entity localBox = new Entity(this.env); + Quaternion transform = new Quaternion(0.3f,0.3f,0.4f,1); + transform.normalize(); localBox.addComponent(new ComponentPosition(new Transform3D(new Vector3f(2,-2,14.2f),transform))); localBox.addComponent(new ComponentStaticMesh(new Uri("RES", "cube-one.obj"))); localBox.addComponent(new ComponentTexture(new Uri("DATA", "blocks/clay.png"))); diff --git a/src/org/atriasoft/gameengine/samples/lowPoly/Main.java b/src/org/atriasoft/gameengine/samples/lowPoly/Main.java index 99faec4..5f23f9a 100644 --- a/src/org/atriasoft/gameengine/samples/lowPoly/Main.java +++ b/src/org/atriasoft/gameengine/samples/lowPoly/Main.java @@ -5,7 +5,7 @@ import org.atriasoft.gale.Gale; public class Main { public static void main(String[] args) { - Uri.setGroup("DATA", "src/org/atriasoft/gameengine/sample/lowPoly/"); + Uri.setGroup("DATA", "src/org/atriasoft/gameengine/samples/lowPoly/"); Uri.setGroup("DATA_EGE", "src/org/atriasoft/gameengine/data/"); Uri.setGroup("RES", "res"); Gale.run(new LowPolyApplication(), args);