package electrosphere.game.collision; import com.bulletphysics.collision.dispatch.CollisionObject; import com.bulletphysics.collision.shapes.BoxShape; import com.bulletphysics.collision.shapes.BvhTriangleMeshShape; import com.bulletphysics.collision.shapes.CylinderShape; import com.bulletphysics.collision.shapes.IndexedMesh; import com.bulletphysics.collision.shapes.TriangleIndexVertexArray; import com.bulletphysics.dynamics.RigidBody; import com.bulletphysics.dynamics.RigidBodyConstructionInfo; import com.bulletphysics.linearmath.DefaultMotionState; import com.bulletphysics.linearmath.Transform; import electrosphere.entity.Entity; import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityUtils; import electrosphere.game.collision.collidable.Collidable; import electrosphere.main.Globals; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import java.nio.IntBuffer; import org.joml.Quaternionf; import org.joml.Vector3f; /** * * @author amaterasu */ public class PhysicsUtils { /** * Constructor for rigid body: * http://jbullet.advel.cz/javadoc/com/bulletphysics/collision/shapes/CylinderShape.html * Creates a sphere where the dimensions are twice the size of the vector passed in * ie diameter = x * 2 or z * 2 * @param entity * @param halfDimensions */ public static void attachCylinderRigidBody(Entity entity, Vector3f halfDimensions){ new com.bulletphysics.collision.shapes.CylinderShape(new javax.vecmath.Vector3f(halfDimensions.x,halfDimensions.y,halfDimensions.z)); } public static RigidBody attachTerrainRigidBody(Entity terrain, float[][] heightfield){ Vector3f position = EntityUtils.getPosition(terrain); int arrayLength = heightfield.length; int arrayWidth = heightfield[0].length; /* Traditional buffer code not working for some reason the approach of https://stackoverflow.com/questions/40855945/lwjgl-mesh-to-jbullet-collider works much better IDK why */ int numberTriangles = (arrayLength - 1) * (arrayWidth - 1) * 2; int triangleStride = 0; int numberVertices = arrayLength * arrayWidth; int vertexStride = 0; float[] vertices = new float[numberVertices * 3]; int vertexInserterPos = 0; int[] indices = new int[numberTriangles * 3]; int indexInserterPos = 0; for(int x = 0; x < arrayLength; x++){ for(int y = 0; y < arrayWidth; y++){ vertices[vertexInserterPos] = x; vertexInserterPos++; vertices[vertexInserterPos] = heightfield[x][y]; vertexInserterPos++; vertices[vertexInserterPos] = y; vertexInserterPos++; if(x < arrayLength - 1 && y < arrayWidth - 1){ //if we should also add a triangle index /* as copied from ModelUtil's terrain mesh generation function faces.put((x / stride + 0) * actualHeight + (y / stride + 0)); faces.put((x / stride + 0) * actualHeight + (y / stride + 1)); faces.put((x / stride + 1) * actualHeight + (y / stride + 0)); faces.put((x / stride + 1) * actualHeight + (y / stride + 0)); faces.put((x / stride + 0) * actualHeight + (y / stride + 1)); faces.put((x / stride + 1) * actualHeight + (y / stride + 1)); */ indices[indexInserterPos] = (x + 0) * arrayWidth + (y + 0); indexInserterPos++; indices[indexInserterPos] = (x + 0) * arrayWidth + (y + 1); indexInserterPos++; indices[indexInserterPos] = (x + 1) * arrayWidth + (y + 0); indexInserterPos++; indices[indexInserterPos] = (x + 1) * arrayWidth + (y + 0); indexInserterPos++; indices[indexInserterPos] = (x + 0) * arrayWidth + (y + 1); indexInserterPos++; indices[indexInserterPos] = (x + 1) * arrayWidth + (y + 1); indexInserterPos++; } } } javax.vecmath.Vector3f aabbMin = new javax.vecmath.Vector3f(); javax.vecmath.Vector3f aabbMax = new javax.vecmath.Vector3f(); //http://jbullet.advel.cz/javadoc/com/bulletphysics/collision/shapes/IndexedMesh.html com.bulletphysics.collision.shapes.IndexedMesh indexedMesh = new com.bulletphysics.collision.shapes.IndexedMesh(); indexedMesh.numTriangles = indices.length / 3; indexedMesh.triangleIndexBase = ByteBuffer.allocateDirect(indices.length*Float.BYTES).order(ByteOrder.nativeOrder()); indexedMesh.triangleIndexBase.asIntBuffer().put(indices); indexedMesh.triangleIndexStride = 3 * Float.BYTES; indexedMesh.numVertices = vertices.length / 3; indexedMesh.vertexBase = ByteBuffer.allocateDirect(vertices.length*Float.BYTES).order(ByteOrder.nativeOrder()); indexedMesh.vertexBase.asFloatBuffer().put(vertices); indexedMesh.vertexStride = 3 * Float.BYTES; //http://jbullet.advel.cz/javadoc/com/bulletphysics/collision/shpaes/TriangleIndexVertexArray.html com.bulletphysics.collision.shapes.TriangleIndexVertexArray triangleIndexArray = new com.bulletphysics.collision.shapes.TriangleIndexVertexArray(); triangleIndexArray.addIndexedMesh(indexedMesh); //this assumes the scalar type is integer (assumes bytebuffer is actually integer // triangleIndexArray.calculateAabbBruteForce(aabbMin, aabbMax); //http://jbullet.advel.cz/javadoc/com/bulletphysics/collision/shapes/BvhTriangleMeshShape.html com.bulletphysics.collision.shapes.BvhTriangleMeshShape terrainShape = new com.bulletphysics.collision.shapes.BvhTriangleMeshShape( triangleIndexArray, true // "useQuantizedAabbCompression" -- apparently means better memory usage ( http://jbullet.advel.cz/javadoc/com/bulletphysics/collision/shapes/BvhTriangleMeshShape.html ) ); // terrainShape.localGetSupportingVertex(new javax.vecmath.Vector3f(1,0,0), aabbMin); // terrainShape.recalcLocalAabb(); // terrainShape.getLocalAabbMin(aabbMin); // terrainShape.getLocalAabbMax(aabbMax); DefaultMotionState defaultMotionState = new DefaultMotionState(new Transform(new javax.vecmath.Matrix4f(new javax.vecmath.Quat4f(0,0,0,1),new javax.vecmath.Vector3f(position.x,position.y,position.z),1.0f))); RigidBodyConstructionInfo terrainRigidBodyCI = new RigidBodyConstructionInfo(0, defaultMotionState, terrainShape); RigidBody terrainRigidBody = new RigidBody(terrainRigidBodyCI); terrainRigidBody.setFriction(1f); Globals.collisionEngine.registerCollisionObject(terrainRigidBody, new Collidable(terrain,Collidable.TYPE_TERRAIN)); // terrainRigidBody.getAabb(aabbMin, aabbMax); // System.out.println("aabbMin: " + aabbMin + " aabbMax: " + aabbMax); terrain.putData(EntityDataStrings.PHYSICS_COLLISION_BODY, terrainRigidBody); return terrainRigidBody; } public static void addTestPlaneRigidBody(){ /* Traditional buffer code not working for some reason the approach of https://stackoverflow.com/questions/40855945/lwjgl-mesh-to-jbullet-collider works much better IDK why */ int[] indices = { 0, 1, 3, 1, 2, 3 }; float[] coords = { 0, 0, 0, 100, 0, 0, 0, 0, 100, 100, 0, 100 }; IndexedMesh indexedMesh = new IndexedMesh(); indexedMesh.numTriangles = indices.length / 3; indexedMesh.triangleIndexBase = ByteBuffer.allocateDirect(indices.length*Float.BYTES).order(ByteOrder.nativeOrder()); indexedMesh.triangleIndexBase.asIntBuffer().put(indices); indexedMesh.triangleIndexStride = 3 * Float.BYTES; indexedMesh.numVertices = coords.length / 3; indexedMesh.vertexBase = ByteBuffer.allocateDirect(coords.length*Float.BYTES).order(ByteOrder.nativeOrder()); indexedMesh.vertexBase.asFloatBuffer().put(coords); indexedMesh.vertexStride = 3 * Float.BYTES; javax.vecmath.Vector3f aabbMin = new javax.vecmath.Vector3f(); javax.vecmath.Vector3f aabbMax = new javax.vecmath.Vector3f(); //http://jbullet.advel.cz/javadoc/com/bulletphysics/collision/shpaes/TriangleIndexVertexArray.html com.bulletphysics.collision.shapes.TriangleIndexVertexArray triangleIndexArray = new com.bulletphysics.collision.shapes.TriangleIndexVertexArray( // numberTriangles, // triangleData, // triangleStride, // numberVertices, // vertexData, // vertexStride ); triangleIndexArray.addIndexedMesh(indexedMesh); // triangleIndexArray.setScaling(new javax.vecmath.Vector3f(1.0f,1.0f,1.0f)); //http://jbullet.advel.cz/javadoc/com/bulletphysics/collision/shapes/BvhTriangleMeshShape.html com.bulletphysics.collision.shapes.BvhTriangleMeshShape terrainShape = new com.bulletphysics.collision.shapes.BvhTriangleMeshShape( triangleIndexArray, true // "useQuantizedAabbCompression" -- apparently means better memory usage ( http://jbullet.advel.cz/javadoc/com/bulletphysics/collision/shapes/BvhTriangleMeshShape.html ) ); DefaultMotionState defaultMotionState = new DefaultMotionState(new Transform(new javax.vecmath.Matrix4f(new javax.vecmath.Quat4f(0,0,0,1),new javax.vecmath.Vector3f(0,0,0),1.0f))); RigidBodyConstructionInfo terrainRigidBodyCI = new RigidBodyConstructionInfo(0, defaultMotionState, terrainShape); RigidBody terrainRigidBody = new RigidBody(terrainRigidBodyCI); // Globals.collisionEngine.registerCollisionObject(terrainRigidBody, new Collidable(terrain,Collidable.TYPE_TERRAIN)); terrainRigidBody.getAabb(aabbMin, aabbMax); } public static Vector3f getRigidBodyPosition(CollisionObject body){ javax.vecmath.Vector3f transform = new javax.vecmath.Vector3f(0,0,0); body.getWorldTransform(new com.bulletphysics.linearmath.Transform()).transform(transform); // body.getMotionState().getWorldTransform(new com.bulletphysics.linearmath.Transform()).transform(transform); return vecmathToJomlVector3f(transform); } public static Quaternionf getRigidBodyRotation(RigidBody body){ return vecmathtoJomlQuaternionf(body.getMotionState().getWorldTransform(new com.bulletphysics.linearmath.Transform()).getRotation(new javax.vecmath.Quat4f())); } public static Vector3f vecmathToJomlVector3f(javax.vecmath.Vector3f vector){ return new Vector3f(vector.x,vector.y,vector.z); } public static Quaternionf vecmathtoJomlQuaternionf(javax.vecmath.Quat4f quaternion){ return new Quaternionf(quaternion.x, quaternion.y, quaternion.z, quaternion.w); } public static javax.vecmath.Vector3f jomlToVecmathVector3f(Vector3f vector){ return new javax.vecmath.Vector3f(vector.x, vector.y, vector.z); } public static javax.vecmath.Quat4f jomlToVecmathQuaternionf(Quaternionf quaternion){ return new javax.vecmath.Quat4f(quaternion.x, quaternion.y, quaternion.z, quaternion.w); } public static com.bulletphysics.linearmath.Transform jomlVecToTransform(Vector3f vector){ com.bulletphysics.linearmath.Transform transform = new com.bulletphysics.linearmath.Transform(); javax.vecmath.Matrix4f transformMatrix = new javax.vecmath.Matrix4f(); transformMatrix.setIdentity(); transformMatrix.setTranslation(new javax.vecmath.Vector3f(vector.x, vector.y, vector.z)); transform.set(transformMatrix); return transform; } public static void setRigidBodyTransform(Vector3f position, Quaternionf rotation, CollisionObject body){ com.bulletphysics.linearmath.Transform transform = new com.bulletphysics.linearmath.Transform(); javax.vecmath.Matrix4f transformMatrix = new javax.vecmath.Matrix4f(); transformMatrix.setIdentity(); transformMatrix.setTranslation(new javax.vecmath.Vector3f(position.x, position.y, position.z)); transformMatrix.setRotation(new javax.vecmath.Quat4f(rotation.x,rotation.y,rotation.z,rotation.w)); transform.set(transformMatrix); //https://docs.oracle.com/cd/E17802_01/j2se/javase/technologies/desktop/java3d/forDevelopers/j3dapi/javax/vecmath/Quat4f.html //constructor is x,y,z,w // transform.setRotation(new javax.vecmath.Quat4f(rotation.x,rotation.y,rotation.z,rotation.w)); body.setWorldTransform(transform); } // public static RigidBody getUnitCylinderRigidBody(float mass){ // CylinderShape cylinderShape = new CylinderShape(jomlToVecmathVector3f(new Vector3f(1.0f,1.0f,1.0f))); // DefaultMotionState defaultMotionState = new DefaultMotionState(new Transform(new javax.vecmath.Matrix4f(new javax.vecmath.Quat4f(0,1,0,1),new javax.vecmath.Vector3f(0,0,0),1.0f))); // RigidBodyConstructionInfo cylinderRigidBodyCI = new RigidBodyConstructionInfo(mass, defaultMotionState, cylinderShape); // RigidBody cylinderRigidBody = new RigidBody(cylinderRigidBodyCI); //// cylinderRigidBody.setMassProps(mass, PhysicsUtils.jomlToVecmathVector3f(new Vector3f(1.0f,1.0f,1.0f))); // cylinderRigidBody.clearForces(); // return cylinderRigidBody; // } public static CollisionObject getCylinderBody(float mass, Vector3f dimensions){ CylinderShape cylinderShape = new CylinderShape(jomlToVecmathVector3f(dimensions)); // DefaultMotionState defaultMotionState = new DefaultMotionState(new Transform(new javax.vecmath.Matrix4f(new javax.vecmath.Quat4f(0,1,0,1),new javax.vecmath.Vector3f(0,0,0),1.0f))); // RigidBodyConstructionInfo cylinderRigidBodyCI = new RigidBodyConstructionInfo(mass, defaultMotionState, cylinderShape); // RigidBody cylinderRigidBody = new RigidBody(cylinderRigidBodyCI); CollisionObject cylinderCollisionObject = new CollisionObject(); cylinderCollisionObject.setCollisionShape(cylinderShape); // cylinderRigidBody.setAngularFactor(1.0f); // cylinderRigidBody.setFriction(0.8f); return cylinderCollisionObject; } public static CollisionObject getPlaneObject(Vector3f dimensions){ int[] indices = { 0, 1, 2, 1, 2, 3 }; float[] coords = { -1 * dimensions.x, 0, -1 * dimensions.z, 1 * dimensions.x, 0, -1 * dimensions.z, -1 * dimensions.x, 0, 1 * dimensions.z, 1 * dimensions.x, 0, 1 * dimensions.z }; IndexedMesh indexedMesh = new IndexedMesh(); indexedMesh.numTriangles = indices.length / 3; indexedMesh.triangleIndexBase = ByteBuffer.allocateDirect(indices.length*Float.BYTES).order(ByteOrder.nativeOrder()); indexedMesh.triangleIndexBase.asIntBuffer().put(indices); indexedMesh.triangleIndexStride = 3 * Float.BYTES; indexedMesh.numVertices = coords.length / 3; indexedMesh.vertexBase = ByteBuffer.allocateDirect(coords.length*Float.BYTES).order(ByteOrder.nativeOrder()); indexedMesh.vertexBase.asFloatBuffer().put(coords); indexedMesh.vertexStride = 3 * Float.BYTES; //http://jbullet.advel.cz/javadoc/com/bulletphysics/collision/shpaes/TriangleIndexVertexArray.html TriangleIndexVertexArray triangleIndexArray = new TriangleIndexVertexArray(); triangleIndexArray.addIndexedMesh(indexedMesh); // triangleIndexArray.setScaling(new javax.vecmath.Vector3f(1.0f,1.0f,1.0f)); //http://jbullet.advel.cz/javadoc/com/bulletphysics/collision/shapes/BvhTriangleMeshShape.html BvhTriangleMeshShape planeShape = new BvhTriangleMeshShape( triangleIndexArray, true // "useQuantizedAabbCompression" -- apparently means better memory usage ( http://jbullet.advel.cz/javadoc/com/bulletphysics/collision/shapes/BvhTriangleMeshShape.html ) ); CollisionObject planeCollisionObject = new CollisionObject(); planeCollisionObject.setCollisionShape(planeShape); return planeCollisionObject; } public static CollisionObject getCubeObject(Vector3f dimensions){ BoxShape boxShape = new BoxShape(jomlToVecmathVector3f(dimensions)); CollisionObject boxCollisionObject = new CollisionObject(); boxCollisionObject.setCollisionShape(boxShape); return boxCollisionObject; } }