super janky rigid body collisions
This commit is contained in:
parent
c02b9ed2ca
commit
b817940716
22 changed files with 2383 additions and 1129 deletions
1726
LastSession.t4jlog
1726
LastSession.t4jlog
File diff suppressed because it is too large
Load diff
|
|
@ -78,6 +78,10 @@ public class EngineConfig {
|
|||
public float Gamma = 0.8545f;
|
||||
public int MaxVulkanCrashesAllowed = 10;
|
||||
public boolean RenderCollisionMesh = true;
|
||||
public float PhysicsSpeed = 1.0f;
|
||||
|
||||
public float PhysicsSpeed(){return PhysicsSpeed;}
|
||||
public void SetPhysicsSpeed(float NewSpeed){PhysicsSpeed =NewSpeed;}
|
||||
|
||||
public boolean RenderCollisionMeshes(){
|
||||
return RenderCollisionMesh;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,19 @@
|
|||
package net.halbear.Terrain4J.EngineCore.Logic.Physics;
|
||||
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Collision.CollisionPoly;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.Scene.Actor;
|
||||
import org.joml.Quaternionf;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
public record CollisionSensor(Vector3f Offset, String ActorID) {
|
||||
public Vector3f GetTransformedCollisionSensor() {
|
||||
Actor actor = Actor.Actors.get(ActorID);
|
||||
if (actor != null) {
|
||||
CollisionSensor newSensor = new CollisionSensor(new Vector3f().set(Offset), ActorID);
|
||||
Vector3f PivotOffset = new Vector3f().set(actor.GetPivotOffset()).add(actor.GetAditionalPivotOffset());
|
||||
return newSensor.TransformPosition(PivotOffset).TransformRotation(actor.GetRotation()).TransformPosition(PivotOffset.negate()).TransformScale(actor.GetScale()).TransformPosition(actor.GetPosition()).Offset;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public CollisionSensor TransformRotation(Quaternionf quaternionf){
|
||||
if(quaternionf == null ) return this;
|
||||
Vector3f newV1 = new Vector3f(Offset);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
package net.halbear.Terrain4J.EngineCore.Logic.Physics;
|
||||
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Physics.LegacyCollision.CollisionMesh;
|
||||
import org.joml.Vector2f;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IPhysicsController {
|
||||
public String ID();
|
||||
public String ActorID();
|
||||
public String MeshID();
|
||||
public void PhysicsTick(float DeltaTime, float TargetFrameRate);
|
||||
public List<String> Collisions();
|
||||
public void CollisionEvent(CollisionMesh collidingMesh, Vector3f PositionDifference, Vector2f CollisionScale);
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package net.halbear.Terrain4J.EngineCore.Logic.Physics.LegacyCollision;
|
||||
|
||||
import org.joml.Vector3f;
|
||||
|
||||
public record CollisionIndexPoly(int Index1, int Index2, int Index3) {
|
||||
public CollisionPoly GetCollisionPoly(CollisionMesh mesh){
|
||||
Vector3f[] vertices = mesh.GetTransformedVertices(new int[]{Index1,Index2,Index3});
|
||||
CollisionPoly polygon = new CollisionPoly(vertices[0],vertices[1],vertices[2],new Vector3f());
|
||||
polygon.CalculateCentre();
|
||||
return polygon;
|
||||
}
|
||||
public CollisionPoly GetRawCollisionPoly(CollisionMesh mesh){
|
||||
Vector3f[] vertices = mesh.GetUntransformedVertices(new int[]{Index1,Index2,Index3});
|
||||
CollisionPoly polygon = new CollisionPoly(vertices[0],vertices[1],vertices[2],new Vector3f());
|
||||
polygon.CalculateCentre();
|
||||
return polygon;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package net.halbear.Terrain4J.EngineCore.Logic.Collision;
|
||||
package net.halbear.Terrain4J.EngineCore.Logic.Physics.LegacyCollision;
|
||||
|
||||
import org.joml.Vector3f;
|
||||
import org.joml.primitives.AABBf;
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package net.halbear.Terrain4J.EngineCore.Logic.Collision;
|
||||
package net.halbear.Terrain4J.EngineCore.Logic.Physics.LegacyCollision;
|
||||
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Physics.LegacyPhysicsController;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.Scene.Actor;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.Util.Maths.T4Math;
|
||||
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel.MeshData;
|
||||
|
|
@ -15,7 +16,9 @@ import java.io.*;
|
|||
import java.util.*;
|
||||
|
||||
public class CollisionMesh {
|
||||
public final List<CollisionPoly> Polygons;
|
||||
public final List<Vector3f> Vertices;
|
||||
public final List<CollisionIndexPoly> Polygons;
|
||||
public final Map<String, Integer> VertexLookup;
|
||||
public Vector3f TopRightFront = new Vector3f(0,0,0);
|
||||
public Vector3f BottomLeftBack = new Vector3f(0,0,0);
|
||||
public Vector3f WorldPosition = new Vector3f(0,0,0);
|
||||
|
|
@ -25,6 +28,8 @@ public class CollisionMesh {
|
|||
public final String ParentID;
|
||||
public AABBf Voxel;
|
||||
|
||||
public List<Vector3f> GetVertices(){return Vertices;}
|
||||
|
||||
public CollisionMesh(String ID, String ActorID){
|
||||
this.ID = ID;
|
||||
if(ActorID != "NULL") {
|
||||
|
|
@ -32,7 +37,9 @@ public class CollisionMesh {
|
|||
Rotation = new Quaternionf(Actor.Actors.get(ActorID).GetRotation());
|
||||
}
|
||||
ParentID = ActorID;
|
||||
VertexLookup = new HashMap<>();
|
||||
Polygons = new ArrayList<>();
|
||||
Vertices = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void RegisterMesh(){
|
||||
|
|
@ -40,15 +47,15 @@ public class CollisionMesh {
|
|||
}
|
||||
|
||||
public AABBf GetVoxelCollider(){
|
||||
if(TopRightFront == null || BottomLeftBack == null) return null;
|
||||
if(Voxel == null){
|
||||
Vector3f TLF = new Vector3f(TopRightFront);
|
||||
Vector3f BRB = new Vector3f(BottomLeftBack);
|
||||
TLF = TLF.mul(Scale).rotate(Rotation).add(WorldPosition);
|
||||
BRB = BRB.mul(Scale).rotate(Rotation).add(WorldPosition);
|
||||
AABBf ThisVoxel = new AABBf(BRB,TLF);
|
||||
this.Voxel = ThisVoxel;
|
||||
}
|
||||
//if(TopRightFront == null || BottomLeftBack == null) return null;
|
||||
//if(Voxel == null){
|
||||
Vector3f PivotOffset = Actor.Actors.get(ParentID) != null ? new Vector3f(Actor.Actors.get(ParentID).GetPivotOffset()).add(Actor.Actors.get(ParentID).GetAditionalPivotOffset()) : new Vector3f(0,0,0);
|
||||
Vector3f TLF = new Vector3f(TopRightFront);
|
||||
Vector3f BRB = new Vector3f(BottomLeftBack);
|
||||
TLF = TLF.add(PivotOffset).rotate(Rotation).sub(PivotOffset).mul(Scale).add(WorldPosition);
|
||||
BRB = BRB.add(PivotOffset).rotate(Rotation).sub(PivotOffset).mul(Scale).add(WorldPosition);
|
||||
this.Voxel = new AABBf(BRB,TLF);
|
||||
//}
|
||||
return Voxel;
|
||||
}
|
||||
|
||||
|
|
@ -93,7 +100,7 @@ public class CollisionMesh {
|
|||
List<int[]> Indices = new ArrayList<>();
|
||||
int IndexCount = 0;
|
||||
int vertexOffset = 0;
|
||||
int vertexStride = 14; // Your stride configuration
|
||||
int vertexStride = 14;
|
||||
for (MeshData meshData : vkModel.Meshes()) {
|
||||
int intsToRead = meshData.IndexSize() / VulkanUtils.INT_SIZE;
|
||||
int[] meshIndices = new int[intsToRead];
|
||||
|
|
@ -141,17 +148,30 @@ public class CollisionMesh {
|
|||
BottomLeftBack.z = Math.min(BottomLeftBack.z, localMinZ);
|
||||
}
|
||||
|
||||
public void GenerateSensorsFromVertices(){
|
||||
if(Actor.Actors.get(ParentID) != null &&Actor.Actors.get(ParentID).PhysicsType == Actor.PhysicsControllerType.T4JLegacyCollision) {
|
||||
LegacyPhysicsController physicsController = (LegacyPhysicsController)Actor.Actors.get(ParentID).GetPhysicsController();
|
||||
physicsController.collisionSensors.clear();
|
||||
for(int i = 0; i < Vertices.size(); i++){
|
||||
physicsController.AddCollisionSensor(Vertices.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AddNewCollisionPoly(Vector3f v1, Vector3f v2, Vector3f v3){
|
||||
// if(Actor.Actors.get(ParentID) != null) {
|
||||
// PhysicsController physicsController = Actor.Actors.get(ParentID).GetPhysicsController();
|
||||
// if (physicsController != null) {
|
||||
// physicsController.AddCollisionSensor(v1);
|
||||
// physicsController.AddCollisionSensor(v2);
|
||||
// physicsController.AddCollisionSensor(v3);
|
||||
// }
|
||||
// }
|
||||
CollisionPoly newPoly = new CollisionPoly(v1,v2,v3,new Vector3f(0,0,0));
|
||||
newPoly.CalculateCentre();
|
||||
Vector3f[] vertices = new Vector3f[]{v1,v2,v3};
|
||||
int[] Index = new int[3];
|
||||
for(int i = 0; i < 3; i++) {
|
||||
String Vertex = vertices[i].x + "_" + vertices[i].y + "_" + vertices[i].z;
|
||||
Index[i] = Vertices.size();
|
||||
if (VertexLookup.containsKey(Vertex)) {
|
||||
Index[i] = VertexLookup.get(Vertex);
|
||||
} else {
|
||||
Vertices.add(new Vector3f(vertices[i]));
|
||||
VertexLookup.put(Vertex, Index[i]);
|
||||
}
|
||||
}
|
||||
CollisionIndexPoly newPoly = new CollisionIndexPoly(Index[0],Index[1],Index[2]);
|
||||
Polygons.add(newPoly);
|
||||
CheckAABbounds(v1,v2,v3);
|
||||
}
|
||||
|
|
@ -168,10 +188,11 @@ public class CollisionMesh {
|
|||
}
|
||||
|
||||
public boolean CheckAABBCollisionAgainstAABB(AABBf OtherVoxel){
|
||||
Vector3f PivotOffset = Actor.Actors.get(ParentID) != null ? new Vector3f(Actor.Actors.get(ParentID).GetPivotOffset()).add(Actor.Actors.get(ParentID).GetAditionalPivotOffset()) : new Vector3f(0,0,0);
|
||||
Vector3f TLF = new Vector3f(TopRightFront);
|
||||
Vector3f BRB = new Vector3f(BottomLeftBack);
|
||||
TLF = TLF.mul(Scale).rotate(Rotation).add(WorldPosition);
|
||||
BRB = BRB.mul(Scale).rotate(Rotation).add(WorldPosition);
|
||||
TLF = TLF.add(PivotOffset).rotate(Rotation).sub(PivotOffset).mul(Scale).add(WorldPosition);
|
||||
BRB = BRB.add(PivotOffset).rotate(Rotation).sub(PivotOffset).mul(Scale).add(WorldPosition);
|
||||
AABBf ThisVoxel = new AABBf(BRB,TLF);
|
||||
this.Voxel = ThisVoxel;
|
||||
return ThisVoxel.intersectsAABB(OtherVoxel);
|
||||
|
|
@ -191,10 +212,10 @@ public class CollisionMesh {
|
|||
public boolean SimpleCheckCollision(Vector3f Origin, Vector3f Sensor){
|
||||
Vector3f LineDirection = new Vector3f(Sensor).sub(Origin);
|
||||
Vector2f Result = new Vector2f(0,0);
|
||||
CollisionPoly[] polygons = GetAllPolygons();
|
||||
if(Intersectionf.intersectRayAab(Origin, LineDirection, BottomLeftBack, TopRightFront,Result) && Result.x <= 1.0f && Result.y >= 0.0f){
|
||||
for(int i = 0; i < Polygons.size(); i++){
|
||||
CollisionPoly polygon = Polygons.get(i);
|
||||
if(T4Math.Math3D.DoesLineCollideWithPoly(Origin,Sensor,new Vector3f[]{polygon.v1(),polygon.v2(),polygon.v3()})){
|
||||
for (CollisionPoly polygon : polygons) {
|
||||
if (T4Math.Math3D.DoesLineCollideWithPoly(Origin, Sensor, new Vector3f[]{polygon.v1(), polygon.v2(), polygon.v3()})) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -202,27 +223,63 @@ public class CollisionMesh {
|
|||
return false;
|
||||
}
|
||||
|
||||
public Vector3f[] GetTransformedVertices(int[] index){
|
||||
Vector3f PivotOffset = Actor.Actors.get(ParentID) != null ? new Vector3f(Actor.Actors.get(ParentID).GetPivotOffset()).add(Actor.Actors.get(ParentID).GetAditionalPivotOffset()) : new Vector3f(0,0,0);
|
||||
Vector3f[] vertices = new Vector3f[index.length];
|
||||
Vector3f Vertex = new Vector3f();
|
||||
for(int i = 0; i < vertices.length; i++) {
|
||||
if (index[i] < Vertices.size() && Vertices.get(index[i]) != null) {
|
||||
Vertex.set((Vertices.get(index[i])));
|
||||
Vertex.add(PivotOffset).rotate(Rotation).sub(PivotOffset).mul(Scale).add(WorldPosition);
|
||||
vertices[i] = new Vector3f(Vertex);
|
||||
}
|
||||
}
|
||||
return vertices;
|
||||
}
|
||||
|
||||
public Vector3f[] GetUntransformedVertices(int[] index){
|
||||
Vector3f[] vertices = new Vector3f[index.length];
|
||||
Vector3f Vertex = new Vector3f();
|
||||
for(int i = 0; i < vertices.length; i++) {
|
||||
if (index[i] < Vertices.size() && Vertices.get(index[i]) != null) {
|
||||
Vertex.set((Vertices.get(index[i])));
|
||||
vertices[i] = new Vector3f(Vertex);
|
||||
}
|
||||
}
|
||||
return vertices;
|
||||
}
|
||||
|
||||
public Vector3f GetTransformedVertex(int index){
|
||||
Vector3f PivotOffset = Actor.Actors.get(ParentID) != null ? new Vector3f(Actor.Actors.get(ParentID).GetPivotOffset()).add(Actor.Actors.get(ParentID).GetAditionalPivotOffset()) : new Vector3f(0,0,0);
|
||||
if(index > Vertices.size() || index < 0) return null;
|
||||
Vector3f Vertex = new Vector3f(Vertices.get(index));
|
||||
Vertex.add(PivotOffset).rotate(Rotation).sub(PivotOffset).mul(Scale).add(WorldPosition);
|
||||
return Vertex;
|
||||
}
|
||||
|
||||
public CollisionPoly[] GetAllPolygons(){
|
||||
int Rows = Polygons.size();
|
||||
CollisionPoly[] PolygonArr = new CollisionPoly[Rows * 3];
|
||||
Vector3f PivotOffset = Actor.Actors.get(ParentID) != null ? new Vector3f(Actor.Actors.get(ParentID).GetPivotOffset()).add(Actor.Actors.get(ParentID).GetAditionalPivotOffset()) : new Vector3f(0,0,0);
|
||||
for(int row = 0; row < Rows; row++){
|
||||
PolygonArr[row] = Polygons.get(row).TransformScale(Scale).TransformPosition(PivotOffset).TransformRotation(Rotation).TransformPosition(PivotOffset.negate()).TransformPosition(WorldPosition);
|
||||
CollisionIndexPoly IndexPoly = Polygons.get(row);
|
||||
CollisionPoly CollisionPoly = IndexPoly.GetRawCollisionPoly(this);
|
||||
PolygonArr[row] = CollisionPoly.TransformPosition(PivotOffset).TransformRotation(Rotation).TransformPosition(PivotOffset.negate()).TransformScale(Scale).TransformPosition(WorldPosition);
|
||||
}
|
||||
return PolygonArr;
|
||||
}
|
||||
|
||||
public Vector3f[] GetAllVertices(){
|
||||
int Rows = Polygons.size();
|
||||
Vector3f PivotOffset = Actor.Actors.get(ParentID) != null ? new Vector3f(Actor.Actors.get(ParentID).GetPivotOffset()).add(Actor.Actors.get(ParentID).GetAditionalPivotOffset()) : new Vector3f(0,0,0);
|
||||
Vector3f[] Vertices = new Vector3f[Rows * 3];
|
||||
for(int row = 0; row < Rows; row++){
|
||||
int StartPos = row * 3;
|
||||
CollisionPoly poly = Polygons.get(row).TransformScale(Scale).TransformPosition(PivotOffset).TransformRotation(Rotation).TransformPosition(PivotOffset.negate()).TransformPosition(WorldPosition);
|
||||
Vertices[StartPos] = new Vector3f(poly.v1().x,poly.v1().y,poly.v1().z);
|
||||
Vertices[StartPos + 1] = new Vector3f(poly.v2().x,poly.v2().y,poly.v2().z);
|
||||
Vertices[StartPos + 2] = new Vector3f(poly.v3().x,poly.v3().y,poly.v3().z);
|
||||
Vector3f[] vertices = new Vector3f[Vertices.size()];
|
||||
Vector3f Vertex = new Vector3f();
|
||||
for(int i = 0; i < vertices.length; i++) {
|
||||
if (Vertices.get(i) != null) {
|
||||
Vertex.set((Vertices.get(i)));
|
||||
Vertex.add(PivotOffset).rotate(Rotation).sub(PivotOffset).mul(Scale).add(WorldPosition);
|
||||
vertices[i] = new Vector3f(Vertex);
|
||||
}
|
||||
}
|
||||
return Vertices;
|
||||
return vertices;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package net.halbear.Terrain4J.EngineCore.Logic.Collision;
|
||||
package net.halbear.Terrain4J.EngineCore.Logic.Physics.LegacyCollision;
|
||||
|
||||
import net.halbear.Terrain4J.EngineCore.Main.Util.Maths.T4Math;
|
||||
import org.joml.Math;
|
||||
|
|
@ -16,6 +16,7 @@ public record CollisionPoly(Vector3f v1, Vector3f v2, Vector3f v3, Vector3f Cent
|
|||
Centre.set(new Vector3f(x,y,z));
|
||||
return Centre;
|
||||
}
|
||||
public Vector3f[] GetVertices(){return new Vector3f[]{v1,v2,v3};}
|
||||
public CollisionPoly TransformRotation(Quaternionf quaternionf){
|
||||
if(quaternionf == null ) return this;
|
||||
Vector3f newV1 = new Vector3f(v1);
|
||||
|
|
@ -0,0 +1,336 @@
|
|||
package net.halbear.Terrain4J.EngineCore.Logic.Physics;
|
||||
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Physics.LegacyCollision.CollisionManager;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Physics.LegacyCollision.CollisionMesh;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Physics.LegacyCollision.CollisionPoly;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.Scene.Actor;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.Util.Maths.T4Math;
|
||||
import org.joml.Vector2f;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static net.halbear.Terrain4J.EngineCore.Logic.Physics.LegacyCollision.CollisionManager.ChunkWidth;
|
||||
import static net.halbear.Terrain4J.EngineCore.Main.Util.Maths.T4Math.Physics.*;
|
||||
|
||||
public class LegacyPhysicsController implements IPhysicsController {
|
||||
|
||||
public enum CollisionType{
|
||||
PolyToPoly,
|
||||
Sensor
|
||||
}
|
||||
|
||||
public List<CollisionSensor> collisionSensors;
|
||||
public Vector3f Velocities = new Vector3f(0,0,0);
|
||||
public Vector3f WeightBalance = new Vector3f(0,0,0);
|
||||
public float MassKG = 10.0f;
|
||||
public Vector3f TerminalVelocitiesMS = new Vector3f(36f,6.6f,36f);
|
||||
public Vector3f Drag = new Vector3f(0.2f,0.2f,0.2f);
|
||||
public Vector3f DragCoefficients = new Vector3f(0.1f,0.1f,0.1f);
|
||||
public Vector3f CrossSectionAreas = new Vector3f(1.8f * 0.9f, 0.6f * 0.9f, 1.8f * 0.6f);
|
||||
public Vector3f WeightDistribution = new Vector3f(2.0f,5.0f,7.0f);
|
||||
public float FallingAcceleration = 0.0f;
|
||||
public float Bounciness = 0.3f;
|
||||
String CurrentChunkPosition = "NULL";
|
||||
public CollisionType MeshCollision;
|
||||
|
||||
private final Vector3f Velocity = new Vector3f();
|
||||
private final Vector3f Position = new Vector3f();
|
||||
private final Vector3f NextPosition = new Vector3f();
|
||||
private final Vector3f localVelocityStep = new Vector3f();
|
||||
private final Vector3f displacement = new Vector3f();
|
||||
private final Vector3f slidingCorrection = new Vector3f();
|
||||
private final Vector3f sensorSubtraction = new Vector3f();
|
||||
private final Vector3f pivotOffsetCache = new Vector3f();
|
||||
|
||||
private final List<Vector3f> transformedSensorsCache = new ArrayList<>();
|
||||
|
||||
public final List<String> Collisions = new ArrayList<>();
|
||||
|
||||
//public record CollisionResult(boolean Intersects,Vector3f StartPoint,Vector3f EndPoint){
|
||||
//
|
||||
//}
|
||||
public static class CollisionResult{
|
||||
public boolean Intersects = false;
|
||||
public Vector3f StartPoint = null;
|
||||
public Vector3f EndPoint = null;
|
||||
public Vector3f CollisionNormal = null;
|
||||
public float CollisionDepth;
|
||||
}
|
||||
|
||||
public void SetCollisionType(CollisionType collisionType){
|
||||
this.MeshCollision = collisionType;
|
||||
}
|
||||
public CollisionType GetCollisionType(){return MeshCollision;}
|
||||
|
||||
public final String ID;
|
||||
public final String ParentID;
|
||||
|
||||
public void ImpulseVelocity(Vector3f Velocity){
|
||||
Velocities.add(Velocity);
|
||||
}
|
||||
|
||||
public LegacyPhysicsController(String ActorID, CollisionType collisionType){
|
||||
MeshCollision = collisionType;
|
||||
collisionSensors = new ArrayList<>();
|
||||
ID = ActorID + "_PHYSICS_CONTROLLER";
|
||||
ParentID = ActorID;
|
||||
WorldPhysicsManager.PhysicsObjects.put(ID, this);
|
||||
WorldPhysicsManager.ActiveControllers.add(ID);
|
||||
Actor actor = Actor.Actors.get(ParentID);
|
||||
Vector3f WorldPos = new Vector3f(actor.GetPosition()).div(ChunkWidth);
|
||||
WorldPos.x = (int)Math.floor(WorldPos.x);
|
||||
WorldPos.y = (int)Math.floor(WorldPos.y);
|
||||
WorldPos.z = (int)Math.floor(WorldPos.z);
|
||||
CurrentChunkPosition = WorldPos.x + ":" + WorldPos.y + ":" + WorldPos.z;
|
||||
DragCoefficients = CalculateDragCoefficients(TerminalVelocitiesMS, MassKG,CrossSectionAreas, actor.GetScale());
|
||||
}
|
||||
|
||||
public LegacyPhysicsController AddCollisionSensor(Vector3f RelativeOffset){
|
||||
collisionSensors.add(new CollisionSensor(RelativeOffset, ParentID));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String ID() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String ActorID() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String MeshID() {
|
||||
return "";
|
||||
}
|
||||
|
||||
//aaaaand i give up on this system, time to attempt something completely different
|
||||
public void PhysicsTick(float DeltaTime, float TargetFrameRate){
|
||||
Actor actor = Actor.Actors.get(ParentID);
|
||||
if (actor == null) return;
|
||||
|
||||
Position.set(actor.GetPosition());
|
||||
NextPosition.set(Position);
|
||||
|
||||
localVelocityStep.set(Velocities).mul(DeltaTime);
|
||||
NextPosition.add(localVelocityStep);
|
||||
|
||||
boolean ValidMovement = true;
|
||||
Drag = CalculateDrag(TerminalVelocitiesMS, DragCoefficients,CrossSectionAreas, actor.GetScale());
|
||||
FallingAcceleration = CalculateFallSpeed(MassKG, Drag, actor.GetScale());
|
||||
|
||||
Velocities.y -= (FallingAcceleration / (TargetFrameRate * 2f)) * DeltaTime;
|
||||
|
||||
float dragFactor = 1f - (WorldPhysicsManager.Drag * DeltaTime);
|
||||
Velocities.set(Velocities.x * dragFactor, Velocities.y, Velocities.z * dragFactor);
|
||||
|
||||
List<CollisionMesh> CollisionMeshesToCycleThrough = CollisionManager.GetAllCollisionMeshes();
|
||||
if (MeshCollision == CollisionType.Sensor && collisionSensors != null && !collisionSensors.isEmpty()) {
|
||||
ValidMovement = CalculateSensorCollision(CollisionMeshesToCycleThrough, actor);
|
||||
} else if (MeshCollision == CollisionType.PolyToPoly) {
|
||||
ValidMovement = CalculateMeshCollision(CollisionMeshesToCycleThrough, actor);
|
||||
}
|
||||
|
||||
actor.SetPosition(NextPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> Collisions() {
|
||||
return Collisions;
|
||||
}
|
||||
|
||||
public boolean CalculateMeshCollision(List<CollisionMesh> CollisionMeshesToCycleThrough, Actor actor){
|
||||
float skinThickness = 0.001f;
|
||||
CollisionMesh thisCollisionMesh = actor.GetCollisionMesh();
|
||||
// Logger.debug("POLY TO POLY");
|
||||
if (thisCollisionMesh == null) return false;
|
||||
|
||||
CollisionPoly[] thisPolygons = thisCollisionMesh.GetAllPolygons();
|
||||
boolean hasCollidedThisFrame = false;
|
||||
for (int i = 0; i < CollisionMeshesToCycleThrough.size(); i++) {
|
||||
CollisionMesh collisionMesh = CollisionMeshesToCycleThrough.get(i);
|
||||
|
||||
if (collisionMesh != null &&
|
||||
!Objects.equals(collisionMesh.ID, thisCollisionMesh.ID) && !Collisions.contains(collisionMesh.ID) &&
|
||||
collisionMesh.CheckAABBCollisionAgainstAABB(thisCollisionMesh.GetVoxelCollider())) {
|
||||
CollisionPoly[] polygons = collisionMesh.GetAllPolygons();
|
||||
|
||||
for (int k = 0; k < thisPolygons.length; k++) {
|
||||
for (int j = 0; j < polygons.length; j++) {
|
||||
|
||||
CollisionResult result = T4Math.ComplexCollision.ComputePolyToPolyIntersection(thisPolygons[k], polygons[j]);
|
||||
|
||||
if (result != null && result.Intersects) {
|
||||
hasCollidedThisFrame = true;
|
||||
Collisions.add(collisionMesh.ID);
|
||||
|
||||
float totalPushDistance = result.CollisionDepth + skinThickness;
|
||||
displacement.set(result.CollisionNormal).mul(totalPushDistance);
|
||||
if(result.CollisionDepth < 0.01f) {
|
||||
NextPosition.set(Position).add(0,displacement.y,0);
|
||||
}
|
||||
float velocityAlongNormal = Velocities.dot(result.CollisionNormal);
|
||||
// if (velocityAlongNormal < 0) {
|
||||
// slidingCorrection.set(result.CollisionNormal).mul(velocityAlongNormal);
|
||||
// Velocities.sub(slidingCorrection);
|
||||
// Velocities.mul(0.98f); // Apply wall friction sliding damping
|
||||
// }
|
||||
Velocities.mul(result.CollisionNormal).mul(Bounciness);
|
||||
// thisCollisionMesh.updatePositionContext(NextPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return !hasCollidedThisFrame;
|
||||
|
||||
|
||||
/*float skinThickness = 0.001f;
|
||||
float totalPushDistance = 0;
|
||||
Vector3f displacement = new Vector3f();
|
||||
Vector3f slidingCorrection = new Vector3f();
|
||||
CollisionMesh thisCollisionMesh = actor.GetCollisionMesh();
|
||||
boolean ValidMovement = true;
|
||||
if(thisCollisionMesh == null) return false;
|
||||
CollisionPoly[] thisPolygons = thisCollisionMesh.GetAllPolygons();
|
||||
for (int i = 0; i < CollisionMeshesToCycleThrough.size(); i++) {
|
||||
CollisionMesh collisionMesh = CollisionMeshesToCycleThrough.get(i);
|
||||
if (collisionMesh != null && !Objects.equals(collisionMesh.ID, thisCollisionMesh.ID) && collisionMesh.CheckAABBCollisionAgainstAABB(thisCollisionMesh.GetVoxelCollider())) {
|
||||
CollisionPoly[] polygons = collisionMesh.GetAllPolygons();
|
||||
for(int k = 0; k < thisPolygons.length; k++) {
|
||||
for (int j = 0; j < polygons.length; j++) {
|
||||
CollisionResult result = T4Math.ComplexCollision.ComputePolyToPolyIntersection(thisPolygons[k], polygons[j]);
|
||||
if(result != null && result.Intersects){
|
||||
totalPushDistance = result.CollisionDepth + skinThickness;
|
||||
displacement.set(result.CollisionNormal).mul(totalPushDistance);
|
||||
float velocityAlongNormal = Velocities.dot(result.CollisionNormal);
|
||||
if(velocityAlongNormal < 0){
|
||||
slidingCorrection.set(result.CollisionNormal).mul(velocityAlongNormal);
|
||||
Velocities.sub(slidingCorrection);
|
||||
Velocities.mul(0.98f);
|
||||
}
|
||||
//Velocities.y = -Velocities.y * Bounciness;//Velocities.mul(result.CollisionNormal).mul(Bounciness);
|
||||
Logger.debug(displacement + "<- DISPLACEMENT " + NextPosition + "<- NEXTPOS " + Position + "<- POS");
|
||||
NextPosition.add(displacement);
|
||||
ValidMovement = false;
|
||||
}
|
||||
if (!ValidMovement) break;
|
||||
}
|
||||
if (!ValidMovement) break;
|
||||
}
|
||||
}
|
||||
if (!ValidMovement) break;
|
||||
}
|
||||
return ValidMovement;*/
|
||||
}
|
||||
|
||||
public void CollisionEvent(CollisionMesh collidingMesh, Vector3f PositionDifference, Vector2f CollisionScale){
|
||||
Collisions.add(collidingMesh.ID);
|
||||
if (Math.abs(PositionDifference.x) > 0.01f && Math.abs(PositionDifference.z) > 0.01f) {
|
||||
NextPosition.add(PositionDifference);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean CalculateSensorCollision(List<CollisionMesh> CollisionMeshesToCycleThrough, Actor actor){
|
||||
boolean hasCollidedThisFrame = false;
|
||||
|
||||
Actor parentActor = Actor.Actors.get(ParentID);
|
||||
if (parentActor != null) {
|
||||
pivotOffsetCache.set(parentActor.GetPivotOffset()).add(parentActor.GetAditionalPivotOffset());
|
||||
} else {
|
||||
pivotOffsetCache.set(0, 0, 0);
|
||||
}
|
||||
|
||||
while (transformedSensorsCache.size() < collisionSensors.size()) {
|
||||
transformedSensorsCache.add(new Vector3f());
|
||||
}
|
||||
for (int j = 0; j < collisionSensors.size(); j++) {
|
||||
transformedSensorsCache.get(j).set(collisionSensors.get(j).GetTransformedCollisionSensor());
|
||||
}
|
||||
Vector2f CollisionScale = new Vector2f();
|
||||
for (int i = 0; i < CollisionMeshesToCycleThrough.size(); i++) {
|
||||
CollisionMesh collisionMesh = CollisionMeshesToCycleThrough.get(i);
|
||||
|
||||
if (collisionMesh != null &&
|
||||
!Objects.equals(collisionMesh.ID, actor.GetCollisionMesh().ID) && !Collisions.contains(collisionMesh.ID)&&
|
||||
collisionMesh.CheckAABBCollisionAgainstAABB(actor.GetCollisionMesh().GetVoxelCollider())) {
|
||||
|
||||
CollisionPoly[] polygons = collisionMesh.GetAllPolygons();
|
||||
|
||||
for (int j = 0; j < polygons.length; j++) {
|
||||
CollisionPoly poly = polygons[j];
|
||||
if (poly == null) continue;
|
||||
|
||||
for (int k = 0; k < collisionSensors.size(); k++) {
|
||||
|
||||
Vector3f CollisionPoint = T4Math.Math3D.LineCollisionPointWithPoly(
|
||||
NextPosition, transformedSensorsCache.get(k), poly.GetVertices(),CollisionScale);
|
||||
|
||||
if (CollisionPoint != null) {
|
||||
hasCollidedThisFrame = true;
|
||||
|
||||
sensorSubtraction.set(NextPosition).sub(CollisionPoint);
|
||||
if (Math.abs(sensorSubtraction.x) > 0.01f && Math.abs(sensorSubtraction.z) > 0.01f) {
|
||||
NextPosition.sub(sensorSubtraction);
|
||||
} else {
|
||||
NextPosition.sub(0, sensorSubtraction.y, 0);
|
||||
}
|
||||
Collisions.add(collisionMesh.ID);
|
||||
if(collisionMesh.ParentID != "NULL" && Actor.Actors.get(collisionMesh.ParentID) != null){
|
||||
Actor.Actors.get(collisionMesh.ParentID).GetPhysicsController().CollisionEvent(Actor.Actors.get(ParentID).GetCollisionMesh(),sensorSubtraction,CollisionScale);
|
||||
}
|
||||
Velocities.y = -Velocities.y * Bounciness;
|
||||
if (Math.abs(Velocities.y) < 0.05f) {
|
||||
Velocities.y = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return !hasCollidedThisFrame;
|
||||
|
||||
/*boolean ValidMovement = true;
|
||||
Vector3f PivotOffset = Actor.Actors.get(ParentID) != null ? new Vector3f(Actor.Actors.get(ParentID).GetPivotOffset()).add(Actor.Actors.get(ParentID).GetAditionalPivotOffset()) : new Vector3f(0, 0, 0);
|
||||
List<Vector3f> CollidingSensors = new ArrayList<>();
|
||||
for (int j = 0; j < collisionSensors.size(); j++) {
|
||||
CollidingSensors.add(new Vector3f().set(collisionSensors.get(j).GetTransformedCollisionSensor()));
|
||||
}
|
||||
Vector3f Subtraction = new Vector3f();
|
||||
if (!CollidingSensors.isEmpty()) {
|
||||
for (int i = 0; i < CollisionMeshesToCycleThrough.size(); i++) {
|
||||
CollisionMesh collisionMesh = CollisionMeshesToCycleThrough.get(i);
|
||||
if (collisionMesh != null && !Objects.equals(collisionMesh.ID, actor.GetCollisionMesh().ID) && collisionMesh.CheckAABBCollisionAgainstAABB(actor.GetCollisionMesh().GetVoxelCollider())) {
|
||||
CollisionPoly[] polygons = collisionMesh.GetAllPolygons();
|
||||
for (int j = 0; j < polygons.length; j++) {
|
||||
CollisionPoly poly = polygons[j];
|
||||
if (poly != null) {
|
||||
for (int k = 0; k < CollidingSensors.size(); k++) {
|
||||
Vector3f CollisionPoint = T4Math.Math3D.LineCollisionPointWithPoly(NextPosition, CollidingSensors.get(k), new Vector3f[]{poly.v1(), poly.v2(), poly.v3()});
|
||||
if (CollisionPoint != null) {
|
||||
Subtraction.set(NextPosition).sub(CollisionPoint);
|
||||
if (Math.abs(Subtraction.x) > 0.1f && Math.abs(Subtraction.z) > 0.1f) {
|
||||
NextPosition.sub(Subtraction);
|
||||
} else {
|
||||
NextPosition.sub(0, Subtraction.y, 0);
|
||||
}
|
||||
Velocities.y = -Velocities.y * Bounciness;
|
||||
if (Math.abs(Velocities.y) < 0.05f) Velocities.y = 0;
|
||||
ValidMovement = false;
|
||||
}
|
||||
if (!ValidMovement) break;
|
||||
}
|
||||
}
|
||||
if (!ValidMovement) break;
|
||||
}
|
||||
}
|
||||
if (!ValidMovement) break;
|
||||
}
|
||||
}
|
||||
return ValidMovement;*/
|
||||
}
|
||||
}
|
||||
|
|
@ -1,132 +0,0 @@
|
|||
package net.halbear.Terrain4J.EngineCore.Logic.Physics;
|
||||
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Collision.CollisionManager;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Collision.CollisionMesh;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Collision.CollisionPoly;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.Scene.Actor;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.Util.Maths.T4Math;
|
||||
import org.joml.Vector3f;
|
||||
import org.tinylog.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static net.halbear.Terrain4J.EngineCore.Logic.Collision.CollisionManager.ChunkWidth;
|
||||
|
||||
public class PhysicsController {
|
||||
|
||||
public List<CollisionSensor> collisionSensors;
|
||||
public Vector3f Velocities = new Vector3f(0,0,0);
|
||||
public Vector3f WeightBalance = new Vector3f(0,0,0);
|
||||
public float MassKG = 10.0f;
|
||||
public Vector3f TerminalVelocitiesMS = new Vector3f(36f,6.6f,36f);
|
||||
public Vector3f Drag = new Vector3f(0.2f,0.2f,0.2f);
|
||||
public Vector3f DragCoefficients = new Vector3f(0.1f,0.1f,0.1f);
|
||||
public Vector3f CrossSectionAreas = new Vector3f(1.8f * 0.9f, 0.6f * 0.9f, 1.8f * 0.6f);
|
||||
public Vector3f WeightDistribution = new Vector3f(2.0f,5.0f,7.0f);
|
||||
public float FallingAcceleration = 0.0f;
|
||||
public float Bounciness = 0.3f;
|
||||
String CurrentChunkPosition = "NULL";
|
||||
|
||||
public void CalculateDragCoefficients(){
|
||||
Vector3f dragCoefficients = WorldPhysicsManager.CalculateDragFromTerminalVelocities(TerminalVelocitiesMS,MassKG,CrossSectionAreas);
|
||||
this.DragCoefficients = new Vector3f(dragCoefficients);
|
||||
}
|
||||
public void CalculateDrag(){
|
||||
Vector3f drag = WorldPhysicsManager.CalculateRealDrag(Velocities,DragCoefficients,CrossSectionAreas);
|
||||
this.Drag = new Vector3f(drag);
|
||||
}
|
||||
public void CalculateFallSpeed(){
|
||||
FallingAcceleration = WorldPhysicsManager.CalculateGravityForce(MassKG, Drag);
|
||||
}
|
||||
|
||||
public final String ID;
|
||||
public final String ParentID;
|
||||
|
||||
public PhysicsController(String ActorID){
|
||||
collisionSensors = new ArrayList<>();
|
||||
ID = ActorID + "_PHYSICS_CONTROLLER";
|
||||
ParentID = ActorID;
|
||||
WorldPhysicsManager.PhysicsObjects.put(ID, this);
|
||||
WorldPhysicsManager.ActiveControllers.add(ID);
|
||||
Actor actor = Actor.Actors.get(ParentID);
|
||||
Vector3f WorldPos = new Vector3f(actor.GetPosition()).div(ChunkWidth);
|
||||
WorldPos.x = (int)Math.floor(WorldPos.x);
|
||||
WorldPos.y = (int)Math.floor(WorldPos.y);
|
||||
WorldPos.z = (int)Math.floor(WorldPos.z);
|
||||
CurrentChunkPosition = WorldPos.x + ":" + WorldPos.y + ":" + WorldPos.z;
|
||||
CalculateDragCoefficients();
|
||||
}
|
||||
|
||||
public PhysicsController AddCollisionSensor(Vector3f RelativeOffset){
|
||||
collisionSensors.add(new CollisionSensor(RelativeOffset, ParentID));
|
||||
return this;
|
||||
}
|
||||
|
||||
public void PhysicsTick(float DeltaTime, float TargetFrameRate){
|
||||
Actor actor = Actor.Actors.get(ParentID);
|
||||
Vector3f Position = new Vector3f(actor.GetPosition());
|
||||
Vector3f NextPosition = new Vector3f(Position);
|
||||
Vector3f Velocity = new Vector3f(Velocities);
|
||||
Velocity = Velocity.mul(DeltaTime);
|
||||
NextPosition.add(Velocity);
|
||||
boolean ValidMovement = true;
|
||||
CalculateDrag();
|
||||
CalculateFallSpeed();
|
||||
Velocities.y -= (FallingAcceleration/(TargetFrameRate*2)) * DeltaTime;
|
||||
Velocities = Velocities.mul((1f - (WorldPhysicsManager.Drag * (DeltaTime))),1f,(1f - (WorldPhysicsManager.Drag * (DeltaTime))));
|
||||
if(collisionSensors != null && !collisionSensors.isEmpty()) {
|
||||
// Vector3f WorldPos = new Vector3f(NextPosition).div(ChunkWidth);
|
||||
// WorldPos.x = (int) Math.floor(WorldPos.x);
|
||||
// WorldPos.y = (int) Math.floor(WorldPos.y);
|
||||
// WorldPos.z = (int) Math.floor(WorldPos.z);
|
||||
// String NextChunkPosition = WorldPos.x + ":" + WorldPos.y + ":" + WorldPos.z;
|
||||
// List<String> CollisionMeshesToCycleThrough = new ArrayList<>(CollisionManager.AlwaysCheckMeshes);
|
||||
// CollisionMeshesToCycleThrough.addAll(CollisionManager.GetCollisionMeshesAtChunk(NextChunkPosition));
|
||||
// if (!NextChunkPosition.equals(CurrentChunkPosition)) {
|
||||
// CollisionMeshesToCycleThrough.addAll(CollisionManager.GetCollisionMeshesAtChunk(CurrentChunkPosition));
|
||||
// CurrentChunkPosition = NextChunkPosition;
|
||||
// }
|
||||
// Logger.debug(CollisionMeshesToCycleThrough.size());
|
||||
List<CollisionMesh> CollisionMeshesToCycleThrough = CollisionManager.GetAllCollisionMeshes();
|
||||
//Logger.debug("Collision Mesh Count [{}]",CollisionMeshesToCycleThrough.size());
|
||||
Vector3f PivotOffset = Actor.Actors.get(ParentID) != null ? new Vector3f(Actor.Actors.get(ParentID).GetPivotOffset()).add(Actor.Actors.get(ParentID).GetAditionalPivotOffset()) : new Vector3f(0,0,0);
|
||||
List<CollisionSensor> CollidingSensors = new ArrayList<>();
|
||||
for (int j = 0; j < collisionSensors.size(); j++) {
|
||||
CollidingSensors.add(collisionSensors.get(j).TransformScale(actor.GetScale()).TransformPosition(PivotOffset).TransformRotation(actor.GetRotation()).TransformPosition(PivotOffset.negate()).TransformPosition(NextPosition));
|
||||
}
|
||||
if(CollidingSensors.size() > 0){
|
||||
for(int i = 0; i < CollisionMeshesToCycleThrough.size(); i++){
|
||||
CollisionMesh collisionMesh = CollisionMeshesToCycleThrough.get(i);
|
||||
if(collisionMesh != null && !Objects.equals(collisionMesh.ID, actor.GetCollisionMesh().ID) && collisionMesh.CheckAABBCollisionAgainstAABB(collisionMesh.GetVoxelCollider())) {
|
||||
CollisionPoly[] polygons = collisionMesh.GetAllPolygons();
|
||||
for(int j = 0; j < polygons.length; j++){
|
||||
CollisionPoly poly = polygons[j];
|
||||
if(poly != null) {
|
||||
for (int k = 0; k < CollidingSensors.size(); k++) {
|
||||
Vector3f CollisionPoint = T4Math.Math3D.LineCollisionPointWithPoly(NextPosition, CollidingSensors.get(k).Offset(), new Vector3f[]{poly.v1(), poly.v2(), poly.v3()});
|
||||
if (CollisionPoint != null) {
|
||||
Vector3f subtraction = new Vector3f(NextPosition).sub(CollisionPoint);
|
||||
if(Math.abs(subtraction.x) > 0.1f && Math.abs(subtraction.z) > 0.1f) {
|
||||
NextPosition.sub(new Vector3f(NextPosition).sub(CollisionPoint));
|
||||
} else {
|
||||
NextPosition.sub(0,new Vector3f(NextPosition).sub(CollisionPoint).y,0);
|
||||
}
|
||||
Velocities.y = -Velocities.y * Bounciness;
|
||||
if(Math.abs(Velocities.y) < 0.05f) Velocities.y = 0;
|
||||
ValidMovement = false;
|
||||
}
|
||||
if(!ValidMovement)break;
|
||||
}
|
||||
}
|
||||
if(!ValidMovement)break;
|
||||
}
|
||||
}
|
||||
if(!ValidMovement)break;
|
||||
}
|
||||
}
|
||||
}
|
||||
actor.SetPosition(NextPosition);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
package net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody;
|
||||
|
||||
import org.joml.Quaternionf;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class ConvexMesh {
|
||||
public static class Face{
|
||||
public final int[] Indices;
|
||||
public final Vector3f LocalNormal;
|
||||
public Face(int[] Indices, Vector3f localNormal){
|
||||
this.Indices = Indices;
|
||||
this.LocalNormal = localNormal;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3f BottomLeftBack = new Vector3f(Float.MAX_VALUE,Float.MAX_VALUE,Float.MAX_VALUE);
|
||||
public Vector3f TopRightForward = new Vector3f(Float.MIN_VALUE,Float.MIN_VALUE,Float.MIN_VALUE);
|
||||
|
||||
public final List<Vector3f> LocalVertices = new ArrayList<>();
|
||||
public final List<Face> Faces = new ArrayList<>();
|
||||
public final List<int[]> Edges = new ArrayList<>();
|
||||
|
||||
public final Vector3f Position = new Vector3f();
|
||||
public final Quaternionf Orientation = new Quaternionf();
|
||||
|
||||
public Vector3f WorldVertex(int i) {
|
||||
Vector3f vertex = new Vector3f(LocalVertices.get(i));
|
||||
Orientation.transform(vertex);
|
||||
vertex.add(Position);
|
||||
return vertex;
|
||||
}
|
||||
|
||||
public Vector3f WorldFaceNormal(Face f) {
|
||||
Vector3f normal = new Vector3f(f.LocalNormal);
|
||||
Orientation.transform(normal);
|
||||
return normal.normalize();
|
||||
}
|
||||
|
||||
public List<Vector3f> WorldVertices() {
|
||||
List<Vector3f> out = new ArrayList<>(LocalVertices.size());
|
||||
for (int i = 0; i < LocalVertices.size(); i++) out.add(WorldVertex(i));
|
||||
return out;
|
||||
}
|
||||
|
||||
public Vector3f Support(Vector3f Direction) {
|
||||
float best = -Float.MAX_VALUE;
|
||||
Vector3f bestV = null;
|
||||
for (int i = 0; i < LocalVertices.size(); i++) {
|
||||
Vector3f w = WorldVertex(i);
|
||||
float d = w.dot(Direction);
|
||||
if (d > best) { best = d; bestV = w; }
|
||||
}
|
||||
return bestV;
|
||||
}
|
||||
|
||||
public void CheckAABbounds(Vector3f v1){
|
||||
TopRightForward.x = Math.max(TopRightForward.x, v1.x);
|
||||
TopRightForward.y = Math.max(TopRightForward.y, v1.y);
|
||||
TopRightForward.z = Math.max(TopRightForward.z, v1.z);
|
||||
BottomLeftBack.x = Math.min(BottomLeftBack.x, v1.x);
|
||||
BottomLeftBack.y = Math.min(BottomLeftBack.y, v1.y);
|
||||
BottomLeftBack.z = Math.min(BottomLeftBack.z, v1.z);
|
||||
}
|
||||
|
||||
//Creates a basic AABB, that said, its not really axis aligned so idk why im referring to is as one
|
||||
public static ConvexMesh Box(float hx, float hy, float hz) {
|
||||
ConvexMesh mesh = new ConvexMesh();
|
||||
mesh.LocalVertices.add(new Vector3f(-hx, -hy, -hz)); // 0
|
||||
mesh.LocalVertices.add(new Vector3f( hx, -hy, -hz)); // 1
|
||||
mesh.LocalVertices.add(new Vector3f( hx, hy, -hz)); // 2
|
||||
mesh.LocalVertices.add(new Vector3f(-hx, hy, -hz)); // 3
|
||||
mesh.LocalVertices.add(new Vector3f(-hx, -hy, hz)); // 4
|
||||
mesh.LocalVertices.add(new Vector3f( hx, -hy, hz)); // 5
|
||||
mesh.LocalVertices.add(new Vector3f( hx, hy, hz)); // 6
|
||||
mesh.LocalVertices.add(new Vector3f(-hx, hy, hz)); // 7
|
||||
|
||||
for(int i = 0; i < mesh.LocalVertices.size(); i++){
|
||||
mesh.CheckAABbounds(mesh.LocalVertices.get(i));
|
||||
}
|
||||
|
||||
mesh.Faces.add(new Face(new int[]{0, 3, 2, 1}, new Vector3f(0, 0, -1))); // -Z
|
||||
mesh.Faces.add(new Face(new int[]{4, 5, 6, 7}, new Vector3f(0, 0, 1))); // +Z
|
||||
mesh.Faces.add(new Face(new int[]{0, 1, 5, 4}, new Vector3f(0, -1, 0))); // -Y
|
||||
mesh.Faces.add(new Face(new int[]{3, 7, 6, 2}, new Vector3f(0, 1, 0))); // +Y
|
||||
mesh.Faces.add(new Face(new int[]{0, 4, 7, 3}, new Vector3f(-1, 0, 0))); // -X
|
||||
mesh.Faces.add(new Face(new int[]{1, 2, 6, 5}, new Vector3f( 1, 0, 0))); // +X
|
||||
|
||||
int[][] e = {{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},{6,7},{7,4},{0,4},{1,5},{2,6},{3,7}};
|
||||
mesh.Edges.addAll(Arrays.asList(e));
|
||||
return mesh;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
package net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody;
|
||||
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Physics.IPhysicsController;
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Quaternionf;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class RigidBody {
|
||||
|
||||
public static final Map<String, RigidBody> RigidBodyRegister = new HashMap<>();
|
||||
public static final List<String> RigidBodies = new ArrayList<>();
|
||||
|
||||
|
||||
public final ConvexMesh shape;
|
||||
|
||||
public final Vector3f Position;
|
||||
public final Quaternionf Rotation;
|
||||
public Vector3f WeightBalance = new Vector3f(0,0,0);
|
||||
public float MassKG = 10.0f;
|
||||
public float InverseMassKG = -10.0f;
|
||||
public Vector3f TerminalVelocitiesMS = new Vector3f(36f,6.6f,36f);
|
||||
public Vector3f Drag = new Vector3f(0.2f,0.2f,0.2f);
|
||||
public Vector3f DragCoefficients = new Vector3f(0.1f,0.1f,0.1f);
|
||||
public Vector3f CrossSectionAreas = new Vector3f(1.8f * 0.9f, 0.6f * 0.9f, 1.8f * 0.6f);
|
||||
public Vector3f WeightDistribution = new Vector3f(2.0f,5.0f,7.0f);
|
||||
public float FallingAcceleration = 0.0f;
|
||||
public float Bounciness = 0.3f;
|
||||
|
||||
public final Vector3f LinearVelocity = new Vector3f();
|
||||
public final Vector3f AngularVelocity = new Vector3f();
|
||||
|
||||
public final Matrix3f InverseInertiaLocal = new Matrix3f();
|
||||
public final Matrix3f InverseInertiaWorld = new Matrix3f();
|
||||
|
||||
public float Restitution = 0.3f; // 0 = fully inelastic, 1 = perfectly elastic
|
||||
public float Friction = 0.5f;
|
||||
public boolean IsStatic = false;
|
||||
|
||||
public String PhysicsControllerID = "NULL";
|
||||
public final String RigidBodyID;
|
||||
|
||||
public RigidBody(String RigidBodyID, ConvexMesh Shape, float MassKG){
|
||||
this.RigidBodyID = RigidBodyID;
|
||||
RigidBodyRegister.put(RigidBodyID,this);
|
||||
RigidBodies.add(RigidBodyID);
|
||||
this.shape = Shape;
|
||||
this.Position = shape.Position;
|
||||
this.Rotation = shape.Orientation;
|
||||
SetMass(MassKG);
|
||||
}
|
||||
|
||||
public void SetMass(float mass) {
|
||||
this.MassKG = mass;
|
||||
if (mass <= 0f) {
|
||||
InverseMassKG = 0f;
|
||||
InverseInertiaLocal.zero();
|
||||
IsStatic = true;
|
||||
} else {
|
||||
InverseMassKG = 1.0f / mass;
|
||||
IsStatic = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetRigidBoxInertia(float x, float y, float z){
|
||||
if(IsStatic) return;
|
||||
float width = 2 * x, height = 2 * y, depth = 2 * z;
|
||||
float ix = (MassKG/12.0f) * (height * height + depth * depth);
|
||||
float iy = (MassKG/12.0f) * (width * width + depth * depth);
|
||||
float iz = (MassKG/12.0f) * (width * width + height * height);
|
||||
InverseInertiaLocal.identity();
|
||||
InverseInertiaLocal.m00(1.0f/ix);
|
||||
InverseInertiaLocal.m11(1.0f/iy);
|
||||
InverseInertiaLocal.m22(1.0f/iz);
|
||||
UpdateInertiaWorld();
|
||||
}
|
||||
|
||||
public void UpdateInertiaWorld(){
|
||||
if(IsStatic) {
|
||||
InverseInertiaWorld.zero();
|
||||
return;
|
||||
}
|
||||
Matrix3f rotation = new Matrix3f();
|
||||
Rotation.get(rotation);
|
||||
Matrix3f rotationT = new Matrix3f(rotation).transpose();
|
||||
InverseInertiaWorld.set(rotation).mul(InverseInertiaLocal).mul(rotationT);
|
||||
}
|
||||
|
||||
private final Vector3f r = new Vector3f();
|
||||
public Vector3f VecolityAtPoint(Vector3f worldPoint){
|
||||
r.set(worldPoint).sub(Position);
|
||||
Vector3f AngularPart = new Vector3f(AngularVelocity).cross(r);
|
||||
return new Vector3f(LinearVelocity).add(AngularPart);
|
||||
}
|
||||
|
||||
private final Vector3f ImpulseVelocity = new Vector3f();
|
||||
public void ApplyImpulse(Vector3f impulse, Vector3f WorldPoint){
|
||||
if(IsStatic) return;
|
||||
LinearVelocity.add(ImpulseVelocity.set(impulse).mul(InverseMassKG));
|
||||
|
||||
r.set(WorldPoint).sub(Position);
|
||||
Vector3f AngleImpulse = new Vector3f(r).cross(impulse);
|
||||
Vector3f DeltaAngular = new Vector3f();
|
||||
InverseInertiaWorld.transform(AngleImpulse,DeltaAngular);
|
||||
AngularVelocity.add(DeltaAngular);
|
||||
}
|
||||
|
||||
private final Vector3f GravityToAdd = new Vector3f();
|
||||
private final Vector3f VelocityToAdd = new Vector3f();
|
||||
public void Integrate(float DeltaTime, Vector3f Gravity){
|
||||
if(IsStatic) return;
|
||||
LinearVelocity.add(GravityToAdd.set(Gravity).mul(DeltaTime));
|
||||
Position.add(VelocityToAdd.set(LinearVelocity).mul(DeltaTime));
|
||||
|
||||
Quaternionf Spin = new Quaternionf(
|
||||
AngularVelocity.x * DeltaTime * 0.5f,
|
||||
AngularVelocity.y * DeltaTime * 0.5f,
|
||||
AngularVelocity.z * DeltaTime * 0.5f,
|
||||
0
|
||||
);
|
||||
|
||||
Quaternionf DeltaRotation = Spin.mul(Rotation);
|
||||
Rotation.set(Rotation.x + DeltaRotation.x,
|
||||
Rotation.y + DeltaRotation.y,
|
||||
Rotation.z + DeltaRotation.z,
|
||||
Rotation.w + DeltaRotation.w
|
||||
).normalize();
|
||||
|
||||
UpdateInertiaWorld();
|
||||
}
|
||||
|
||||
public RigidBody AttachPhysicsController(String PhysicsControllerID){
|
||||
this.PhysicsControllerID = PhysicsControllerID;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String GetID(){return RigidBodyID;}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
package net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody;
|
||||
|
||||
import net.halbear.Terrain4J.EngineCore.Main.Util.Maths.T4Math;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
//Resolves the Separating Axis Theorem Test into reaction forces in impulses and position correction
|
||||
public class RigidCollision {
|
||||
private static final float CORRECTION_THRESHOLD = 1.0f; //how much it gets corrected positionally per physics step
|
||||
private static final float SLOP = 0.001f; // amount of overlap can happen before collision gets corrected
|
||||
|
||||
public synchronized static void ResolveCollision(RigidBody body1, RigidBody body2, SeparatingAxisTheoremTester.CollisionResult collisionResult){
|
||||
Vector3f Normal = collisionResult.Normal;
|
||||
for(SeparatingAxisTheoremTester.Contact contact : collisionResult.Contacts){
|
||||
ResolveContact(body1, body2, Normal, contact);
|
||||
}
|
||||
|
||||
CorrectPositioning(body1,body2,Normal,collisionResult.Penetration);
|
||||
}
|
||||
|
||||
private static final Vector3f Dist1 = new Vector3f();
|
||||
private static final Vector3f Dist2 = new Vector3f();
|
||||
private static final Vector3f Impulse = new Vector3f();
|
||||
private static final Vector3f NegatedImpulse = new Vector3f();
|
||||
private static final Vector3f RelativeVelocity = new Vector3f();
|
||||
private synchronized static void ResolveContact(RigidBody body1, RigidBody body2, Vector3f normal, SeparatingAxisTheoremTester.Contact contact){
|
||||
Vector3f Point = contact.Point;
|
||||
|
||||
Dist1.set(Point).sub(body1.Position);
|
||||
Dist2.set(Point).sub(body2.Position);
|
||||
|
||||
Vector3f Velocity1 = body1.VecolityAtPoint(Point);
|
||||
Vector3f Velocity2 = body2.VecolityAtPoint(Point);
|
||||
RelativeVelocity.set(Velocity2).sub(Velocity1);
|
||||
|
||||
float VelocityAlongNormal = RelativeVelocity.dot(normal);
|
||||
if(VelocityAlongNormal > 0) return;
|
||||
|
||||
float Restitution = Math.min(body1.Restitution, body2.Restitution);
|
||||
|
||||
float InverseMassSum = body1.InverseMassKG + body2.InverseMassKG + AngularTerm(body1, Dist1, normal) + AngularTerm(body2,Dist2,normal);
|
||||
if(InverseMassSum <= T4Math.Math3D.epsilon) return;
|
||||
|
||||
float j = -(1 + Restitution) * VelocityAlongNormal / InverseMassSum;
|
||||
Impulse.set(normal).mul(j);
|
||||
|
||||
body1.ApplyImpulse(NegatedImpulse.set(Impulse).negate(), Point);
|
||||
|
||||
body2.ApplyImpulse(Impulse,Point);
|
||||
|
||||
ApplyFriction(body1, body2, normal, Point, Dist1, Dist2, j);
|
||||
}
|
||||
|
||||
private static final Vector3f DistanceCrossAxis = new Vector3f();
|
||||
private static final Vector3f Angular = new Vector3f();
|
||||
private static synchronized float AngularTerm(RigidBody body, Vector3f distance, Vector3f axis){
|
||||
DistanceCrossAxis.set(distance).cross(axis);
|
||||
Angular.zero();
|
||||
body.InverseInertiaWorld.transform(DistanceCrossAxis,Angular);
|
||||
return Angular.cross(distance).dot(axis);
|
||||
}
|
||||
|
||||
private static final Vector3f relativeVelocity = new Vector3f();
|
||||
private static final Vector3f Tangent = new Vector3f();
|
||||
private static synchronized void ApplyFriction(RigidBody body1, RigidBody body2, Vector3f Normal, Vector3f Point, Vector3f Dist1, Vector3f Dist2, float NormalImpulseMagnitude){
|
||||
Vector3f Velocity1 = body1.VecolityAtPoint(Point);
|
||||
Vector3f Velocity2 = body2.VecolityAtPoint(Point);
|
||||
relativeVelocity.set(Velocity2).sub(Velocity1);
|
||||
|
||||
Tangent.set(relativeVelocity).sub(new Vector3f(Normal).mul(relativeVelocity.dot(Normal)));
|
||||
float TangentLengthSquared = Tangent.lengthSquared();
|
||||
if(TangentLengthSquared <= 1e-10f) return;
|
||||
Tangent.mul(1.0f/(float)Math.sqrt(TangentLengthSquared));
|
||||
|
||||
float InverseMassSumT = body1.InverseMassKG + body2.InverseMassKG + AngularTerm(body1, Dist1, Tangent) + AngularTerm(body2,Dist2,Tangent);
|
||||
if(InverseMassSumT <= T4Math.Math3D.epsilon) return;
|
||||
|
||||
float jt = -relativeVelocity.dot(Tangent) / InverseMassSumT;
|
||||
float mu = (body1.Friction + body2.Friction) * 0.5f;
|
||||
float MaxFriction = mu * Math.abs(NormalImpulseMagnitude);
|
||||
jt = Math.max(-MaxFriction, Math.min(MaxFriction,jt));
|
||||
|
||||
Vector3f FrictionResults = new Vector3f(Tangent).mul(jt);
|
||||
body1.ApplyImpulse(new Vector3f(FrictionResults).negate(),Point);
|
||||
body2.ApplyImpulse((FrictionResults),Point);
|
||||
}
|
||||
|
||||
private static final Vector3f Correction = new Vector3f();
|
||||
private static void CorrectPositioning(RigidBody body1, RigidBody body2, Vector3f Normal, float Penetration){
|
||||
float InverseMassSum = body1.InverseMassKG + body2.InverseMassKG;
|
||||
if(InverseMassSum <= T4Math.Math3D.epsilon) return;
|
||||
|
||||
float CorrectionMagnitude = Math.max(Penetration - SLOP, 0f) / InverseMassSum * CORRECTION_THRESHOLD;
|
||||
Correction.set(Normal).mul(CorrectionMagnitude);
|
||||
|
||||
if(!body1.IsStatic) body1.Position.sub(new Vector3f(Correction).mul(body1.InverseMassKG));
|
||||
if(!body2.IsStatic) body2.Position.add(new Vector3f(Correction).mul(body2.InverseMassKG));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
package net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody;
|
||||
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Physics.LegacyCollision.CollisionMesh;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Physics.IPhysicsController;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Physics.WorldPhysicsManager;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.Scene.Actor;
|
||||
import org.joml.Vector2f;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody.RigidBody.RigidBodies;
|
||||
import static net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody.RigidBody.RigidBodyRegister;
|
||||
import static net.halbear.Terrain4J.EngineCore.Main.Util.Maths.T4Math.Physics.CalculateDrag;
|
||||
import static net.halbear.Terrain4J.EngineCore.Main.Util.Maths.T4Math.Physics.CalculateFallSpeed;
|
||||
|
||||
public class RigidPhysicsController implements IPhysicsController {
|
||||
|
||||
public static final Map<String,IPhysicsController> RigidControllerRegister = new HashMap<>();
|
||||
public static final List<String> RigidControllers = new ArrayList<>();
|
||||
|
||||
public static IPhysicsController GetPhysicsController(String ID){
|
||||
return RigidControllerRegister.get(ID);
|
||||
}
|
||||
public final List<String> Collisions = new ArrayList<>();
|
||||
|
||||
public static RigidBody Ground = new RigidBody("FLOOR",ConvexMesh.Box(100,100f,100),0);
|
||||
|
||||
static {
|
||||
Ground.Position.set(0,-100f,0);
|
||||
}
|
||||
|
||||
public String RigidBodyID = "NULL";
|
||||
public String ActorID = "NULL";
|
||||
public String ControllerID = "NOTSET";
|
||||
public RigidPhysicsController(String ID, String ActorID){
|
||||
RigidControllerRegister.put(ID, this);
|
||||
RigidControllers.add(ID);
|
||||
ControllerID = ID;
|
||||
this.ActorID = ActorID;
|
||||
}
|
||||
|
||||
public RigidPhysicsController CreateRigidBody(ConvexMesh Shape, float MassKG){
|
||||
RigidBodyID = ActorID + "_RIGID_BODY";
|
||||
RigidBody newRigidBody = new RigidBody(RigidBodyID,Shape,MassKG);
|
||||
newRigidBody.SetRigidBoxInertia(0.5f,0.5f,0.5f);
|
||||
newRigidBody.Position.set(Actor.Actors.get(ActorID).GetPosition());
|
||||
newRigidBody.Rotation.set(Actor.Actors.get(ActorID).GetRotation());
|
||||
newRigidBody.UpdateInertiaWorld();
|
||||
WorldPhysicsManager.PhysicsObjects.put(ControllerID, this);
|
||||
WorldPhysicsManager.ActiveControllers.add(ControllerID);
|
||||
return this;
|
||||
}
|
||||
|
||||
public RigidPhysicsController SetRigidBody(RigidBody rigidBody){
|
||||
RigidBodyID = rigidBody.GetID();
|
||||
WorldPhysicsManager.PhysicsObjects.put(ControllerID, this);
|
||||
WorldPhysicsManager.ActiveControllers.add(ControllerID);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String ID() {
|
||||
return ControllerID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String ActorID() {
|
||||
return ActorID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String MeshID() {
|
||||
return RigidBodyID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void PhysicsTick(float DeltaTime, float TargetFrameRate) {
|
||||
DeltaTime/=10f;
|
||||
if(DeltaTime >0.1f) DeltaTime = 0.1f;
|
||||
if(RigidBodyID != null && RigidBodyRegister.get(RigidBodyID) != null && ActorID != "NULL") {
|
||||
RigidBody rigidBody = RigidBodyRegister.get(RigidBodyID);
|
||||
rigidBody.Integrate(DeltaTime, new Vector3f(0,-1.8f,0));
|
||||
for(int i = 0; i < RigidBodies.size(); i++) {
|
||||
RigidBody OtherRigidBody = RigidBodyRegister.get(RigidBodies.get(i));
|
||||
if(OtherRigidBody != null && OtherRigidBody.RigidBodyID != null && !Objects.equals(OtherRigidBody.RigidBodyID, RigidBodyID)) {
|
||||
SeparatingAxisTheoremTester.CollisionResult collisionResult = SeparatingAxisTheoremTester.TestCollision(OtherRigidBody.shape, rigidBody.shape);
|
||||
if (collisionResult != null) {
|
||||
RigidCollision.ResolveCollision(OtherRigidBody, rigidBody, collisionResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(Actor.Actors.get(ActorID) != null) {
|
||||
Actor.Actors.get(ActorID).SetPivotOffset(new Vector3f(0,(rigidBody.shape.TopRightForward.y - rigidBody.shape.BottomLeftBack.y)/2f,0));
|
||||
Actor.Actors.get(ActorID).SetPosition(new Vector3f(rigidBody.Position));
|
||||
Actor.Actors.get(ActorID).SetRotation(rigidBody.Rotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> Collisions() {
|
||||
return Collisions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void CollisionEvent(CollisionMesh collidingMesh, Vector3f PositionDifference, Vector2f CollisionScale) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,260 @@
|
|||
package net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody;
|
||||
|
||||
import net.halbear.Terrain4J.EngineCore.Main.Util.Maths.T4Math;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/* this is an alternative collision system because the original Collision Mesh system is fuck ass and sucks ass while MUNCHING on performance
|
||||
and makes the fast thread not so fast
|
||||
this is Separating Axis Theorem testing for two convex polyhedra or something idk im no rocket scientist, but i think this shi needs comments for once
|
||||
say we have 2 faces, face A and face B,this thingy-ma-jig tests face normals of A, face normals of B,
|
||||
and cross products of every edge pair (A x B) for edge-edge contacts, the axis with the smallest
|
||||
overlap (least "penetration" or intersection amount) is the collision normal,
|
||||
face contacts are "resolved into a full contact manifold"(whatever that means) by clipping the incident face
|
||||
against the side planes of the reference face, this is what gives stable multipoint contact (e.g. a box resting flat on a floor gets 4 contact points, not 1)
|
||||
|
||||
I'm not gonna lie, I asked Google AI Overview for help on this one, and it did NOT help, but it *did* provide some pretty useful information on how to do it
|
||||
For a good explanation, visit this https://dyn4j.org/2010/01/sat/*/
|
||||
public class SeparatingAxisTheoremTester {
|
||||
|
||||
private static final float BIAS = 0.005f;
|
||||
private static final Vector3f Distance1 = new Vector3f();
|
||||
private static final Vector3f Distance2 = new Vector3f();
|
||||
private static final Vector3f Axis = new Vector3f();
|
||||
private static final Vector3f Normal = new Vector3f();
|
||||
|
||||
public static class Contact {
|
||||
public Vector3f Point;
|
||||
public float Penetration;
|
||||
}
|
||||
|
||||
public static class CollisionResult {
|
||||
public Vector3f Normal;
|
||||
public float Penetration;
|
||||
public final List<Contact> Contacts = new ArrayList<>();
|
||||
}
|
||||
//as much as i'd like to multithread the fuck out of this, im putting it as synchronised so it doesn't get messy, and so memory management is smoother, i want to minimize the amount of Vectors creating during loops
|
||||
public synchronized static CollisionResult TestCollision(ConvexMesh Mesh1, ConvexMesh Mesh2){
|
||||
float BestOverlap = Float.MAX_VALUE;
|
||||
Vector3f BestAxis = null;
|
||||
ConvexMesh.Face BestFace =null;
|
||||
ConvexMesh BestFaceOwner = null;
|
||||
|
||||
for(ConvexMesh.Face face : Mesh1.Faces){
|
||||
Vector3f Axis = Mesh1.WorldFaceNormal(face);
|
||||
Float Overlap = AxisOverlap(Mesh1,Mesh2,Axis);
|
||||
if(Overlap == null) return null; // Axis do not overlap, no collision is happening, return to whatever fuck ass code is running
|
||||
if(Overlap < BestOverlap){
|
||||
BestOverlap = Overlap;
|
||||
BestAxis = Axis;
|
||||
BestFace = face;
|
||||
BestFaceOwner = Mesh1;
|
||||
}
|
||||
}
|
||||
for(ConvexMesh.Face face : Mesh2.Faces){
|
||||
Vector3f Axis = Mesh2.WorldFaceNormal(face);// /\
|
||||
Float Overlap = AxisOverlap(Mesh1,Mesh2,Axis);// |
|
||||
if(Overlap == null) return null; //what he said up there |
|
||||
if(Overlap < BestOverlap){
|
||||
BestOverlap = Overlap;
|
||||
BestAxis = Axis;
|
||||
BestFace = face;
|
||||
BestFaceOwner = Mesh2;
|
||||
}
|
||||
}
|
||||
|
||||
Vector3f BestEdgeAxis = null;
|
||||
float BestEdgeOverlap = Float.MAX_VALUE;
|
||||
int[] BestEdge1 = null, BestEdge2 = null;
|
||||
for(int[]Edge1 : Mesh1.Edges){
|
||||
Vector3f Point11 = Mesh1.WorldVertex(Edge1[0]);
|
||||
Vector3f Point12 = Mesh1.WorldVertex(Edge1[1]);
|
||||
Distance1.set(Point12).sub(Point11);
|
||||
|
||||
for(int[]Edge2 : Mesh2.Edges){
|
||||
Vector3f Point21 = Mesh2.WorldVertex(Edge2[0]);
|
||||
Vector3f Point22 = Mesh2.WorldVertex(Edge2[1]);
|
||||
Distance2.set(Point22).sub(Point21);
|
||||
|
||||
Axis.set(Distance1).cross(Distance2);
|
||||
if(Axis.lengthSquared() < T4Math.Math3D.epsilon) continue; //if its parallel or close to parallel jump town (continue here skips it to the next item in the loop)
|
||||
Axis.normalize();
|
||||
|
||||
Float Overlap = AxisOverlap(Mesh1, Mesh2, Axis);
|
||||
if(Overlap == null) return null;
|
||||
if(Overlap < BestEdgeOverlap){
|
||||
BestEdgeOverlap = Overlap;
|
||||
BestEdgeAxis = Axis;
|
||||
BestEdge1 = Edge1;
|
||||
BestEdge2 = Edge2;
|
||||
}
|
||||
}
|
||||
}
|
||||
Vector3f Center1 = MeshCenter(Mesh1);
|
||||
Vector3f Center2 = MeshCenter(Mesh2);
|
||||
|
||||
CollisionResult result = new CollisionResult();
|
||||
|
||||
if(BestEdgeAxis != null && BestEdgeOverlap < BestOverlap - BIAS){ // they're furiously EDGING (edge-edge collision)
|
||||
Vector3f Normal = new Vector3f(BestEdgeAxis);
|
||||
if(new Vector3f(Center2).sub(Center1).dot(Normal) < 0) Normal.negate();
|
||||
Vector3f Point11 = Mesh1.WorldVertex(BestEdge1[0]), Point12 = Mesh1.WorldVertex(BestEdge1[1]);
|
||||
Vector3f Point21 = Mesh2.WorldVertex(BestEdge2[0]), Point22 = Mesh2.WorldVertex(BestEdge2[1]);
|
||||
Vector3f[] Closest = ClosestPointsSegment2(Point11,Point12,Point21,Point22);
|
||||
|
||||
result.Normal = Normal;
|
||||
result.Penetration = BestEdgeOverlap;
|
||||
Contact contact = new Contact();
|
||||
contact.Point = new Vector3f(Closest[0]).lerp(Closest[1],0.5f);
|
||||
contact.Penetration = BestEdgeOverlap;
|
||||
result.Contacts.add(contact);
|
||||
return result;
|
||||
}
|
||||
|
||||
//Face collision/clipping
|
||||
ConvexMesh ReferenceMesh = BestFaceOwner;
|
||||
ConvexMesh IncidentMesh = (ReferenceMesh == Mesh1) ? Mesh2 : Mesh1;
|
||||
ConvexMesh.Face ReferenceFace = BestFace;
|
||||
Vector3f ReferenceFaceNormalWorld = ReferenceMesh.WorldFaceNormal(ReferenceFace);
|
||||
|
||||
ConvexMesh.Face IncidentFace = FindIncidentFace(IncidentMesh, ReferenceFaceNormalWorld);
|
||||
List<Vector3f> IncidentPolygon = new ArrayList<>();
|
||||
for(int Index : IncidentFace.Indices) IncidentPolygon.add(IncidentMesh.WorldVertex(Index));
|
||||
List<Vector3f> ReferencePolygon = new ArrayList<>();
|
||||
for(int Index : ReferenceFace.Indices) ReferencePolygon.add(ReferenceMesh.WorldVertex(Index));
|
||||
|
||||
List<Vector3f> Clipped = ClipPolygonAgainstFace(IncidentPolygon, ReferencePolygon, ReferenceFaceNormalWorld);
|
||||
|
||||
Vector3f ReferencePoint = ReferencePolygon.get(0);
|
||||
Vector3f DepthVector = new Vector3f();
|
||||
for(Vector3f point : Clipped){
|
||||
float Depth = DepthVector.set(ReferencePoint).sub(point).dot(ReferenceFaceNormalWorld);
|
||||
if(Depth >= 0){
|
||||
Contact contact = new Contact();
|
||||
contact.Point = point;
|
||||
contact.Penetration = Depth;
|
||||
result.Contacts.add(contact);
|
||||
}
|
||||
}
|
||||
if(result.Contacts.isEmpty())return null;
|
||||
|
||||
Normal.set(BestAxis);
|
||||
if(new Vector3f(Center2).sub(Center1).dot(Normal) < 0) Normal.negate();
|
||||
result.Normal = Normal;
|
||||
result.Penetration = BestOverlap;
|
||||
return result;
|
||||
}
|
||||
|
||||
private synchronized static Float AxisOverlap(ConvexMesh mesh1, ConvexMesh mesh2, Vector3f axis) {
|
||||
float[] Range1 = ProjectOntoAxis(mesh1, axis);
|
||||
float[] Range2 = ProjectOntoAxis(mesh2, axis);
|
||||
float Overlap = Math.min(Range1[1],Range2[1]) - Math.max(Range1[0],Range2[0]);
|
||||
return (Overlap < 0) ? null : Overlap;
|
||||
}
|
||||
|
||||
private synchronized static float[] ProjectOntoAxis(ConvexMesh mesh, Vector3f axis){
|
||||
float minimum = Float.MAX_VALUE, maximum = -Float.MAX_VALUE;
|
||||
for(int i = 0; i < mesh.LocalVertices.size(); i++){
|
||||
float distance = mesh.WorldVertex(i).dot(axis);
|
||||
minimum = Math.min(minimum, distance);
|
||||
maximum = Math.max(maximum, distance);
|
||||
}
|
||||
return new float[]{minimum,maximum};
|
||||
}
|
||||
|
||||
private synchronized static Vector3f MeshCenter(ConvexMesh mesh){
|
||||
Vector3f Center = new Vector3f();
|
||||
for(int i = 0; i < mesh.LocalVertices.size(); i++) Center.add(mesh.WorldVertex(i));
|
||||
Center.div(mesh.LocalVertices.size());
|
||||
return Center;
|
||||
}
|
||||
|
||||
private synchronized static ConvexMesh.Face FindIncidentFace(ConvexMesh mesh, Vector3f ReferenceNormal){
|
||||
ConvexMesh.Face Best = null;
|
||||
float BestDot = Float.MAX_VALUE;
|
||||
for(ConvexMesh.Face face : mesh.Faces){
|
||||
float d = mesh.WorldFaceNormal(face).dot(ReferenceNormal);
|
||||
if(d < BestDot) {
|
||||
BestDot = d;
|
||||
Best = face;
|
||||
}
|
||||
}
|
||||
return Best;
|
||||
}
|
||||
|
||||
private synchronized static List<Vector3f> ClipPolygonAgainstFace(List<Vector3f> Incident, List<Vector3f> ReferencePoly, Vector3f ReferenceNormal){
|
||||
List<Vector3f> Output = new ArrayList<>(Incident);
|
||||
int Count = ReferencePoly.size();
|
||||
for(int i = 0; i < Count; i++){
|
||||
if(Output.isEmpty())break;
|
||||
Vector3f Point1 = ReferencePoly.get(i);
|
||||
Vector3f Point2 = ReferencePoly.get((i + 1) % Count);
|
||||
Vector3f Edge = new Vector3f(Point2).sub(Point1);
|
||||
Vector3f SidePlaneNormal = new Vector3f(Edge).cross(ReferenceNormal).normalize();
|
||||
float Offset = SidePlaneNormal.dot(Point1);
|
||||
|
||||
List<Vector3f> Input=Output;
|
||||
Output = new ArrayList<>();
|
||||
for(int j = 0; j < Input.size(); j++){
|
||||
Vector3f Current = Input.get(j);
|
||||
Vector3f Previous = Input.get((j - 1 + Input.size()) % Input.size());
|
||||
|
||||
float dCurrent = SidePlaneNormal.dot(Current) - Offset;
|
||||
float dPrev = SidePlaneNormal.dot(Previous) - Offset;
|
||||
|
||||
if (dCurrent <= 0) {
|
||||
if (dPrev > 0) Output.add(IntersectEdge(Previous, Current, SidePlaneNormal, Offset));
|
||||
Output.add(Current);
|
||||
} else if (dPrev <= 0) {
|
||||
Output.add(IntersectEdge(Previous, Current, SidePlaneNormal, Offset));
|
||||
}
|
||||
}
|
||||
}
|
||||
return Output;
|
||||
}
|
||||
|
||||
private synchronized static Vector3f IntersectEdge(Vector3f Vertex1, Vector3f Vertex2, Vector3f Normal, float Offset) {
|
||||
Vector3f Distance = new Vector3f(Vertex2).sub(Vertex1);
|
||||
float Denominator = Normal.dot(Distance);
|
||||
float t = (Math.abs(Denominator) < T4Math.Math3D.epsilon) ? 0 : (Offset - Normal.dot(Vertex1)) / Denominator;
|
||||
return new Vector3f(Vertex1).add(Distance.mul(t));
|
||||
}
|
||||
|
||||
|
||||
private synchronized static Vector3f[] ClosestPointsSegment2(Vector3f p1, Vector3f q1, Vector3f p2, Vector3f q2) {
|
||||
Vector3f d1 = new Vector3f(q1).sub(p1);
|
||||
Vector3f d2 = new Vector3f(q2).sub(p2);
|
||||
Vector3f r = new Vector3f(p1).sub(p2);
|
||||
float a = d1.dot(d1), e = d2.dot(d2), f = d2.dot(r);
|
||||
float s, t;
|
||||
|
||||
if (a <= 1e-8f && e <= 1e-8f) {
|
||||
s = 0; t = 0;
|
||||
} else if (a <= 1e-8f) {
|
||||
s = 0; t = clamp(f / e, 0, 1);
|
||||
} else {
|
||||
float c = d1.dot(r);
|
||||
if (e <= 1e-8f) {
|
||||
t = 0; s = clamp(-c / a, 0, 1);
|
||||
} else {
|
||||
float b = d1.dot(d2);
|
||||
float denom = a * e - b * b;
|
||||
s = (Math.abs(denom) > 1e-8f) ? clamp((b * f - c * e) / denom, 0, 1) : 0;
|
||||
t = (b * s + f) / e;
|
||||
if (t < 0) { t = 0; s = clamp(-c / a, 0, 1); }
|
||||
else if (t > 1) { t = 1; s = clamp((b - c) / a, 0, 1); }
|
||||
}
|
||||
}
|
||||
|
||||
Vector3f c1 = new Vector3f(p1).add(new Vector3f(d1).mul(s));
|
||||
Vector3f c2 = new Vector3f(p2).add(new Vector3f(d2).mul(t));
|
||||
return new Vector3f[]{c1, c2};
|
||||
}
|
||||
|
||||
private static float clamp(float v, float lo, float hi) {
|
||||
return Math.max(lo, Math.min(hi, v));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package net.halbear.Terrain4J.EngineCore.Logic.Physics;
|
||||
|
||||
import org.joml.Vector3f;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
|
@ -13,30 +13,52 @@ public class WorldPhysicsManager {
|
|||
public static float Drag = 0.02f;
|
||||
public static float AirDensityKGM3 = 1.225f;
|
||||
|
||||
public static Vector3f CalculateRealDrag(Vector3f Velocity, Vector3f DragCoefficients, Vector3f CrossSectionAreas){
|
||||
float XDrag = 0.5f * (AirDensityKGM3 * Velocity.x * Velocity.x * DragCoefficients.x * CrossSectionAreas.x);
|
||||
float YDrag = 0.5f * (AirDensityKGM3 * Velocity.y * Velocity.y * DragCoefficients.y * CrossSectionAreas.y);
|
||||
float ZDrag = 0.5f * (AirDensityKGM3 * Velocity.z * Velocity.z * DragCoefficients.z * CrossSectionAreas.z);
|
||||
return new Vector3f(XDrag,YDrag,ZDrag);
|
||||
}
|
||||
public static int PhysicsTick = 0;
|
||||
|
||||
public static float CalculateGravityForce(float Mass, Vector3f Drag){
|
||||
return ((Mass * GravityMS) - Drag.y)/Mass;
|
||||
}
|
||||
|
||||
public static Vector3f CalculateDragFromTerminalVelocities(Vector3f TerminalVelocities, float Mass, Vector3f CrossSectionAreas){
|
||||
float Cdx = (2 * Mass * GravityMS) / (AirDensityKGM3 * TerminalVelocities.x * TerminalVelocities.x * CrossSectionAreas.x);
|
||||
float Cdy = (2 * Mass * GravityMS) / (AirDensityKGM3 * TerminalVelocities.y * TerminalVelocities.y * CrossSectionAreas.y);
|
||||
float Cdz = (2 * Mass * GravityMS) / (AirDensityKGM3 * TerminalVelocities.z * TerminalVelocities.z * CrossSectionAreas.z);
|
||||
return new Vector3f(Cdx, Cdy, Cdz);
|
||||
}
|
||||
|
||||
public static final Map<String, PhysicsController> PhysicsObjects = new HashMap<>();
|
||||
public static final Map<String, IPhysicsController> PhysicsObjects = new HashMap<>();
|
||||
public static List<String> ActiveControllers = new ArrayList<>();
|
||||
|
||||
public static float FixedTimeStep = 1f / 60f;
|
||||
public static int MaxSubStepsPerFrame = 8;
|
||||
private static float Accumulator = 0f;
|
||||
|
||||
public static void SteppedPhysicsTick(float DeltaTime, float TargetFrameTime){
|
||||
if(EngineConfig.getInstance().IsEngineThrottled()) return;
|
||||
DeltaTime *= EngineConfig.getInstance().PhysicsSpeed();
|
||||
|
||||
Accumulator += DeltaTime;
|
||||
float maxAccumulated = FixedTimeStep * MaxSubStepsPerFrame;
|
||||
if (Accumulator > maxAccumulated) Accumulator = maxAccumulated;
|
||||
|
||||
int stepsRun = 0;
|
||||
|
||||
while (Accumulator >= FixedTimeStep && stepsRun < MaxSubStepsPerFrame) {
|
||||
PhysicsTick++;
|
||||
for (int i = 0; i < ActiveControllers.size(); i++) {
|
||||
if (PhysicsObjects.get(ActiveControllers.get(i)) != null) {
|
||||
PhysicsObjects.get(ActiveControllers.get(i)).PhysicsTick(FixedTimeStep, TargetFrameTime);
|
||||
}
|
||||
}
|
||||
Accumulator -= FixedTimeStep;
|
||||
stepsRun++;
|
||||
}
|
||||
for (int i = 0; i < ActiveControllers.size(); i++) {
|
||||
PhysicsObjects.get(ActiveControllers.get(i)).Collisions().clear();
|
||||
}
|
||||
}
|
||||
|
||||
public static void PhysicsTick(float DeltaTime, float TargetFrameTime){
|
||||
for(int i = 0; i < ActiveControllers.size(); i++){
|
||||
PhysicsObjects.get(ActiveControllers.get(i)).PhysicsTick(DeltaTime, TargetFrameTime);
|
||||
DeltaTime *= EngineConfig.getInstance().PhysicsSpeed();
|
||||
if(!EngineConfig.getInstance().IsEngineThrottled()) {
|
||||
PhysicsTick++;
|
||||
for (int i = 0; i < ActiveControllers.size(); i++) {
|
||||
if(PhysicsObjects.get(ActiveControllers.get(i)) != null) {
|
||||
PhysicsObjects.get(ActiveControllers.get(i)).PhysicsTick(DeltaTime, TargetFrameTime);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < ActiveControllers.size(); i++) {
|
||||
PhysicsObjects.get(ActiveControllers.get(i)).Collisions().clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,30 +6,29 @@ import imgui.ImGuiViewport;
|
|||
import imgui.flag.ImGuiCond;
|
||||
import imgui.flag.ImGuiWindowFlags;
|
||||
import net.halbear.Terrain4J.EngineCore.Audio.AudioManager;
|
||||
import net.halbear.Terrain4J.EngineCore.Audio.AudioSource;
|
||||
import net.halbear.Terrain4J.EngineCore.Audio.SoundBuffer;
|
||||
import net.halbear.Terrain4J.EngineCore.Audio.SoundListener;
|
||||
import net.halbear.Terrain4J.EngineCore.Display.Window;
|
||||
import net.halbear.Terrain4J.EngineCore.Input.KeyboardInput;
|
||||
import net.halbear.Terrain4J.EngineCore.Input.MouseListener;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Collision.CollisionManager;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Collision.CollisionMesh;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Physics.LegacyCollision.CollisionMesh;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.GameLogic;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.InitData;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Physics.LegacyPhysicsController;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody.ConvexMesh;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Physics.WorldPhysicsManager;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.ModelLoader;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.Scene.*;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.Scene.GUIs.Gimbal;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.Scene.GUIs.LoadingScreen;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.Scene.GUIs.PerformanceOverlay;
|
||||
import net.halbear.Terrain4J.EngineCore.Profiling.CPUMonitor;
|
||||
import net.halbear.Terrain4J.EngineCore.Profiling.GPUProfiler;
|
||||
import net.halbear.Terrain4J.EngineCore.Vulkan.GUI.GuiTexture;
|
||||
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel.MaterialData;
|
||||
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel.ModelData;
|
||||
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DisplayToScreen.ForwardSceneRender;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Vector2f;
|
||||
import org.joml.Vector3f;
|
||||
import org.lwjgl.openal.AL11;
|
||||
|
|
@ -80,14 +79,14 @@ public class GameCore implements GameLogic {
|
|||
MelonaData = ModelLoader.LoadModel("resources/models/melona/melona.json");
|
||||
List<MaterialData> MelonaDataMat = ModelLoader.LoadMaterials("resources/models/melona/melona_mat.json");
|
||||
var Melona = new Actor("Melona", MelonaData.ID(), new Vector3f(0,0f,-5f)).SetRotation(0,(float)Math.toRadians(180),0);
|
||||
Melona.CreatePhysicsController();
|
||||
Melona.GetPhysicsController()
|
||||
Melona.CreatePhysicsController(LegacyPhysicsController.CollisionType.Sensor);
|
||||
/* Melona.GetPhysicsController()
|
||||
.AddCollisionSensor(new Vector3f(0,0,0))
|
||||
.AddCollisionSensor(new Vector3f(0,1.8f,0))
|
||||
.AddCollisionSensor(new Vector3f(0,2.4f,0))
|
||||
.AddCollisionSensor(new Vector3f(0.5f,0,0))
|
||||
.AddCollisionSensor(new Vector3f(-0.5f,0,0))
|
||||
.AddCollisionSensor(new Vector3f(0.5f,1.8f,0))
|
||||
.AddCollisionSensor(new Vector3f(-5f,1.8f,0))
|
||||
.AddCollisionSensor(new Vector3f(-0.5f,1.8f,0))
|
||||
.AddCollisionSensor(new Vector3f(0.5f,1.8f,0.5f))
|
||||
.AddCollisionSensor(new Vector3f(-0.5f,1.8f,0.5f))
|
||||
.AddCollisionSensor(new Vector3f(-0.5f,1.8f,-0.5f))
|
||||
|
|
@ -95,13 +94,15 @@ public class GameCore implements GameLogic {
|
|||
.AddCollisionSensor(new Vector3f(0f,1.8f,0.5f))
|
||||
.AddCollisionSensor(new Vector3f(-0f,1.8f,-0.5f))
|
||||
.AddCollisionSensor(new Vector3f(-0f,0f,-0.5f))
|
||||
.AddCollisionSensor(new Vector3f(0f,0f,0.5f));
|
||||
.AddCollisionSensor(new Vector3f(0f,0f,0.5f));*/
|
||||
|
||||
CollisionMesh mesh = new CollisionMesh("Super Collision Mesh","NULL");
|
||||
mesh.AddNewCollisionPoly(new Vector3f(-100,-5,100),new Vector3f(-100,-5.5f,-100),new Vector3f(100,-6,-100));
|
||||
mesh.AddNewCollisionPoly(new Vector3f(100,-5.5f,100),new Vector3f(100,-6,-100),new Vector3f(-100,-5,100));
|
||||
try {
|
||||
Melona.GenerateCollisionMesh(MelonaData);
|
||||
Melona.SetPhysicsType(Actor.PhysicsControllerType.T4JLegacyCollision);
|
||||
Melona.GetCollisionMesh().GenerateSensorsFromVertices();
|
||||
} catch(IOException e){
|
||||
Logger.error("Could Not Generate Collison Mesh [{}]",e);
|
||||
}
|
||||
|
|
@ -145,33 +146,41 @@ public class GameCore implements GameLogic {
|
|||
return new InitData(models,materials,guiTextures);
|
||||
}
|
||||
|
||||
private static final Vector3f SpawnPosition = new Vector3f();
|
||||
private static final Vector3f SpawnDirection = new Vector3f();
|
||||
private static final Matrix4f rotationMatrix = new Matrix4f();
|
||||
|
||||
public void SpawnNewActorEditorComponent(EngineInstance engineInstance){
|
||||
var scene = engineInstance.scene();
|
||||
Camera camera = scene.GetCamera().CloneCamera();
|
||||
camera.MoveForward(5);
|
||||
var Melona = new Actor("MelonaSpawned" + scene.GetActors().size(), MelonaData.ID(), new Vector3f(camera.GetPosition()));
|
||||
camera = null;
|
||||
Melona.CreatePhysicsController();
|
||||
Melona.GetPhysicsController()
|
||||
.AddCollisionSensor(new Vector3f(0,0,0))
|
||||
.AddCollisionSensor(new Vector3f(0,1.8f,0))
|
||||
.AddCollisionSensor(new Vector3f(0.5f,0,0))
|
||||
.AddCollisionSensor(new Vector3f(-0.5f,0,0))
|
||||
.AddCollisionSensor(new Vector3f(0.5f,1.8f,0))
|
||||
.AddCollisionSensor(new Vector3f(-5f,1.8f,0))
|
||||
.AddCollisionSensor(new Vector3f(0.5f,1.8f,0.5f))
|
||||
.AddCollisionSensor(new Vector3f(-0.5f,1.8f,0.5f))
|
||||
.AddCollisionSensor(new Vector3f(-0.5f,1.8f,-0.5f))
|
||||
.AddCollisionSensor(new Vector3f(0.5f,1.8f,-0.5f))
|
||||
.AddCollisionSensor(new Vector3f(0f,1.8f,0.5f))
|
||||
.AddCollisionSensor(new Vector3f(-0f,1.8f,-0.5f))
|
||||
.AddCollisionSensor(new Vector3f(-0f,0f,-0.5f))
|
||||
.AddCollisionSensor(new Vector3f(0f,0f,0.5f));
|
||||
try {
|
||||
Melona.GenerateCollisionMesh(MelonaData);
|
||||
} catch(IOException e){
|
||||
Logger.error("Could Not Generate Collison Mesh [{}]",e);
|
||||
}
|
||||
var scene = engineInstance.scene();
|
||||
Camera camera = scene.GetCamera();
|
||||
SpawnNewActorEditorComponent(engineInstance, new Vector3f(camera.GetPosition()),camera.GetRotation(),camera.GetDirection());
|
||||
}
|
||||
|
||||
public void SpawnNewActor(EngineInstance engineInstance, Vector3f Position, Vector3f Rotation, Vector3f Direction){
|
||||
var scene = engineInstance.scene();
|
||||
Camera camera = scene.GetCamera();
|
||||
SpawnPosition.set(Position);
|
||||
rotationMatrix.set(new Matrix4f().rotateX(Rotation.x).rotateY(Rotation.y).rotateZ(Rotation.z));
|
||||
SpawnDirection.set(new Vector3f(Direction));
|
||||
rotationMatrix.positiveZ(SpawnDirection).negate().mul(5);
|
||||
SpawnPosition.add(SpawnDirection);
|
||||
var Melona = new Actor("MelonaSpawned" + scene.GetActors().size(), MelonaData.ID(), new Vector3f(SpawnPosition));
|
||||
|
||||
Melona.CreatePhysicsController( ConvexMesh.Box(0.75f,1,0.5f),20);
|
||||
scene.AddActor(Melona);
|
||||
}
|
||||
|
||||
public void SpawnNewActorEditorComponent(EngineInstance engineInstance, Vector3f Position, Vector3f Rotation, Vector3f Direction){
|
||||
var scene = engineInstance.scene();
|
||||
Camera camera = scene.GetCamera();
|
||||
SpawnPosition.set(Position);
|
||||
rotationMatrix.set(new Matrix4f().rotateX(Rotation.x).rotateY(Rotation.y).rotateZ(Rotation.z));
|
||||
SpawnDirection.set(new Vector3f(Direction));
|
||||
rotationMatrix.positiveZ(SpawnDirection).negate().mul(5);
|
||||
SpawnPosition.add(SpawnDirection);
|
||||
var Melona = new Actor("MelonaSpawned" + scene.GetActors().size(), MelonaData.ID(), new Vector3f(SpawnPosition));
|
||||
|
||||
Melona.CreatePhysicsController( ConvexMesh.Box(0.75f,1.2f,0.5f),20);
|
||||
scene.AddActor(Melona);
|
||||
ActorEditorComponents.add(new EditorActorComponent(Melona,new Vector3f(scene.GetCamera().GetPosition()),new Vector3f(1.0f,1.8f,1.0f)));
|
||||
}
|
||||
|
|
@ -235,8 +244,8 @@ public class GameCore implements GameLogic {
|
|||
KeyboardInput input = window.getKeyboardInput();
|
||||
float MovementDist = (float)(FrameDiffNanoSeconds / 1000000L) * MOVEMENT_SPEED;
|
||||
Camera camera = scene.GetCamera();
|
||||
if(input.keySinglePress(GLFW_KEY_F3)){
|
||||
GUI_MODE = (GUI_MODE + 1) % 2;
|
||||
if(input.keyPressed(GLFW_KEY_ENTER)) {
|
||||
SpawnNewActor(engineInstance, new Vector3f( (float)(2 * Math.random()),20 + (float)(10 * Math.random()), (float)(2 * Math.random())),new Vector3f(-1f + (float)(2 * Math.random()),-1f + (float)(2 * Math.random()),-1f + (float)(2 * Math.random())),new Vector3f((float)Math.random(),(float)Math.random(),(float)Math.random()));
|
||||
}
|
||||
if(input.keyPressed(GLFW_KEY_1)) {
|
||||
Gimbal.universalType = Gimbal.GimbalType.Move;
|
||||
|
|
|
|||
|
|
@ -1,19 +1,30 @@
|
|||
package net.halbear.Terrain4J.EngineCore.Main.Scene;
|
||||
|
||||
import imgui.extension.imguizmo.flag.Mode;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Collision.CollisionMesh;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Physics.PhysicsController;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Physics.LegacyCollision.CollisionMesh;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Physics.IPhysicsController;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Physics.LegacyPhysicsController;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody.ConvexMesh;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody.RigidCollision;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody.RigidPhysicsController;
|
||||
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel.ModelData;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Quaternionf;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class Actor{
|
||||
public enum PhysicsControllerType{
|
||||
RigidBodySeparatingAxisTheory,
|
||||
T4JLegacyCollision
|
||||
}
|
||||
|
||||
public static final Map<String, Actor> Actors = new HashMap<>();
|
||||
public static final List<String> ActorNames = new ArrayList<>();
|
||||
private final String ID;
|
||||
private final String ModelID;
|
||||
private final Matrix4f ModelMatrix;
|
||||
|
|
@ -21,10 +32,15 @@ public class Actor{
|
|||
private final Quaternionf Rotation;
|
||||
private CollisionMesh collisionMesh;
|
||||
private Vector3f Scale;
|
||||
private PhysicsController physicsController;
|
||||
private IPhysicsController physicsController;
|
||||
private final Vector3f PivotOffset;
|
||||
private final Vector3f AdditionalPivotOffset;
|
||||
private final Vector3f TemporaryVector;
|
||||
public PhysicsControllerType PhysicsType = PhysicsControllerType.RigidBodySeparatingAxisTheory;
|
||||
|
||||
public void SetPhysicsType(PhysicsControllerType type){
|
||||
this.PhysicsType = type;
|
||||
}
|
||||
|
||||
public CollisionMesh GetCollisionMesh(){
|
||||
return collisionMesh;
|
||||
|
|
@ -32,6 +48,7 @@ public class Actor{
|
|||
|
||||
public Actor(String ID, String ModelID, Vector3f Position){
|
||||
this.ID = ID;
|
||||
ActorNames.add(ID);
|
||||
this.ModelID = ModelID;
|
||||
this.Position = Position;
|
||||
TemporaryVector = new Vector3f();
|
||||
|
|
@ -58,10 +75,15 @@ public class Actor{
|
|||
return this;
|
||||
}
|
||||
|
||||
public PhysicsController GetPhysicsController(){return physicsController;}
|
||||
public IPhysicsController GetPhysicsController(){return physicsController;}
|
||||
|
||||
public Actor CreatePhysicsController(){
|
||||
physicsController = new PhysicsController(ID);
|
||||
public Actor CreatePhysicsController(ConvexMesh mesh, float Mass){
|
||||
physicsController = new RigidPhysicsController(ID + "_RIGID_CONTROLLER", ID).CreateRigidBody(mesh, Mass);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Actor CreatePhysicsController(LegacyPhysicsController.CollisionType collisionType){
|
||||
physicsController = new LegacyPhysicsController(ID, collisionType);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -79,7 +101,11 @@ public class Actor{
|
|||
Rotation.w = 1.0f;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Actor SetRotation(Quaternionf rot){
|
||||
Rotation.set(rot);
|
||||
UpdateModelMatrix();
|
||||
return this;
|
||||
}
|
||||
public Actor SetRotation(Vector3f rot){
|
||||
Rotation.rotateX(rot.x);
|
||||
Rotation.rotateY(rot.y);
|
||||
|
|
@ -101,16 +127,12 @@ public class Actor{
|
|||
return this;
|
||||
}
|
||||
public Actor SetPosition(float x, float y, float z){
|
||||
Position.x = x;
|
||||
Position.y = y;
|
||||
Position.z = z;
|
||||
Position.set(x,y,z);
|
||||
UpdateModelMatrix();
|
||||
return this;
|
||||
}
|
||||
public Actor SetScale(float x, float y, float z){
|
||||
Scale.x = x;
|
||||
Scale.y = y;
|
||||
Scale.z = z;
|
||||
Scale.set(x,y,z);
|
||||
UpdateModelMatrix();
|
||||
return this;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@ public class Camera {
|
|||
private float FOV = (float) (60 * EngineConfig.DegToRad);
|
||||
private boolean Sprint;
|
||||
|
||||
public Vector3f GetDirection(){
|
||||
return Direction;
|
||||
}
|
||||
public Camera CloneCamera(){
|
||||
Camera NewCam = new Camera();
|
||||
NewCam.SetPosition(Position.x, Position.y, Position.z);
|
||||
|
|
|
|||
|
|
@ -5,19 +5,21 @@ import imgui.ImGui;
|
|||
import imgui.ImVec2;
|
||||
import imgui.flag.ImGuiCol;
|
||||
import imgui.flag.ImGuiWindowFlags;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Collision.CollisionManager;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Collision.CollisionMesh;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Collision.CollisionPoly;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Physics.LegacyCollision.CollisionManager;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Physics.LegacyCollision.CollisionMesh;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Physics.LegacyCollision.CollisionPoly;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Physics.CollisionSensor;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Physics.LegacyPhysicsController;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.GameCore;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.Scene.Actor;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.Scene.GUIOverlay;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.Scene.IMoveableActorComponent;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.Util.Maths.T4Math;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Vector2f;
|
||||
import org.joml.Vector3f;
|
||||
import org.tinylog.Logger;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
|
@ -61,6 +63,17 @@ public class Gimbal implements GUIOverlay {
|
|||
for(int j = 0; j < polygons.length; j++){
|
||||
DrawCollisionPolygon(engineInstance.scene().GetCamera().GetViewMatrix(), engineInstance.scene().GetProjection().GetProjectionMatrix(),winWidth,winHeight,polygons[j]);
|
||||
}
|
||||
if(mesh.ParentID != "NULL" && Actor.Actors.get(mesh.ParentID) != null) {
|
||||
Actor actor = Actor.Actors.get(mesh.ParentID);
|
||||
if(actor.PhysicsType == Actor.PhysicsControllerType.T4JLegacyCollision) {
|
||||
LegacyPhysicsController physicsController = (LegacyPhysicsController) actor.GetPhysicsController();
|
||||
List<CollisionSensor> RawCollisionSesnors = physicsController.collisionSensors;
|
||||
// Vector3f[] CollisionSensors = new Vector3f[RawCollisionSesnors.size()];
|
||||
for (int j = 0; j < RawCollisionSesnors.size(); j++) {
|
||||
DrawCollisionSensor(engineInstance.scene().GetCamera().GetViewMatrix(), engineInstance.scene().GetProjection().GetProjectionMatrix(), winWidth, winHeight, RawCollisionSesnors.get(j).GetTransformedCollisionSensor(), actor.GetPosition());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for(int i = 0; i < gimbals.size(); i++){
|
||||
|
|
@ -106,6 +119,17 @@ public class Gimbal implements GUIOverlay {
|
|||
DrawGimbalInWorld(engineInstance.scene().GetCamera().GetViewMatrix(), engineInstance.scene().GetProjection().GetProjectionMatrix(),engineInstance.window().getWidth(),engineInstance.window().getHeight());
|
||||
}
|
||||
|
||||
public static void DrawCollisionSensor(Matrix4f viewMatrix, Matrix4f projMatrix, int winWidth, int winHeight, Vector3f Point, Vector3f Origin){
|
||||
if(Point == null) return;
|
||||
Vector3f v1 = T4Math.Math3D.GetScreenCoordFromWorldSpace(Point, viewMatrix, projMatrix, winWidth, winHeight);
|
||||
Vector3f v2 = T4Math.Math3D.GetScreenCoordFromWorldSpace(Origin, viewMatrix, projMatrix, winWidth, winHeight);
|
||||
if(v1 == null || v2 == null) return;
|
||||
ImDrawList drawList = ImGui.getBackgroundDrawList();
|
||||
int colour = ImGui.getColorU32(1.0f, 0.0f, 0.0f, 0.5f);
|
||||
drawList.addLine(v1.x, v1.y, v2.x, v2.y, colour, 1f);
|
||||
drawList.addCircle(new ImVec2(v1.x,v1.y),6,colour,5f);
|
||||
}
|
||||
|
||||
public static void DrawCollisionPolygon(Matrix4f viewMatrix, Matrix4f projMatrix, int winWidth, int winHeight, CollisionPoly polygon){
|
||||
if(polygon == null || polygon.v1() == null || polygon.v2() == null || polygon.v3() == null) return;
|
||||
Vector3f v1 = T4Math.Math3D.GetScreenCoordFromWorldSpace(polygon.v1(), viewMatrix, projMatrix, winWidth, winHeight);
|
||||
|
|
@ -133,6 +157,7 @@ public class Gimbal implements GUIOverlay {
|
|||
Vector3f ZYPoint = new Vector3f(Position.x,Position.y + (GimbalArmLengths.y/2.5f),Position.z + (GimbalArmLengths.z/2.5f));
|
||||
Vector3f XPoint = new Vector3f(Position.x + GimbalArmLengths.x,Position.y,Position.z);
|
||||
Vector3f XYPoint = new Vector3f(Position.x + (GimbalArmLengths.x/2.5f),Position.y+ (GimbalArmLengths.y/2.5f),Position.z);
|
||||
Vector3f XYZPoint = new Vector3f(Position.x + (GimbalArmLengths.x/1.5f),Position.y+ (GimbalArmLengths.y/1.5f),Position.z+ (GimbalArmLengths.y/1.5f));
|
||||
Vector3f XZPoint = new Vector3f(Position.x + (GimbalArmLengths.x/2.5f),Position.y,Position.z + (GimbalArmLengths.z/2.5f));
|
||||
Vector3f YPoint = new Vector3f(Position.x,Position.y + GimbalArmLengths.y,Position.z);
|
||||
Vector3f ZPoint = new Vector3f(Position.x,Position.y,Position.z + GimbalArmLengths.z);
|
||||
|
|
@ -143,6 +168,7 @@ public class Gimbal implements GUIOverlay {
|
|||
Vector3f ZCScreenPos = T4Math.Math3D.GetScreenCoordFromWorldSpace(ZCPoint, viewMatrix, projMatrix, winWidth, winHeight);
|
||||
Vector3f ZYScreenPos = T4Math.Math3D.GetScreenCoordFromWorldSpace(ZYPoint, viewMatrix, projMatrix, winWidth, winHeight);
|
||||
Vector3f XYScreenPos = T4Math.Math3D.GetScreenCoordFromWorldSpace(XYPoint, viewMatrix, projMatrix, winWidth, winHeight);
|
||||
Vector3f XYZScreenPos = T4Math.Math3D.GetScreenCoordFromWorldSpace(XYZPoint, viewMatrix, projMatrix, winWidth, winHeight);
|
||||
Vector3f XZScreenPos = T4Math.Math3D.GetScreenCoordFromWorldSpace(XZPoint, viewMatrix, projMatrix, winWidth, winHeight);
|
||||
Vector3f XPointScreenPos = T4Math.Math3D.GetScreenCoordFromWorldSpace(XPoint, viewMatrix, projMatrix, winWidth, winHeight);
|
||||
Vector3f YPointScreenPos = T4Math.Math3D.GetScreenCoordFromWorldSpace(YPoint, viewMatrix, projMatrix, winWidth, winHeight);
|
||||
|
|
@ -232,11 +258,10 @@ public class Gimbal implements GUIOverlay {
|
|||
if (ImGui.isItemActive()) {
|
||||
switch(universalType) {
|
||||
case Rotate:
|
||||
parent.AddRotation(new Vector3f((float) ((MouseDiff.x + MouseDiff.y) / (float) (winWidth / 10.0f)),0,0));
|
||||
|
||||
parent.AddRotation(new Vector3f((float) ((MouseDiff.x + MouseDiff.y) / (float) (winHeight / 10.0f)),0,0));
|
||||
break;
|
||||
case Resize:
|
||||
parent.AddScale(new Vector3f(0, (MouseDiff.x + MouseDiff.y) / (float) (winWidth / 10.0f), 0));
|
||||
parent.AddScale(new Vector3f(0, (MouseDiff.x + MouseDiff.y) / (float) (winHeight / 10.0f), 0));
|
||||
break;
|
||||
case Move:
|
||||
default:
|
||||
|
|
@ -303,6 +328,20 @@ public class Gimbal implements GUIOverlay {
|
|||
new ImVec2(YCScreenPos.x,YCScreenPos.y),
|
||||
},4,color);
|
||||
}
|
||||
|
||||
if(universalType == GimbalType.Resize && XYZScreenPos != null) {
|
||||
color = ImGui.getColorU32(1.0f, 0.8f, 0.0f, 1.0f);
|
||||
drawList.addLine(CentreScreenPos.x, CentreScreenPos.y, XYZScreenPos.x, XYZScreenPos.y, color, thickness);
|
||||
float adjustedX = XYZScreenPos.x - (buttonWidth / 2.0f);
|
||||
float adjustedY = XYZScreenPos.y - (buttonHeight / 2.0f);
|
||||
ImGui.setCursorScreenPos(adjustedX, adjustedY);
|
||||
ImGui.button("XYZ##" + ID, buttonWidth, buttonHeight);
|
||||
drawList.addRectFilled(XYZScreenPos.x- (thickness * ButtonMultiplier/2.0f), XYZScreenPos.y- (thickness * ButtonMultiplier/2.0f), XYZScreenPos.x+ (thickness * ButtonMultiplier/2.0f), XYZScreenPos.y + (thickness * ButtonMultiplier/2.0f), color);
|
||||
if (ImGui.isItemActive()) {
|
||||
parent.AddScale(new Vector3f((MouseDiff.x + MouseDiff.y) / (float) (winWidth / 10.0f), (MouseDiff.x + MouseDiff.y) / (float) (winWidth / 10.0f), (MouseDiff.x + MouseDiff.y) / (float) (winWidth / 10.0f)));
|
||||
parent.UpdateAll();
|
||||
}
|
||||
}
|
||||
ImGui.popStyleColor(3);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -148,8 +148,17 @@ public class Scene implements IScene {
|
|||
public void SetActiveCameraFrame(String frameName){SetCameraFrame = frameName;}
|
||||
public String GetActiveCameraFrame(){return ActiveCameraFrame;}
|
||||
public Camera GetCamera(){return camera;}
|
||||
public void AddActor(Actor NewActor){Actors.put(NewActor.GetID(), NewActor);}
|
||||
public List<Actor> GetActors(){return Actors.values().stream().toList();}
|
||||
public void AddActor(Actor NewActor){
|
||||
Actors.put(NewActor.GetID(), NewActor);
|
||||
ActiveActors.add(NewActor.GetID());
|
||||
}
|
||||
public List<Actor> GetActors(){
|
||||
List<Actor> actors = new ArrayList<>();
|
||||
for(int i = 0; i < ActiveActors.size(); i++){
|
||||
actors.add(Actors.get(ActiveActors.get(i)));
|
||||
}
|
||||
return actors;
|
||||
}
|
||||
public Project3D GetProjection(){return Projection;}
|
||||
public void RemoveAllActors(){Actors.clear();}
|
||||
public Actor RemoveActor(Actor actor){return Actors.remove(actor.GetID());}
|
||||
|
|
@ -158,6 +167,8 @@ public class Scene implements IScene {
|
|||
|
||||
}
|
||||
|
||||
public int GUI_MODE = 0;
|
||||
|
||||
@Override
|
||||
public void Input(EngineInstance engineInstance, long FrameDiffNanoSeconds) {
|
||||
IScene scene = engineInstance.scene();
|
||||
|
|
@ -166,14 +177,8 @@ public class Scene implements IScene {
|
|||
KeyboardInput input = window.getKeyboardInput();
|
||||
float MovementDist = (float)(FrameDiffNanoSeconds / 1000000L) * MOVEMENT_SPEED;
|
||||
Camera camera = scene.GetCamera();
|
||||
if(input.keyPressed(GLFW_KEY_1)){
|
||||
|
||||
}
|
||||
if(input.keyPressed(GLFW_KEY_2)){
|
||||
|
||||
}
|
||||
if(input.keyPressed(GLFW_KEY_3)){
|
||||
|
||||
if(input.keySinglePress(GLFW_KEY_F3)){
|
||||
GUI_MODE = (GUI_MODE + 1) % 2;
|
||||
}
|
||||
if(input.keyPressed(GLFW_KEY_W)){
|
||||
camera.MoveForward(MovementDist);
|
||||
|
|
@ -196,6 +201,8 @@ public class Scene implements IScene {
|
|||
if(input.keyPressed(GLFW_KEY_LEFT_CONTROL)){
|
||||
camera.Sprint(true);
|
||||
} else camera.Sprint(false);
|
||||
if(GUI_MODE == 0 && !ActiveGUIs.contains("PerformanceOverlay")) ActiveGUIs.add("PerformanceOverlay");
|
||||
else if (GUI_MODE != 0) ActiveGUIs.remove("PerformanceOverlay");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1,10 +1,14 @@
|
|||
package net.halbear.Terrain4J.EngineCore.Main.Util.Maths;
|
||||
|
||||
import imgui.ImVec2;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Physics.LegacyCollision.CollisionPoly;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.Physics.LegacyPhysicsController;
|
||||
import org.joml.*;
|
||||
|
||||
import java.lang.Math;
|
||||
|
||||
import static net.halbear.Terrain4J.EngineCore.Logic.Physics.WorldPhysicsManager.AirDensityKGM3;
|
||||
import static net.halbear.Terrain4J.EngineCore.Logic.Physics.WorldPhysicsManager.GravityMS;
|
||||
|
||||
public class T4Math {
|
||||
public static double Log2(int n){
|
||||
return Math.log(n) / Math.log(n);
|
||||
|
|
@ -25,9 +29,140 @@ public class T4Math {
|
|||
}
|
||||
}
|
||||
|
||||
public static class Math3D {
|
||||
public static float epsilon = 1e-6f;
|
||||
public static class Physics{
|
||||
public static Vector3f CalculateDragCoefficients(Vector3f TerminalVelocitiesMS, float MassKG, Vector3f CrossSectionAreas, Vector3f Scale){
|
||||
return (CalculateDragFromTerminalVelocities(TerminalVelocitiesMS,MassKG *Math.abs((Scale.x + Scale.y + Scale.z)/3),new Vector3f(CrossSectionAreas)));
|
||||
}
|
||||
public static Vector3f CalculateDrag(Vector3f Velocities, Vector3f DragCoefficients, Vector3f CrossSectionAreas, Vector3f Scale){
|
||||
return (CalculateRealDrag(Velocities,DragCoefficients,new Vector3f(CrossSectionAreas)));
|
||||
}
|
||||
public static float CalculateFallSpeed(float MassKG, Vector3f Drag, Vector3f Scale){
|
||||
return CalculateGravityForce(MassKG *Math.abs((Scale.x + Scale.y + Scale.z)/3), Drag);
|
||||
}
|
||||
|
||||
public static Vector3f CalculateRealDrag(Vector3f Velocity, Vector3f DragCoefficients, Vector3f CrossSectionAreas){
|
||||
float XDrag = 0.5f * (AirDensityKGM3 * Velocity.x * Velocity.x * DragCoefficients.x * CrossSectionAreas.x);
|
||||
float YDrag = 0.5f * (AirDensityKGM3 * Velocity.y * Velocity.y * DragCoefficients.y * CrossSectionAreas.y);
|
||||
float ZDrag = 0.5f * (AirDensityKGM3 * Velocity.z * Velocity.z * DragCoefficients.z * CrossSectionAreas.z);
|
||||
return new Vector3f(XDrag,YDrag,ZDrag);
|
||||
}
|
||||
|
||||
public static float CalculateGravityForce(float Mass, Vector3f Drag){
|
||||
return ((Mass * GravityMS) - Drag.y)/Mass;
|
||||
}
|
||||
|
||||
public static Vector3f CalculateDragFromTerminalVelocities(Vector3f TerminalVelocities, float Mass, Vector3f CrossSectionAreas){
|
||||
float Cdx = (2 * Mass * GravityMS) / (AirDensityKGM3 * TerminalVelocities.x * TerminalVelocities.x * CrossSectionAreas.x);
|
||||
float Cdy = (2 * Mass * GravityMS) / (AirDensityKGM3 * TerminalVelocities.y * TerminalVelocities.y * CrossSectionAreas.y);
|
||||
float Cdz = (2 * Mass * GravityMS) / (AirDensityKGM3 * TerminalVelocities.z * TerminalVelocities.z * CrossSectionAreas.z);
|
||||
return new Vector3f(Cdx, Cdy, Cdz);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static class ComplexCollision{
|
||||
public static LegacyPhysicsController.CollisionResult ComputePolyToPolyIntersection(CollisionPoly poly1, CollisionPoly poly2){
|
||||
LegacyPhysicsController.CollisionResult result = new LegacyPhysicsController.CollisionResult();
|
||||
if(poly1 == null || poly2 == null) return null;
|
||||
Vector3f[] vertices1 = new Vector3f[]{new Vector3f().set(poly1.v1()),new Vector3f().set(poly1.v2()),new Vector3f().set(poly1.v3())};
|
||||
Vector3f[] vertices2 = new Vector3f[]{new Vector3f().set(poly2.v1()),new Vector3f().set(poly2.v2()),new Vector3f().set(poly2.v3())};
|
||||
Vector3f e1 = new Vector3f().set(poly1.v2()).sub(poly1.v1());
|
||||
Vector3f e2 = new Vector3f().set(poly1.v3()).sub(poly1.v1());
|
||||
Vector3f Normal1 = new Vector3f().set(e1).cross(e2).normalize();
|
||||
float Distance1 = -Normal1.dot(poly1.v1());
|
||||
|
||||
float[] du = new float[3];
|
||||
for(int i = 0; i < 3; i++) du[i] = Math.abs(Normal1.dot(vertices2[i]) + Distance1) < Math3D.epsilon ? 0 : Normal1.dot(vertices2[i]) + Distance1;
|
||||
if ((du[0] > 0 && du[1] > 0 && du[2] > 0) || (du[0] < 0 && du[1] < 0 && du[2] < 0)) return result;
|
||||
|
||||
|
||||
Vector3f f1 = new Vector3f().set(poly2.v2()).sub(poly2.v1());
|
||||
Vector3f f2 = new Vector3f().set(poly2.v3()).sub(poly2.v1());
|
||||
Vector3f Normal2 = new Vector3f().set(f1).cross(f2).normalize();
|
||||
float Distance2 = -Normal2.dot(poly2.v1());
|
||||
|
||||
float[] dv = new float[3];
|
||||
for(int i = 0; i < 3; i++) dv[i] = Math.abs(Normal2.dot(vertices1[i]) + Distance2) < Math3D.epsilon ? 0 : Normal2.dot(vertices1[i]) + Distance2;
|
||||
if ((dv[0] > 0 && dv[1] > 0 && dv[2] > 0) || (dv[0] < 0 && dv[1] < 0 && dv[2] < 0)) return result;
|
||||
|
||||
Vector3f IntersectionDirection = new Vector3f().set(Normal1).cross(Normal2);
|
||||
if (IntersectionDirection.lengthSquared() < Math3D.epsilon) {
|
||||
return result;
|
||||
}
|
||||
IntersectionDirection.normalize();
|
||||
|
||||
Vector3f[] Segment1 = GetIntersectionPoints(poly1, dv);
|
||||
Vector3f[] Segment2 = GetIntersectionPoints(poly2, du);
|
||||
|
||||
if (Segment1 == null || Segment2 == null) return result;
|
||||
|
||||
return ComputerSegmentOverlap(Segment1, Segment2, IntersectionDirection,Normal1);
|
||||
}
|
||||
|
||||
public static Vector3f[] GetIntersectionPoints(CollisionPoly poly, float[] d){
|
||||
Vector3f[] vertices1 = new Vector3f[]{new Vector3f().set(poly.v1()),new Vector3f().set(poly.v2()),new Vector3f().set(poly.v3())};
|
||||
Vector3f[] Points = new Vector3f[2];
|
||||
int Count = 0;
|
||||
for(int i = 0; i < 3; i++) {
|
||||
int next = (i + 1) % 3;
|
||||
if (d[i] * d[next] < 0 || (d[i] == 0 && d[next] != 0) || (d[i] != 0 && d[next] == 0)) {
|
||||
float Factor = d[i] / (d[i] - d[next]);
|
||||
if (Float.isNaN(Factor) || Float.isInfinite(Factor)) Factor = 0.0f;
|
||||
Vector3f Intersect = new Vector3f().set(vertices1[next]).sub(vertices1[i])
|
||||
.mul(Factor).add(vertices1[i]);
|
||||
if(Count < 2){
|
||||
Points[Count++] = Intersect;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Count == 2 ? Points : null;
|
||||
}
|
||||
|
||||
public static LegacyPhysicsController.CollisionResult ComputerSegmentOverlap(Vector3f[] Segment1, Vector3f[] Segment2, Vector3f Direction, Vector3f CollisionNormal){
|
||||
LegacyPhysicsController.CollisionResult result = new LegacyPhysicsController.CollisionResult();
|
||||
|
||||
float Poly1Min = Segment1[0].dot(Direction);
|
||||
float Poly1Max = Segment1[1].dot(Direction);
|
||||
Vector3f point1Min = Segment1[0], point1Max = Segment1[1];
|
||||
if(Poly1Min > Poly1Max){
|
||||
float temp = Poly1Max;
|
||||
Poly1Max = Poly1Min;
|
||||
Poly1Min = temp;
|
||||
Vector3f pTemp = point1Min;
|
||||
point1Min = point1Max;
|
||||
point1Max = pTemp;
|
||||
}
|
||||
float Poly2Min = Segment2[0].dot(Direction);
|
||||
float Poly2Max = Segment2[1].dot(Direction);
|
||||
Vector3f point2Min = Segment2[0], point2Max = Segment2[1];
|
||||
if(Poly2Min > Poly2Max){
|
||||
float temp = Poly2Max;
|
||||
Poly2Max = Poly2Min;
|
||||
Poly2Min = temp;
|
||||
Vector3f pTemp = point2Min;
|
||||
point2Min = point2Max;
|
||||
point2Max = pTemp;
|
||||
}
|
||||
|
||||
if (Poly1Max < Poly2Min - Math3D.epsilon || Poly2Max < Poly1Min - Math3D.epsilon) return result;
|
||||
|
||||
float overlapMin = Math.max(Poly1Min, Poly2Min);
|
||||
float overlapMax = Math.min(Poly1Max, Poly2Max);
|
||||
float segmentLength = overlapMax - overlapMin;
|
||||
|
||||
result.Intersects = true;
|
||||
result.StartPoint = new Vector3f((Poly1Min > Poly2Min) ? point1Min : point2Min);
|
||||
result.EndPoint = new Vector3f((Poly1Max < Poly2Max) ? point1Max : point2Max);
|
||||
result.CollisionNormal = new Vector3f(CollisionNormal);
|
||||
result.CollisionDepth = segmentLength;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Math3D {
|
||||
public static float epsilon = 1e-8f;
|
||||
|
||||
|
||||
public static boolean TestAabbAabb(
|
||||
|
|
@ -56,11 +191,12 @@ public class T4Math {
|
|||
return null;
|
||||
}
|
||||
|
||||
public static Vector3f LineCollisionPointWithPoly(Vector3f Origin, Vector3f Point, Vector3f[] Vertices){
|
||||
public static Vector3f LineCollisionPointWithPoly(Vector3f Origin, Vector3f Point, Vector3f[] Vertices, Vector2f ReturnTestValue){
|
||||
Vector3f LineDirection = new Vector3f(Point).sub(Origin);
|
||||
float Test = Intersectionf.intersectRayTriangle(Origin,LineDirection,
|
||||
Vertices[0],Vertices[1],Vertices[2], epsilon);
|
||||
if (Test >= 0.0f && Test <= 1.0f) {
|
||||
ReturnTestValue.set(Test,1-Test);
|
||||
return new Vector3f(LineDirection).mul(Test).add(Origin);
|
||||
}
|
||||
return null;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue