Gun + the physics are on evil mode

This commit is contained in:
Halbear 2026-07-06 22:41:47 +01:00
parent 605c96362b
commit 8ab8c06f9c
23 changed files with 2248 additions and 899 deletions

View file

@ -7,6 +7,7 @@ import org.joml.Vector3f;
import java.util.List;
public interface IPhysicsController {
public boolean ApplyRotationalForce();
public String ID();
public String ActorID();
public String MeshID();

View file

@ -22,6 +22,7 @@ public class LegacyPhysicsController implements IPhysicsController {
Sensor
}
public List<CollisionSensor> collisionSensors;
public Vector3f Velocities = new Vector3f(0,0,0);
public Vector3f WeightBalance = new Vector3f(0,0,0);
@ -93,6 +94,11 @@ public class LegacyPhysicsController implements IPhysicsController {
return this;
}
@Override
public boolean ApplyRotationalForce() {
return false;
}
@Override
public String ID() {
return "";

View file

@ -2,6 +2,7 @@ package net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import org.joml.primitives.AABBf;
import java.util.ArrayList;
import java.util.Arrays;
@ -34,6 +35,17 @@ public class ConvexMesh {
return vertex;
}
public AABBf GetWorldAABB() {
float minX = Float.MAX_VALUE, minY = Float.MAX_VALUE, minZ = Float.MAX_VALUE;
float maxX = -Float.MAX_VALUE, maxY = -Float.MAX_VALUE, maxZ = -Float.MAX_VALUE;
for (int i = 0; i < LocalVertices.size(); i++) {
Vector3f w = WorldVertex(i);
minX = Math.min(minX, w.x); minY = Math.min(minY, w.y); minZ = Math.min(minZ, w.z);
maxX = Math.max(maxX, w.x); maxY = Math.max(maxY, w.y); maxZ = Math.max(maxZ, w.z);
}
return new AABBf(minX, minY, minZ, maxX, maxY, maxZ);
}
public Vector3f WorldFaceNormal(Face f) {
Vector3f normal = new Vector3f(f.LocalNormal);
Orientation.transform(normal);

View file

@ -1,6 +1,7 @@
package net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody;
import net.halbear.Terrain4J.EngineCore.Logic.Physics.IPhysicsController;
import net.halbear.Terrain4J.EngineCore.Logic.Physics.LegacyPhysicsController;
import org.joml.Matrix3f;
import org.joml.Quaternionf;
import org.joml.Vector3f;
@ -21,6 +22,8 @@ public class RigidBody {
public AABBf BoundingBox;
public boolean OnGround = false;
public Vector3f LastPosition = new Vector3f();
public final Vector3f Position;
public final Quaternionf Rotation;
public Vector3f WeightBalance = new Vector3f(0,0,0);
@ -44,6 +47,14 @@ public class RigidBody {
public float Friction = 0.5f;
public boolean IsStatic = false;
public boolean RotationLocked = false;
public boolean UsesFrictionResolution = true;
public final Vector3f PreviousPosition = new Vector3f();
public boolean Grounded = false;
public String PhysicsControllerID = "NULL";
public final String RigidBodyID;
@ -57,6 +68,13 @@ public class RigidBody {
SetMass(MassKG);
}
public RigidBody LockRotation(){
RotationLocked = true;
InverseInertiaLocal.zero();
InverseInertiaWorld.zero();
return this;
}
public void SetMass(float mass) {
this.MassKG = mass;
if (mass <= 0f) {
@ -70,7 +88,7 @@ public class RigidBody {
}
public void SetRigidBoxInertia(float x, float y, float z){
if(IsStatic) return;
if(IsStatic || RotationLocked) 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);
@ -83,7 +101,7 @@ public class RigidBody {
}
public void UpdateInertiaWorld(){
if(IsStatic) {
if(IsStatic || RotationLocked) {
InverseInertiaWorld.zero();
return;
}
@ -115,8 +133,11 @@ public class RigidBody {
private final Vector3f GravityToAdd = new Vector3f();
private final Vector3f VelocityToAdd = new Vector3f();
public void Integrate(float DeltaTime, Vector3f Gravity){
PreviousPosition.set(Position);
if(IsStatic) return;
LinearVelocity.add(GravityToAdd.set(Gravity).mul(DeltaTime));
if(!Grounded) {
LinearVelocity.add(GravityToAdd.set(Gravity).mul(DeltaTime));
}
Position.add(VelocityToAdd.set(LinearVelocity).mul(DeltaTime));
Quaternionf Spin = new Quaternionf(

View file

@ -5,8 +5,11 @@ 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 = 0.9f; //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
private static final float CORRECTION_THRESHOLD = 1.0f;
private static final float SLOP = 0.00f;
private static final float GROUNDED_DOT_THRESHOLD = 0.7f;
private static final Vector3f WorldUp = new Vector3f(0, 1, 0);
public synchronized static void ResolveCollision(RigidBody body1, RigidBody body2, SeparatingAxisTheoremTester.CollisionResult collisionResult){
Vector3f Normal = collisionResult.Normal;
@ -15,6 +18,9 @@ public class RigidCollision {
}
CorrectPositioning(body1,body2,Normal,collisionResult.Penetration);
if(Normal.dot(WorldUp) > GROUNDED_DOT_THRESHOLD && !body2.IsStatic) body2.Grounded = true;
if(-Normal.dot(WorldUp) > GROUNDED_DOT_THRESHOLD && !body1.IsStatic) body1.Grounded = true;
}
private static final Vector3f Dist1 = new Vector3f();
@ -24,7 +30,6 @@ public class RigidCollision {
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);
@ -43,8 +48,8 @@ public class RigidCollision {
float j = -(1 + Restitution) * VelocityAlongNormal / InverseMassSum;
Impulse.set(normal).mul(j);
body1.LinearVelocity.mul(-1,body1.LinearVelocity.y < 0 ? 1 : -1,-1).mul(body1.Bounciness,body1.LinearVelocity.y < 0 ? 1 : body1.Bounciness,body1.Bounciness);
body2.LinearVelocity.mul(-1,body2.LinearVelocity.y < 0 ? 1 : -1,-1).mul(body2.Bounciness,body2.LinearVelocity.y < 0 ? 1 : body2.Bounciness,body2.Bounciness);
// body1.LinearVelocity.mul(-1,body1.LinearVelocity.y < 0 ? 1 : -1,-1).mul(body1.Bounciness,body1.LinearVelocity.y < 0 ? 1 : body1.Bounciness,body1.Bounciness);
// body2.LinearVelocity.mul(-1,body2.LinearVelocity.y < 0 ? 1 : -1,-1).mul(body2.Bounciness,body2.LinearVelocity.y < 0 ? 1 : body2.Bounciness,body2.Bounciness);
body1.ApplyImpulse(NegatedImpulse.set(Impulse).negate(), Point);

View file

@ -23,6 +23,7 @@ public class RigidPhysicsController implements IPhysicsController {
return RigidControllerRegister.get(ID);
}
public final List<String> Collisions = new ArrayList<>();
public boolean ApplyRotation = true;
public static RigidBody Ground = new RigidBody("FLOOR",ConvexMesh.Box(100,100f,100),0);
public static RigidBody Wall = new RigidBody("WALL",ConvexMesh.Box(100,100f,10),0);
@ -78,6 +79,11 @@ public class RigidPhysicsController implements IPhysicsController {
return this;
}
@Override
public boolean ApplyRotationalForce() {
return ApplyRotation;
}
@Override
public String ID() {
return ControllerID;
@ -103,7 +109,7 @@ public class RigidPhysicsController implements IPhysicsController {
rigidBody.Integrate(DeltaTime, new Vector3f(0,-1.8f,0));
if(Actor.Actors.get(ActorID) != null) {
Actor.Actors.get(ActorID).SetPosition(new Vector3f(rigidBody.Position));
Actor.Actors.get(ActorID).SetRotation(rigidBody.Rotation);
if(ApplyRotation) Actor.Actors.get(ActorID).SetRotation(rigidBody.Rotation);
}
}
/*

View file

@ -115,6 +115,7 @@ public class SeparatingAxisTheoremTester {
//Face collision/clipping
ConvexMesh ReferenceMesh = BestFaceOwner;
if(ReferenceMesh == null) return null;
ConvexMesh IncidentMesh = (ReferenceMesh == Mesh1) ? Mesh2 : Mesh1;
ConvexMesh.Face ReferenceFace = BestFace;
Vector3f ReferenceFaceNormalWorld = ReferenceMesh.WorldFaceNormal(ReferenceFace);

View file

@ -0,0 +1,45 @@
package net.halbear.Terrain4J.EngineCore.Logic.Physics;
import org.joml.primitives.AABBf;
import java.util.*;
public class SpatialHashGrid {
public static float CellSize = 3f;
private static final Map<Long, List<String>> Cells = new HashMap<>();
public static void Clear() {
Cells.clear();
}
public static void Insert(String bodyID, AABBf worldBounds) {
int minX = (int) Math.floor(worldBounds.minX / CellSize);
int minY = (int) Math.floor(worldBounds.minY / CellSize);
int minZ = (int) Math.floor(worldBounds.minZ / CellSize);
int maxX = (int) Math.floor(worldBounds.maxX / CellSize);
int maxY = (int) Math.floor(worldBounds.maxY / CellSize);
int maxZ = (int) Math.floor(worldBounds.maxZ / CellSize);
for (int x = minX; x <= maxX; x++) {
for (int y = minY; y <= maxY; y++) {
for (int z = minZ; z <= maxZ; z++) {
long key = HashCell(x, y, z);
Cells.computeIfAbsent(key, k -> new ArrayList<>()).add(bodyID);
}
}
}
}
private static long HashCell(int x, int y, int z) {
long xi = ((long) x) & 0x1FFFFFL;
long yi = ((long) y) & 0x1FFFFFL;
long zi = ((long) z) & 0x1FFFFFL;
return (xi << 42) | (yi << 21) | zi;
}
public static Collection<List<String>> Buckets() {
return Cells.values();
}
}

View file

@ -1,15 +1,17 @@
package net.halbear.Terrain4J.EngineCore.Logic.Physics;
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
import net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody.ConvexMesh;
import net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody.RigidBody;
import net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody.RigidCollision;
import net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody.SeparatingAxisTheoremTester;
import net.halbear.Terrain4J.EngineCore.Threads.PhysicsThread;
import org.joml.Vector2f;
import org.joml.Vector3f;
import org.joml.primitives.AABBf;
import org.joml.primitives.Intersectionf;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
public class WorldPhysicsManager {
public static float GravityMS = 9.8f;
@ -75,6 +77,8 @@ public class WorldPhysicsManager {
for (int i = 0; i < ActiveControllers.size(); i++) {
PhysicsObjects.get(ActiveControllers.get(i)).PhysicsTick(FixedTimeStep, TargetFrameTime);
}
SweepForTunneling();
ResetGroundedFlags();
ResolveAllCollisions();
Accumulator -= FixedTimeStep;
stepsRun++;
@ -86,20 +90,61 @@ public class WorldPhysicsManager {
}
private static void ResolveAllCollisions() {
List<String> ids = RigidBody.RigidBodies;
for (int i = 0; i < ids.size(); i++) {
RigidBody a = RigidBody.RigidBodyRegister.get(ids.get(i));
if (a == null) continue;
for (int j = i + 1; j < ids.size(); j++) {
RigidBody b = RigidBody.RigidBodyRegister.get(ids.get(j));
if (b == null) continue;
if (a.IsStatic && b.IsStatic) continue;
SeparatingAxisTheoremTester.CollisionResult result = SeparatingAxisTheoremTester.TestCollision(a.shape, b.shape);
if (result != null) {
RigidCollision.ResolveCollision(a, b, result);
List<RigidBody> dynamicBodies = new ArrayList<>();
List<RigidBody> staticBodies = new ArrayList<>();
Map<String, AABBf> worldBounds = new HashMap<>();
SpatialHashGrid.Clear();
for (int i = 0; i < ids.size(); i++) {
RigidBody body = RigidBody.RigidBodyRegister.get(ids.get(i));
if (body == null) continue;
AABBf bounds = body.shape.GetWorldAABB();
worldBounds.put(body.RigidBodyID, bounds);
if (body.IsStatic) {
staticBodies.add(body);
} else {
dynamicBodies.add(body);
SpatialHashGrid.Insert(body.RigidBodyID, bounds);
}
}
Set<String> testedPairs = new HashSet<>();
for (List<String> bucket : SpatialHashGrid.Buckets()) {
int size = bucket.size();
for (int i = 0; i < size; i++) {
RigidBody a = RigidBody.RigidBodyRegister.get(bucket.get(i));
if (a == null) continue;
for (int j = i + 1; j < size; j++) {
RigidBody b = RigidBody.RigidBodyRegister.get(bucket.get(j));
if (b == null || a == b) continue;
TryResolve(a, b, worldBounds, testedPairs);
}
}
}
for (RigidBody dyn : dynamicBodies) {
for (RigidBody stat : staticBodies) {
TryResolve(dyn, stat, worldBounds, testedPairs);
}
}
}
private static void TryResolve(RigidBody a, RigidBody b, Map<String, AABBf> worldBounds, Set<String> testedPairs) {
String key = a.RigidBodyID.compareTo(b.RigidBodyID) < 0
? a.RigidBodyID + "|" + b.RigidBodyID
: b.RigidBodyID + "|" + a.RigidBodyID;
if (!testedPairs.add(key)) return;
if (!worldBounds.get(a.RigidBodyID).intersectsAABB(worldBounds.get(b.RigidBodyID))) return;
SeparatingAxisTheoremTester.CollisionResult result = SeparatingAxisTheoremTester.TestCollision(a.shape, b.shape);
if (result != null) {
RigidCollision.ResolveCollision(a, b, result);
}
}
public static void PhysicsTick2(float DeltaTime, float TargetFrameTime){
@ -109,6 +154,8 @@ public class WorldPhysicsManager {
for (int i = 0; i < ActiveControllers.size(); i++) {
PhysicsObjects.get(ActiveControllers.get(i)).PhysicsTick(DeltaTime, TargetFrameTime);
}
SweepForTunneling();
ResetGroundedFlags();
ResolveAllCollisions();
for (int i = 0; i < ActiveControllers.size(); i++) {
PhysicsObjects.get(ActiveControllers.get(i)).Collisions().clear();
@ -130,4 +177,67 @@ public class WorldPhysicsManager {
}
}
private static void ResetGroundedFlags() {
List<String> ids = RigidBody.RigidBodies;
for (int i = 0; i < ids.size(); i++) {
RigidBody body = RigidBody.RigidBodyRegister.get(ids.get(i));
if (body != null) body.Grounded = false;
}
}
public static float MinSweepDistanceFactor = 0.5f;
public static float SweepMarginFactor = 0.5f;
private static void SweepForTunneling() {
List<String> ids = RigidBody.RigidBodies;
for (int i = 0; i < ids.size(); i++) {
RigidBody body = RigidBody.RigidBodyRegister.get(ids.get(i));
if (body == null || body.IsStatic) continue;
Vector3f from = body.PreviousPosition;
Vector3f to = body.Position;
float movedDistanceSq = from.distanceSquared(to);
if (movedDistanceSq < 1e-8f) continue;
float radius = BoundingRadius(body.shape);
float minSweepDistSq = (radius * radius) * (MinSweepDistanceFactor * MinSweepDistanceFactor);
if (movedDistanceSq < minSweepDistSq) continue; // moved a normal, slow amount - discrete SAT already handles this fine
float margin = radius * SweepMarginFactor;
Float earliestT = null;
for (int j = 0; j < ids.size(); j++) {
if (i == j) continue;
RigidBody other = RigidBody.RigidBodyRegister.get(ids.get(j));
if (other == null) continue;
Float t = RaySweepAABB(from, to, other.shape.GetWorldAABB(), margin);
if (t != null && (earliestT == null || t < earliestT)) {
earliestT = t;
}
}
if (earliestT != null) {
Vector3f safePosition = new Vector3f(from).lerp(to, Math.max(0f, earliestT - 0.01f));
body.Position.set(safePosition);
}
}
}
private static Float RaySweepAABB(Vector3f from, Vector3f to, AABBf bounds, float margin) {
Vector3f dir = new Vector3f(to).sub(from);
Vector3f min = new Vector3f(bounds.minX - margin, bounds.minY - margin, bounds.minZ - margin);
Vector3f max = new Vector3f(bounds.maxX + margin, bounds.maxY + margin, bounds.maxZ + margin);
Vector2f result = new Vector2f();
boolean hit = Intersectionf.intersectRayAab(from, dir, min, max, result);
if (!hit) return null;
if (result.x < 0f || result.x > 1f) return null;
return result.x;
}
private static float BoundingRadius(ConvexMesh shape) {
Vector3f half = new Vector3f(shape.TopRightForward).sub(shape.BottomLeftBack).mul(0.5f);
return half.length();
}
}

View file

@ -45,7 +45,7 @@ import static org.lwjgl.glfw.GLFW.*;
public class GameCore implements GameLogic {
private static final float MOUSE_SENSITIVITY = 0.1f;
private static final float MOVEMENT_SPEED = 0.025f;
private static final float MOVEMENT_SPEED = 0.01f;
public static boolean LoadingLevel = false;
public List<Actor> CubeActors = new ArrayList<>();
@ -67,6 +67,7 @@ public class GameCore implements GameLogic {
public List<IMoveableActorComponent> ActorEditorComponents = new ArrayList<>();
private Gimbal gimbal;
private Vector2f DeltaPos = new Vector2f(0,0);
private String PlayerActorID = "NULL";
public Vector2f GetDeltaPos(){return DeltaPos;}
@Override
@ -101,6 +102,17 @@ public class GameCore implements GameLogic {
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));
ModelData MusketData = ModelLoader.LoadModel("resources/models/musket/musket.json");
List<MaterialData> MusketMat = ModelLoader.LoadMaterials("resources/models/musket/musket_mat.json");
var Musket = new PlayerActor("DebugCamera","Player", MusketData.ID(), new Vector3f(0,5f,-5f)).SetCameraOffset(new Vector3f(0,1.0f,0));
Musket.SetPositionOffset(new Vector3f(0.5f,1.0f,-1.25f));
Musket.SetRotation(0,(float)Math.toRadians(180),0);
Musket.CreatePhysicsController( ConvexMesh.Box(0.5f,0.75f,0.5f),200f);
PlayerActorID = "Player";
RigidPhysicsController physicsController = (RigidPhysicsController) Musket.GetPhysicsController();
RigidBody.RigidBodyRegister.get(physicsController.RigidBodyID).LockRotation();
try {
Melona.GenerateCollisionMesh(MelonaData);
Melona.SetPhysicsType(Actor.PhysicsControllerType.T4JLegacyCollision);
@ -110,12 +122,15 @@ public class GameCore implements GameLogic {
}
mesh.RegisterMesh();
scene.AddActor(Melona);
scene.AddActor(Musket);
ActorEditorComponents.add(new EditorActorComponent(Melona,new Vector3f(0,0f,-5f),new Vector3f(1.0f,1.8f,1.0f)));
CubeActors.forEach(scene::AddActor);
List<MaterialData> materials = new ArrayList<>();
materials.addAll(MelonaDataMat);
materials.addAll(MusketMat);
models.add(MelonaData);
models.add(MusketData);
Camera camera = scene.GetCamera();
camera.SetPosition(0,0,0);
camera.SetRotation(0,0,0);
@ -170,7 +185,7 @@ public class GameCore implements GameLogic {
Melona.CreatePhysicsController( ConvexMesh.Box(0.5f,0.5f,0.5f),20);
RigidPhysicsController physicsController = (RigidPhysicsController) Melona.GetPhysicsController();
RigidBody.RigidBodyRegister.get(physicsController.RigidBodyID).LinearVelocity.set(0,0,-20f -(40f * (float)Math.random()));
//RigidBody.RigidBodyRegister.get(physicsController.RigidBodyID).LinearVelocity.set(0,0,-20f -(40f * (float)Math.random()));
scene.AddActor(Melona);
}
@ -224,6 +239,10 @@ public class GameCore implements GameLogic {
@Override
public void RenderThreadInput(EngineInstance engineInstance, long FrameDiffNanoSeconds) {
Actor player = Actor.Actors.get(PlayerActorID);
if(player != null){
player.TickUpdate();
}
engineInstance.scene().CameraTick(FrameDiffNanoSeconds);
if(ChangeGraphicsSettings){
if(NextAAMode != -1){
@ -248,6 +267,8 @@ public class GameCore implements GameLogic {
KeyboardInput input = window.getKeyboardInput();
float MovementDist = (float)(FrameDiffNanoSeconds / 1000000L) * MOVEMENT_SPEED;
Camera camera = scene.GetCamera();
PlayerActor playerActor = (PlayerActor) Actor.Actors.get(PlayerActorID);
if(playerActor!= null)camera = Camera.GetCamera(playerActor.AttachedCameraID);
if(input.keyPressed(GLFW_KEY_ENTER)) {
SpawnNewActor(engineInstance, new Vector3f( (float)(5 * Math.random()),20 + (float)(10 * Math.random()), (float)(5 * 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()));
}
@ -269,22 +290,30 @@ public class GameCore implements GameLogic {
EngineConfig.getInstance().SetRenderCollisionMesh(!EngineConfig.getInstance().RenderCollisionMeshes());
}
if(input.keyPressed(GLFW_KEY_W)){
camera.MoveForward(MovementDist);
if(playerActor == null)camera.MoveForward(MovementDist);
else playerActor.Move(new Vector3f(MovementDist* (float)Math.sin((camera.GetRotation().y)),0,-MovementDist* (float)Math.cos((camera.GetRotation().y))));
}
if(input.keyPressed(GLFW_KEY_S)){
camera.MoveBackward(MovementDist);
if(playerActor == null)camera.MoveBackward(MovementDist);
else playerActor.Move(new Vector3f(-MovementDist* (float)Math.sin((camera.GetRotation().y)),0,MovementDist * (float)Math.cos((camera.GetRotation().y))));
}
if(input.keyPressed(GLFW_KEY_A)){
camera.MoveLeft(MovementDist);
if(playerActor == null) camera.MoveLeft(MovementDist);
else playerActor.Move(new Vector3f(-MovementDist * (float)Math.cos((camera.GetRotation().y)),0,-MovementDist * (float)Math.sin((camera.GetRotation().y))));
}
if(input.keyPressed(GLFW_KEY_D)){
camera.MoveRight(MovementDist);
if(playerActor == null)camera.MoveRight(MovementDist);
else playerActor.Move(new Vector3f(MovementDist * (float)Math.cos((camera.GetRotation().y)),0,MovementDist * (float)Math.sin((camera.GetRotation().y))));
}
if(input.keyPressed(GLFW_KEY_SPACE)){
camera.MoveUp(MovementDist);
if(playerActor == null)camera.MoveUp(MovementDist);
}
if(input.keySinglePress(GLFW_KEY_SPACE)){
// camera.MoveUp(MovementDist);
if(playerActor != null)playerActor.Move(new Vector3f(0,5f,0));
}
if(input.keyPressed(GLFW_KEY_LEFT_SHIFT)){
camera.MoveDown(MovementDist);
if(playerActor == null)camera.MoveDown(MovementDist);
}
if(input.keyPressed(GLFW_KEY_LEFT_CONTROL)){
camera.Sprint(true);
@ -340,7 +369,7 @@ public class GameCore implements GameLogic {
if(PrimaryRuntime.GetFastThread().Ticks(20)==0){
//CollisionManager.UpdateCollisionChunks();
}
WorldPhysicsManager.SteppedPhysicsTick2(DeltaTime, PhysicsFramerate);
WorldPhysicsManager.PhysicsTick2(DeltaTime, PhysicsFramerate);
}
@Override

View file

@ -29,6 +29,7 @@ public class Actor{
private final String ModelID;
private final Matrix4f ModelMatrix;
private final Vector3f Position;
private final Vector3f PositionOffset;
private final Quaternionf Rotation;
private CollisionMesh collisionMesh;
private Vector3f Scale;
@ -51,6 +52,7 @@ public class Actor{
ActorNames.add(ID);
this.ModelID = ModelID;
this.Position = Position;
this.PositionOffset = new Vector3f();
TemporaryVector = new Vector3f();
PivotOffset = new Vector3f();
AdditionalPivotOffset = new Vector3f();
@ -61,6 +63,20 @@ public class Actor{
Actors.put(ID,this);
}
public Vector3f GetPositionOffset(){
return PositionOffset;
}
public Actor SetPositionOffset(Vector3f PositionOffset){
this.PositionOffset.set(PositionOffset);
return this;
}
public Actor SetPositionOffset(float x, float y, float z){
this.PositionOffset.set(x,y,z);
return this;
}
public Vector3f GetAditionalPivotOffset(){return AdditionalPivotOffset;}
public Actor SetAditionalPivotOffset(Vector3f offset){
@ -75,6 +91,10 @@ public class Actor{
return this;
}
public void TickUpdate() {
}
public IPhysicsController GetPhysicsController(){return physicsController;}
public Actor CreatePhysicsController(ConvexMesh mesh, float Mass){
@ -106,6 +126,13 @@ public class Actor{
UpdateModelMatrix();
return this;
}
public Actor SetRotMatrix(Vector3f rot){
Rotation.set(0,0,0,1.0f);
SetRotation(rot);
return this;
}
public Actor SetRotation(Vector3f rot){
Rotation.rotateX(rot.x);
Rotation.rotateY(rot.y);
@ -146,7 +173,8 @@ public class Actor{
public void UpdateModelMatrix(){
ModelMatrix.translateLocal(TemporaryVector.set(PivotOffset).add(AdditionalPivotOffset));
ModelMatrix.translationRotateScale(Position, Rotation, Scale);
ModelMatrix.translationRotateScale(new Vector3f(Position), Rotation, Scale);
ModelMatrix.translate(PositionOffset);
ModelMatrix.translateLocal(TemporaryVector.negate());
}

View file

@ -4,7 +4,12 @@ import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
import org.joml.Matrix4f;
import org.joml.Vector3f;
import java.util.HashMap;
import java.util.Map;
public class Camera {
public static final Map<String, Camera> CameraRegistry = new HashMap<>();
private final Vector3f Direction;
private final Vector3f Position;
private final Vector3f Right;
@ -13,12 +18,13 @@ public class Camera {
private final Matrix4f ViewMatrix;
private float FOV = (float) (60 * EngineConfig.DegToRad);
private boolean Sprint;
private final String ID;
public Vector3f GetDirection(){
return Direction;
}
public Camera CloneCamera(){
Camera NewCam = new Camera();
public Camera CloneCamera(String CameraName){
Camera NewCam = new Camera(CameraName);
NewCam.SetPosition(Position.x, Position.y, Position.z);
NewCam.SetRotation(Rotation.x, Rotation.y, Rotation.z);
NewCam.Right.set(new Vector3f(Right));
@ -29,13 +35,23 @@ public class Camera {
return NewCam;
}
public Camera(){
public static Camera GetCamera(String CameraID){
return CameraRegistry.get(CameraID);
}
public String GetID(){
return ID;
}
public Camera(String CameraName){
Direction = new Vector3f();
Position = new Vector3f();
Right = new Vector3f();
Rotation = new Vector3f();
Up = new Vector3f();
ViewMatrix = new Matrix4f();
ID = CameraName;
CameraRegistry.put(CameraName,this);
}
public Camera SetFOVrad(float FOVradians){

View file

@ -0,0 +1,70 @@
package net.halbear.Terrain4J.EngineCore.Main.Scene;
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
import net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody.ConvexMesh;
import net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody.RigidBody;
import net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody.RigidPhysicsController;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import org.tinylog.Logger;
public class PlayerActor extends Actor{
public String AttachedCameraID;
public final Vector3f CameraOffset = new Vector3f(0,0,0);
Camera PlayerCam;
public PlayerActor(String AttachedCameraID, String ID, String ModelID, Vector3f Position) {
this.AttachedCameraID = AttachedCameraID;
PlayerCam = Camera.CameraRegistry.get(AttachedCameraID);
super(ID, ModelID, Position);
}
@Override
public Actor CreatePhysicsController(ConvexMesh mesh, float Mass){
super.CreatePhysicsController(mesh,Mass);
RigidPhysicsController controller = (RigidPhysicsController)GetPhysicsController();
controller.ApplyRotation = false;
return this;
}
public PlayerActor SetCameraOffset(Vector3f Offset){
CameraOffset.set(Offset);
return this;
}
@Override
public void TickUpdate(){
Vector3f Rotation = PlayerCam.GetRotation();
Vector3f Position = new Vector3f(GetPosition());
GetRotation().identity().rotateYXZ(-Rotation.y, -Rotation.x, Rotation.z);
UpdateModelMatrix();
if(Position == null || CameraOffset == null) return;
Position.add(CameraOffset);
PlayerCam.SetPosition(Position.x, Position.y, Position.z);
}
public void Move(Vector3f Velocity){
if(PhysicsType == PhysicsControllerType.RigidBodySeparatingAxisTheory) {
RigidPhysicsController physicsController = (RigidPhysicsController) GetPhysicsController();
RigidBody.RigidBodyRegister.get(physicsController.RigidBodyID).LinearVelocity.add(Velocity);
}
}
/* @Override
public void UpdateModelMatrix(){
if(PlayerCam != null){
Vector3f Rotation = PlayerCam.GetRotation();
Vector3f Position = new Vector3f(GetPosition());
SetRotMatrix(new Vector3f(Rotation.x,Rotation.y,Rotation.z));
super.UpdateModelMatrix();
if(Position == null || CameraOffset == null) return;
Position.add(CameraOffset);
PlayerCam.SetPosition(Position.x, Position.y, Position.z);
} else{
super.UpdateModelMatrix();
}
}*/
}

View file

@ -81,7 +81,7 @@ public class Scene implements IScene {
ActiveActors = new ArrayList<>();
CameraFrames = new HashMap<>();
var EngConfig = EngineConfig.getInstance();
camera = new Camera();
camera = new Camera("DebugCamera");
LastCameraFrame = new CameraFrame(camera.GetPosition(),camera.GetRotation(),camera.GetFOV(), "NO_FRAME");
Projection = new Project3D(camera.GetFOV(),EngConfig.GetZNearPlane(), EngConfig.GetZFarPlane(),
window.getWidth(), window.getHeight());