Terrain chunk physics

This commit is contained in:
austin 2023-04-24 18:16:39 -04:00
parent 703f42f8e7
commit 72d1f8ac91
6 changed files with 318 additions and 61 deletions

View File

@ -1,8 +1,13 @@
package electrosphere.entity.types.terrain; package electrosphere.entity.types.terrain;
import org.joml.Vector3d;
import org.joml.Vector3f;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.entity.Entity; import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils; import electrosphere.entity.EntityUtils;
import electrosphere.game.client.terrain.manager.ClientTerrainManager;
import electrosphere.game.collision.PhysicsUtils;
import electrosphere.renderer.Model; import electrosphere.renderer.Model;
import electrosphere.renderer.meshgen.TerrainChunkModelGeneration; import electrosphere.renderer.meshgen.TerrainChunkModelGeneration;
@ -79,11 +84,81 @@ public class TerrainChunk {
}, },
}; };
String modelPath = Globals.clientTerrainManager.queueTerrainGridGeneration(terrainGrid); int[][][] textureGrid = new int[][][]{
//plane 1
{
//row 1
{0, 0, 0, 0, 0},
//row 2
{0, 0, 0, 0, 0},
//row 3
{0, 0, 0, 0, 0},
//row 4
{0, 0, 0, 0, 0},
//row 5
{0, 0, 0, 0, 0},
},
//plane 2
{
//row 1
{0, 0, 0, 0, 0},
//row 2
{0, 0, 0, 0, 0},
//row 3
{0, 0, 0, 0, 0},
//row 4
{0, 0, 0, 0, 0},
//row 5
{0, 0, 0, 0, 0},
},
//plane 3
{
//row 1
{0, 0, 0, 0, 0},
//row 2
{0, 0, 0, 0, 0},
//row 3
{0, 0, 0, 0, 0},
//row 4
{0, 0, 0, 0, 0},
//row 5
{0, 0, 0, 0, 0},
},
//plane 4
{
//row 1
{0, 0, 0, 0, 0},
//row 2
{0, 0, 0, 0, 0},
//row 3
{0, 0, 0, 0, 0},
//row 4
{0, 0, 0, 0, 0},
//row 5
{0, 0, 0, 0, 0},
},
//plane 5
{
//row 1
{0, 0, 0, 0, 0},
//row 2
{0, 0, 0, 0, 0},
//row 3
{0, 0, 0, 0, 0},
//row 4
{0, 0, 0, 0, 0},
//row 5
{0, 0, 0, 0, 0},
},
};
TerrainChunkData data = TerrainChunkModelGeneration.generateTerrainChunkData(terrainGrid, textureGrid);
String modelPath = ClientTerrainManager.queueTerrainGridGeneration(data);
Entity rVal = EntityUtils.spawnDrawableEntityWithPreexistingModel(modelPath); Entity rVal = EntityUtils.spawnDrawableEntityWithPreexistingModel(modelPath);
PhysicsUtils.attachTerrainChunkRigidBody(rVal, data);
EntityUtils.getPosition(rVal).set(1,-1,1); EntityUtils.repositionEntity(rVal, new Vector3d(1,-1,1));
return rVal; return rVal;
} }

View File

@ -0,0 +1,35 @@
package electrosphere.entity.types.terrain;
import java.util.List;
public class TerrainChunkData {
List<Float> vertices;
List<Float> normals;
List<Integer> faceElements;
List<Float> uvs;
public TerrainChunkData(List<Float> vertices, List<Float> normals, List<Integer> faceElements, List<Float> uvs){
this.vertices = vertices;
this.normals = normals;
this.faceElements = faceElements;
this.uvs = uvs;
}
public List<Float> getVertices(){
return vertices;
}
public List<Float> getNormals(){
return normals;
}
public List<Integer> getFaceElements(){
return faceElements;
}
public List<Float> getUVs(){
return uvs;
}
}

View File

@ -1,6 +1,7 @@
package electrosphere.game.client.terrain.manager; package electrosphere.game.client.terrain.manager;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.entity.types.terrain.TerrainChunkData;
import electrosphere.game.client.terrain.cache.ClientTerrainCache; import electrosphere.game.client.terrain.cache.ClientTerrainCache;
import electrosphere.game.client.terrain.cache.LoadingChunk; import electrosphere.game.client.terrain.cache.LoadingChunk;
import electrosphere.game.client.terrain.cache.LoadingChunkCache; import electrosphere.game.client.terrain.cache.LoadingChunkCache;
@ -219,19 +220,18 @@ public class ClientTerrainManager {
} }
} }
public static String queueTerrainGridGeneration(float[][][] terrainGrid){ public static String queueTerrainGridGeneration(TerrainChunkData data){
String promisedHash = ""; String promisedHash = "";
UUID newUUID = UUID.randomUUID(); UUID newUUID = UUID.randomUUID();
promisedHash = newUUID.toString(); promisedHash = newUUID.toString();
TerrainChunkGenQueueItem queueItem = new TerrainChunkGenQueueItem(terrainGrid, promisedHash); TerrainChunkGenQueueItem queueItem = new TerrainChunkGenQueueItem(data, promisedHash);
terrainChunkGenerationQueue.add(queueItem); terrainChunkGenerationQueue.add(queueItem);
return promisedHash; return promisedHash;
} }
public static void generateTerrainChunkGeometry(){ public static void generateTerrainChunkGeometry(){
for(TerrainChunkGenQueueItem queueItem : terrainChunkGenerationQueue){ for(TerrainChunkGenQueueItem queueItem : terrainChunkGenerationQueue){
System.out.println(queueItem); Model terrainModel = TerrainChunkModelGeneration.generateTerrainModel(queueItem.getData());
Model terrainModel = TerrainChunkModelGeneration.generateTerrainModel(queueItem.getTerrainGrid());
Globals.assetManager.registerModelToSpecificString(terrainModel, queueItem.getPromisedHash()); Globals.assetManager.registerModelToSpecificString(terrainModel, queueItem.getPromisedHash());
} }
terrainChunkGenerationQueue.clear(); terrainChunkGenerationQueue.clear();

View File

@ -1,17 +1,19 @@
package electrosphere.game.client.terrain.manager; package electrosphere.game.client.terrain.manager;
import electrosphere.entity.types.terrain.TerrainChunkData;
public class TerrainChunkGenQueueItem { public class TerrainChunkGenQueueItem {
float[][][] terrainGrid; TerrainChunkData data;
String promisedHash; String promisedHash;
public TerrainChunkGenQueueItem(float[][][] terrainGrid, String promisedHash){ public TerrainChunkGenQueueItem(TerrainChunkData data, String promisedHash){
this.terrainGrid = terrainGrid; this.data = data;
this.promisedHash = promisedHash; this.promisedHash = promisedHash;
} }
public float[][][] getTerrainGrid(){ public TerrainChunkData getData(){
return this.terrainGrid; return data;
} }
public String getPromisedHash(){ public String getPromisedHash(){

View File

@ -14,6 +14,7 @@ import electrosphere.linearmath.Transform;
import electrosphere.entity.Entity; import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityUtils; import electrosphere.entity.EntityUtils;
import electrosphere.entity.types.terrain.TerrainChunkData;
import electrosphere.game.collision.collidable.Collidable; import electrosphere.game.collision.collidable.Collidable;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@ -136,6 +137,110 @@ public class PhysicsUtils {
//http://jbullet.advel.cz/javadoc/com/bulletphysics/collision/shpaes/TriangleIndexVertexArray.html
electrosphere.collision.shapes.TriangleIndexVertexArray triangleIndexArray = new electrosphere.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
electrosphere.collision.shapes.BvhTriangleMeshShape terrainShape = new electrosphere.collision.shapes.BvhTriangleMeshShape(
triangleIndexArray,
true // "useQuantizedAabbCompression" -- apparently means better memory usage ( http://jbullet.advel.cz/javadoc/com/bulletphysics/collision/shapes/BvhTriangleMeshShape.html )
);
//uncomment if we start falling through things again
terrainShape.setMargin(collisionMargin);
// 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((float)position.x,(float)position.y,(float)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 RigidBody attachTerrainChunkRigidBody(Entity terrain, TerrainChunkData data){
Vector3d position = EntityUtils.getPosition(terrain);
float collisionMargin = 0.08f;
/*
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 = data.getFaceElements().size() / 3;
int triangleStride = 0;
int numberVertices = data.getVertices().size() / 3;
int vertexStride = 0;
float[] vertices = new float[numberVertices * 3];
int vertexInserterPos = 0;
int[] indices = new int[numberTriangles * 3];
int indexInserterPos = 0;
for(float vertexValue : data.getVertices()){
vertices[vertexInserterPos] = vertexValue;
vertexInserterPos++;
}
for(int element : data.getFaceElements()){
indices[indexInserterPos] = element;
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
electrosphere.collision.shapes.IndexedMesh indexedMesh = new electrosphere.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 //http://jbullet.advel.cz/javadoc/com/bulletphysics/collision/shpaes/TriangleIndexVertexArray.html
electrosphere.collision.shapes.TriangleIndexVertexArray triangleIndexArray = new electrosphere.collision.shapes.TriangleIndexVertexArray(); electrosphere.collision.shapes.TriangleIndexVertexArray triangleIndexArray = new electrosphere.collision.shapes.TriangleIndexVertexArray();
triangleIndexArray.addIndexedMesh(indexedMesh); //this assumes the scalar type is integer (assumes bytebuffer is actually integer triangleIndexArray.addIndexedMesh(indexedMesh); //this assumes the scalar type is integer (assumes bytebuffer is actually integer

View File

@ -20,6 +20,7 @@ import static org.lwjgl.opengl.GL30.glBindVertexArray;
import static org.lwjgl.opengl.GL30.glGenVertexArrays; import static org.lwjgl.opengl.GL30.glGenVertexArrays;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.entity.types.terrain.TerrainChunkData;
import electrosphere.renderer.Material; import electrosphere.renderer.Material;
import electrosphere.renderer.Mesh; import electrosphere.renderer.Mesh;
import electrosphere.renderer.Model; import electrosphere.renderer.Model;
@ -542,19 +543,7 @@ public class TerrainChunkModelGeneration {
return new Vector3f(x,y,z); return new Vector3f(x,y,z);
} }
public static TerrainChunkData generateTerrainChunkData(float[][][] terrainGrid, int[][][] textureGrid){
protected static Mesh generateTerrainMesh(float[][][] terrainGrid){
Mesh mesh = new Mesh();
mesh.mesh = null;
//
// VAO
//
mesh.vertexArrayObject = glGenVertexArrays();
glBindVertexArray(mesh.vertexArrayObject);
// 5 6 // 5 6
// +-------------+ +-----5-------+ ^ Y // +-------------+ +-----5-------+ ^ Y
@ -578,6 +567,10 @@ public class TerrainChunkModelGeneration {
List<Vector3f> normals = new LinkedList<Vector3f>(); List<Vector3f> normals = new LinkedList<Vector3f>();
//the list of number of triangles that share a vert //the list of number of triangles that share a vert
List<Integer> trianglesSharingVert = new LinkedList<Integer>(); List<Integer> trianglesSharingVert = new LinkedList<Integer>();
//List of elements in order
List<Integer> faceElements = new LinkedList<Integer>();
//List of UVs
List<Float> UVs = new LinkedList<Float>();
@ -597,6 +590,72 @@ public class TerrainChunkModelGeneration {
} }
} }
//all verts in order, flattened as an array of floats instead of vecs
List<Float> vertsFlat = new LinkedList<Float>();
//all normals in order, flattened as an array of floats instead of vecs
List<Float> normalsFlat = new LinkedList<Float>();
//all elements of faces in order
List<Integer> elementsFlat = new LinkedList<Integer>();
//flatten verts + normals
for(Vector3f vert : verts){
vertsFlat.add(vert.x);
vertsFlat.add(vert.y);
vertsFlat.add(vert.z);
}
for(Vector3f normal : normals){
normalsFlat.add(normal.x);
normalsFlat.add(normal.y);
normalsFlat.add(normal.z);
}
for(Triangle triangle : triangles){
elementsFlat.add(triangle.indices[0]);
elementsFlat.add(triangle.indices[1]);
elementsFlat.add(triangle.indices[2]);
}
float[] temp = new float[3];
for(Vector3f normal : normals){
float absX = Math.abs(normal.x);
float absY = Math.abs(normal.y);
float absZ = Math.abs(normal.z);
if(absX >= absZ && absX >= absY){
temp[0] = normal.z / 2.0f + 0.5f;
temp[1] = normal.y / 2.0f + 0.5f;
} else if(absZ >= absX && absZ >= absY){
temp[0] = normal.x / 2.0f + 0.5f;
temp[1] = normal.y / 2.0f + 0.5f;
} else if(absY >= absX && absY >= absZ){
temp[0] = normal.x / 2.0f + 0.5f;
temp[1] = normal.z / 2.0f + 0.5f;
}
UVs.add(temp[0]);
UVs.add(temp[1]);
}
//List<Float> vertices, List<Float> normals, List<Integer> faceElements, List<Float> uvs
TerrainChunkData rVal = new TerrainChunkData(vertsFlat, normalsFlat, elementsFlat, UVs);
return rVal;
}
protected static Mesh generateTerrainMesh(TerrainChunkData data){
Mesh mesh = new Mesh();
mesh.mesh = null;
//
// VAO
//
mesh.vertexArrayObject = glGenVertexArrays();
glBindVertexArray(mesh.vertexArrayObject);
@ -606,14 +665,11 @@ public class TerrainChunkModelGeneration {
// //
try { try {
mesh.vertexCount = verts.size(); mesh.vertexCount = data.getVertices().size() / 3;
FloatBuffer VertexArrayBufferData = BufferUtils.createFloatBuffer(mesh.vertexCount * 3); FloatBuffer VertexArrayBufferData = BufferUtils.createFloatBuffer(mesh.vertexCount * 3);
float[] temp = new float[3]; float[] temp = new float[3];
for(Vector3f vert : verts){ for(float vertValue : data.getVertices()){
temp[0] = vert.x; VertexArrayBufferData.put(vertValue);
temp[1] = vert.y;
temp[2] = vert.z;
VertexArrayBufferData.put(temp);
} }
VertexArrayBufferData.flip(); VertexArrayBufferData.flip();
mesh.buffer_vertices(VertexArrayBufferData, 3); mesh.buffer_vertices(VertexArrayBufferData, 3);
@ -626,13 +682,13 @@ public class TerrainChunkModelGeneration {
// //
// FACES // FACES
// //
mesh.faceCount = triangles.size(); mesh.faceCount = data.getFaceElements().size() / 3;
mesh.elementCount = triangles.size() * 3; mesh.elementCount = data.getFaceElements().size();
try { try {
IntBuffer elementArrayBufferData = BufferUtils.createIntBuffer(mesh.elementCount); IntBuffer elementArrayBufferData = BufferUtils.createIntBuffer(mesh.elementCount);
int[] temp = new int[3]; int[] temp = new int[3];
for(Triangle triangle : triangles){ for(int element : data.getFaceElements()){
elementArrayBufferData.put(triangle.indices); elementArrayBufferData.put(element);
} }
elementArrayBufferData.flip(); elementArrayBufferData.flip();
mesh.buffer_faces(elementArrayBufferData); mesh.buffer_faces(elementArrayBufferData);
@ -647,16 +703,13 @@ public class TerrainChunkModelGeneration {
// NORMALS // NORMALS
// //
try { try {
mesh.normalCount = normals.size(); mesh.normalCount = data.getNormals().size() / 3;
FloatBuffer NormalArrayBufferData; FloatBuffer NormalArrayBufferData;
if(mesh.normalCount > 0){ if(mesh.normalCount > 0){
NormalArrayBufferData = BufferUtils.createFloatBuffer(mesh.normalCount * 3); NormalArrayBufferData = BufferUtils.createFloatBuffer(mesh.normalCount * 3);
float[] temp = new float[3]; float[] temp = new float[3];
for(Vector3f normal : normals){ for(float normalValue : data.getNormals()){
temp[0] = normal.x; NormalArrayBufferData.put(normalValue);
temp[1] = normal.y;
temp[2] = normal.z;
NormalArrayBufferData.put(temp);
} }
NormalArrayBufferData.flip(); NormalArrayBufferData.flip();
mesh.buffer_normals(NormalArrayBufferData, 3); mesh.buffer_normals(NormalArrayBufferData, 3);
@ -669,26 +722,13 @@ public class TerrainChunkModelGeneration {
// TEXTURE COORDINATES // TEXTURE COORDINATES
// //
try { try {
mesh.textureCoordCount = normals.size(); mesh.textureCoordCount = data.getUVs().size() / 2;
FloatBuffer TextureArrayBufferData; FloatBuffer TextureArrayBufferData;
if(mesh.textureCoordCount > 0){ if(mesh.textureCoordCount > 0){
TextureArrayBufferData = BufferUtils.createFloatBuffer(mesh.textureCoordCount * 2); TextureArrayBufferData = BufferUtils.createFloatBuffer(mesh.textureCoordCount * 2);
float[] temp = new float[2]; float[] temp = new float[2];
for(Vector3f normal : normals){ for(float uvValue : data.getUVs()){
float absX = Math.abs(normal.x); TextureArrayBufferData.put(uvValue);
float absY = Math.abs(normal.y);
float absZ = Math.abs(normal.z);
if(absX >= absZ && absX >= absY){
temp[0] = normal.z / 2.0f + 0.5f;
temp[1] = normal.y / 2.0f + 0.5f;
} else if(absZ >= absX && absZ >= absY){
temp[0] = normal.x / 2.0f + 0.5f;
temp[1] = normal.y / 2.0f + 0.5f;
} else if(absY >= absX && absY >= absZ){
temp[0] = normal.x / 2.0f + 0.5f;
temp[1] = normal.z / 2.0f + 0.5f;
}
TextureArrayBufferData.put(temp);
} }
TextureArrayBufferData.flip(); TextureArrayBufferData.flip();
mesh.buffer_texture_coords(TextureArrayBufferData, 2); mesh.buffer_texture_coords(TextureArrayBufferData, 2);
@ -707,10 +747,10 @@ public class TerrainChunkModelGeneration {
public static Model generateTerrainModel(float[][][] terrainGrid){ public static Model generateTerrainModel(TerrainChunkData data){
Model rVal = new Model(); Model rVal = new Model();
rVal.meshes = new ArrayList<Mesh>(); rVal.meshes = new ArrayList<Mesh>();
Mesh m = generateTerrainMesh(terrainGrid); Mesh m = generateTerrainMesh(data);
Material groundMat = new Material(); Material groundMat = new Material();