fix block meshes
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good

This commit is contained in:
austin 2024-11-24 11:16:31 -05:00
parent 21e2ec7b06
commit e8c38584fa
11 changed files with 132 additions and 43 deletions

View File

@ -1150,6 +1150,10 @@ Add server manager for block chunk data & management
Add endpoint to request strided block data
Add client side handling of block endpoint
Add server-driven block rasterizer with LOD
Convert PhysicsEntityUtils to use generic interface to load tri geom rigid bodies
(11/24/2024)
Fix winding order on block meshes
# TODO

View File

@ -7,7 +7,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.ReentrantLock;
import io.github.studiorailgun.HashUtils;
@ -64,16 +64,16 @@ public class BlockChunkCache {
/**
* The lock for thread safety
*/
Semaphore lock = new Semaphore(1);
ReentrantLock lock = new ReentrantLock();
/**
* Gets the collection of server block chunks that are cached
* @return The collection of chunks
*/
public Collection<BlockChunkData> getContents(){
lock.acquireUninterruptibly();
lock.lock();
Collection<BlockChunkData> rVal = Collections.unmodifiableCollection(cacheMapFullRes.values());
lock.release();
lock.unlock();
return rVal;
}
@ -81,13 +81,13 @@ public class BlockChunkCache {
* Evicts all chunks in the cache
*/
public void clear(){
lock.acquireUninterruptibly();
lock.lock();
cacheMapFullRes.clear();
cacheMapHalfRes.clear();
cacheMapQuarterRes.clear();
cacheMapEighthRes.clear();
cacheMapSixteenthRes.clear();
lock.release();
lock.unlock();
}
/**
@ -101,12 +101,12 @@ public class BlockChunkCache {
public BlockChunkData get(int worldX, int worldY, int worldZ, int stride){
BlockChunkData rVal = null;
Long key = this.getKey(worldX, worldY, worldZ);
lock.acquireUninterruptibly();
lock.lock();
queryRecencyQueue.remove(key);
queryRecencyQueue.add(0, key);
Map<Long,BlockChunkData> cache = this.getCache(stride);
rVal = cache.get(key);
lock.release();
lock.unlock();
return rVal;
}
@ -120,7 +120,7 @@ public class BlockChunkCache {
*/
public void add(int worldX, int worldY, int worldZ, int stride, BlockChunkData chunk){
Long key = this.getKey(worldX, worldY, worldZ);
lock.acquireUninterruptibly();
lock.lock();
queryRecencyQueue.add(0, key);
Map<Long,BlockChunkData> cache = this.getCache(stride);
cache.put(key, chunk);
@ -132,7 +132,7 @@ public class BlockChunkCache {
cacheMapEighthRes.remove(oldKey);
cacheMapSixteenthRes.remove(oldKey);
}
lock.release();
lock.unlock();
}
/**
@ -145,10 +145,10 @@ public class BlockChunkCache {
*/
public boolean containsChunk(int worldX, int worldY, int worldZ, int stride){
Long key = this.getKey(worldX,worldY,worldZ);
lock.acquireUninterruptibly();
lock.lock();
Map<Long,BlockChunkData> cache = this.getCache(stride);
boolean rVal = cache.containsKey(key);
lock.release();
lock.unlock();
return rVal;
}
@ -172,9 +172,9 @@ public class BlockChunkCache {
*/
public boolean chunkIsQueued(int worldX, int worldY, int worldZ){
Long key = this.getKey(worldX,worldY,worldZ);
lock.acquireUninterruptibly();
lock.lock();
boolean rVal = this.queuedChunkMap.containsKey(key);
lock.release();
lock.unlock();
return rVal;
}
@ -186,9 +186,9 @@ public class BlockChunkCache {
*/
public void queueChunk(int worldX, int worldY, int worldZ){
Long key = this.getKey(worldX,worldY,worldZ);
lock.acquireUninterruptibly();
lock.lock();
this.queuedChunkMap.put(key,true);
lock.release();
lock.unlock();
}
/**
@ -200,9 +200,9 @@ public class BlockChunkCache {
*/
public void unqueueChunk(int worldX, int worldY, int worldZ, int stride){
Long key = this.getKey(worldX,worldY,worldZ);
lock.acquireUninterruptibly();
lock.lock();
this.queuedChunkMap.remove(key);
lock.release();
lock.unlock();
}
/**

View File

@ -19,7 +19,7 @@ import org.ode4j.ode.DMass;
import org.ode4j.ode.DSphere;
import org.ode4j.ode.DTriMesh;
import electrosphere.entity.types.terrain.TerrainChunkData;
import electrosphere.entity.state.collidable.TriGeomData;
/**
* Utilities for creating types of rigid bodies
@ -256,7 +256,7 @@ public class CollisionBodyCreation {
* @param data The terrain data
* @return The DBody
*/
public static DBody generateBodyFromTerrainData(CollisionEngine collisionEngine, TerrainChunkData data, long categoryBits){
public static DBody generateBodyFromTerrainData(CollisionEngine collisionEngine, TriGeomData data, long categoryBits){
DBody body = null;
//create trimesh

View File

@ -18,9 +18,9 @@ import electrosphere.entity.EntityUtils;
import electrosphere.entity.ServerEntityUtils;
import electrosphere.entity.state.collidable.ClientCollidableTree;
import electrosphere.entity.state.collidable.ServerCollidableTree;
import electrosphere.entity.state.collidable.TriGeomData;
import electrosphere.entity.state.physicssync.ClientPhysicsSyncTree;
import electrosphere.entity.state.physicssync.ServerPhysicsSyncTree;
import electrosphere.entity.types.terrain.TerrainChunkData;
import electrosphere.game.data.collidable.CollidableTemplate;
import electrosphere.game.server.world.ServerWorldData;
import electrosphere.server.datacell.Realm;
@ -487,7 +487,7 @@ public class PhysicsEntityUtils {
* @param data The terrain description
* @return The rigid body created (note, attachment has already been performed)
*/
public static void clientAttachTerrainChunkRigidBody(Entity terrain, TerrainChunkData data){
public static void clientAttachTriGeomRigidBody(Entity terrain, TriGeomData data){
DBody terrainBody = CollisionBodyCreation.generateBodyFromTerrainData(Globals.clientSceneWrapper.getCollisionEngine(), data, Collidable.TYPE_STATIC_BIT);
Collidable collidable = new Collidable(terrain,Collidable.TYPE_TERRAIN, false);
Globals.clientSceneWrapper.getCollisionEngine().registerCollisionObject(terrainBody, collidable);
@ -502,7 +502,7 @@ public class PhysicsEntityUtils {
* @param data The terrain description
* @return The rigid body created (note, attachment has already been performed)
*/
public static DBody serverAttachTerrainChunkRigidBody(Entity terrain, TerrainChunkData data){
public static DBody serverAttachTriGeomRigidBody(Entity terrain, TriGeomData data){
Realm terrainRealm = Globals.realmManager.getEntityRealm(terrain);
DBody terrainBody = CollisionBodyCreation.generateBodyFromTerrainData(terrainRealm.getCollisionEngine(),data,Collidable.TYPE_STATIC_BIT);

View File

@ -0,0 +1,20 @@
package electrosphere.entity.state.collidable;
/**
* A data object that can be used to generate a collidable with arbitrary geometry
*/
public interface TriGeomData {
/**
* Gets the vertex data
* @return the vertex data
*/
public float[] getVertices();
/**
* Gets the face element data
* @return the face element data
*/
public int[] getFaceElements();
}

View File

@ -9,6 +9,7 @@ import org.joml.Vector3d;
import electrosphere.client.block.BlockChunkData;
import electrosphere.client.block.cells.BlockDrawCell;
import electrosphere.client.block.cells.BlockTextureAtlas;
import electrosphere.collision.PhysicsEntityUtils;
import electrosphere.engine.Globals;
import electrosphere.engine.assetmanager.queue.QueuedModel;
import electrosphere.entity.ClientEntityUtils;
@ -16,10 +17,12 @@ import electrosphere.entity.Entity;
import electrosphere.entity.EntityCreationUtils;
import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.ServerEntityUtils;
import electrosphere.entity.types.collision.CollisionObjUtils;
import electrosphere.logger.LoggerInterface;
import electrosphere.renderer.meshgen.BlockMeshgen;
import electrosphere.renderer.meshgen.BlockMeshgen.BlockMeshData;
import electrosphere.server.datacell.Realm;
/**
* Generates block chunk entities
@ -63,7 +66,7 @@ public class BlockChunkEntity {
}));
EntityCreationUtils.makeEntityDrawablePreexistingModel(rVal, modelPath);
if(levelOfDetail == BlockChunkData.LOD_FULL_RES){
// PhysicsEntityUtils.clientAttachTerrainChunkRigidBody(rVal, data);
PhysicsEntityUtils.clientAttachTriGeomRigidBody(rVal, data);
CollisionObjUtils.clientPositionCharacter(rVal, new Vector3d(EntityUtils.getPosition(rVal)), new Quaterniond());
} else {
EntityCreationUtils.bypassShadowPass(rVal);
@ -99,6 +102,34 @@ public class BlockChunkEntity {
return rVal;
}
/**
* Creates a block chunk entity on the server
* @param realm The realm
* @param position The position of the chunk
* @param weights The weights for the block chunk
* @param values The values of each voxel in the chunk
* @return The block entity
*/
public static Entity serverCreateBlockChunkEntity(Realm realm, Vector3d position, BlockMeshData blockChunkData){
Entity rVal = EntityCreationUtils.createServerEntity(realm, position);
if(blockChunkData.getVertices().length > 0){
PhysicsEntityUtils.serverAttachTriGeomRigidBody(rVal, blockChunkData);
rVal.putData(EntityDataStrings.TERRAIN_IS_TERRAIN, true);
}
//position entity
//this needs to be called at the end of this function.
//Burried underneath this is function call to initialize a server side entity.
//The server initialization logic checks what type of entity this is, if this function is called prior to its type being stored
//the server will not be able to synchronize it properly.
ServerEntityUtils.initiallyPositionEntity(realm,rVal,position);
return rVal;
}
/**
* Halts all running generation threads
*/

View File

@ -6,6 +6,7 @@ import java.util.concurrent.Executors;
import org.joml.Quaterniond;
import org.joml.Vector3d;
import electrosphere.client.block.BlockChunkData;
import electrosphere.client.terrain.cells.ClientDrawCellManager;
import electrosphere.client.terrain.cells.DrawCell;
import electrosphere.client.terrain.cells.VoxelTextureAtlas;
@ -64,8 +65,8 @@ public class TerrainChunk {
if(Globals.clientScene.containsEntity(rVal)){
String modelPath = ClientTerrainManager.queueTerrainGridGeneration(data, atlas, notifyTarget, toDelete);
EntityCreationUtils.makeEntityDrawablePreexistingModel(rVal, modelPath);
if(levelOfDetail == ClientDrawCellManager.FULL_RES_LOD && data.faceElements.length > 0){
PhysicsEntityUtils.clientAttachTerrainChunkRigidBody(rVal, data);
if(levelOfDetail == BlockChunkData.LOD_FULL_RES && data.faceElements.length > 0){
PhysicsEntityUtils.clientAttachTriGeomRigidBody(rVal, data);
CollisionObjUtils.clientPositionCharacter(rVal, new Vector3d(EntityUtils.getPosition(rVal)), new Quaterniond());
} else {
EntityCreationUtils.bypassShadowPass(rVal);
@ -116,7 +117,7 @@ public class TerrainChunk {
Entity rVal = EntityCreationUtils.createServerEntity(realm, position);
if(data.vertices.length > 0){
PhysicsEntityUtils.serverAttachTerrainChunkRigidBody(rVal, data);
PhysicsEntityUtils.serverAttachTriGeomRigidBody(rVal, data);
rVal.putData(EntityDataStrings.TERRAIN_IS_TERRAIN, true);
// ServerEntityUtils.initiallyPositionEntity(realm, rVal, position);
// physicsObject = PhysicsUtils.attachTerrainRigidBody(physicsEntity,heightmap,true);

View File

@ -5,10 +5,12 @@ import java.nio.IntBuffer;
import org.lwjgl.BufferUtils;
import electrosphere.entity.state.collidable.TriGeomData;
/**
* The data required to generate a texture
*/
public class TerrainChunkData {
public class TerrainChunkData implements TriGeomData {
//the verts
float[] vertices;
@ -81,10 +83,7 @@ public class TerrainChunkData {
ratioBuffer.put(this.textureRatioVectors);
}
/**
* Gets the vertex data
* @return the vertex data
*/
@Override
public float[] getVertices(){
return vertices;
}
@ -97,10 +96,7 @@ public class TerrainChunkData {
return normals;
}
/**
* Gets the face element data
* @return the face element data
*/
@Override
public int[] getFaceElements(){
return faceElements;
}

View File

@ -13,6 +13,7 @@ import org.lwjgl.opengl.GL40;
import electrosphere.client.block.BlockChunkData;
import electrosphere.engine.Globals;
import electrosphere.entity.state.collidable.TriGeomData;
import electrosphere.renderer.model.Mesh;
import electrosphere.renderer.model.Model;
@ -120,8 +121,8 @@ public class BlockMeshgen {
indices.add(2);
indices.add(3);
indices.add(0);
indices.add(1);
indices.add(3);
indices.add(1);
//normals
normals.add(new Vector3f(0,0,-1));
normals.add(new Vector3f(0,0,-1));
@ -144,8 +145,8 @@ public class BlockMeshgen {
verts.add(new Vector3f(quad.x, quad.y + quad.h, quad.z + depth).mul(BlockChunkData.BLOCK_SIZE_MULTIPLIER));
//indices
indices.add(4);
indices.add(6);
indices.add(7);
indices.add(6);
indices.add(4);
indices.add(5);
indices.add(7);
@ -173,8 +174,8 @@ public class BlockMeshgen {
indices.add( 8);
indices.add(10);
indices.add(11);
indices.add( 8);
indices.add( 9);
indices.add( 8);
indices.add(11);
//normals
normals.add(new Vector3f(0,-1,0));
@ -198,8 +199,8 @@ public class BlockMeshgen {
verts.add(new Vector3f(quad.x + quad.w, quad.y + quad.h, quad.z + depth).mul(BlockChunkData.BLOCK_SIZE_MULTIPLIER));
//indices
indices.add(12);
indices.add(14);
indices.add(15);
indices.add(14);
indices.add(12);
indices.add(13);
indices.add(15);
@ -229,8 +230,8 @@ public class BlockMeshgen {
indices.add(18);
indices.add(19);
indices.add(16);
indices.add(17);
indices.add(19);
indices.add(17);
//normals
normals.add(new Vector3f(1,0,0));
normals.add(new Vector3f(1,0,0));
@ -254,8 +255,8 @@ public class BlockMeshgen {
verts.add(new Vector3f(quad.x + quad.w, quad.y + quad.h, quad.z + depth).mul(BlockChunkData.BLOCK_SIZE_MULTIPLIER));
//indices
indices.add(20);
indices.add(22);
indices.add(23);
indices.add(22);
indices.add(20);
indices.add(21);
indices.add(23);
@ -466,7 +467,7 @@ public class BlockMeshgen {
/**
* The final rasterization data that is emitted
*/
public static class BlockMeshData {
public static class BlockMeshData implements TriGeomData {
//the verts
float[] vertices;
//normals
@ -480,6 +481,15 @@ public class BlockMeshgen {
FloatBuffer normalBuffer;
IntBuffer faceBuffer;
FloatBuffer uvBuffer;
@Override
public float[] getVertices() {
return vertices;
}
@Override
public int[] getFaceElements() {
return faceElements;
}
}
/**

View File

@ -121,6 +121,16 @@ public class ServerBlockManager {
returnedChunk.setWorldY(worldY);
returnedChunk.setWorldZ(worldZ);
returnedChunk.setHomogenousValue(0);
if(worldX == 0 && worldY == 0 && worldZ == 0){
returnedChunk.setHomogenousValue(BlockChunkData.NOT_HOMOGENOUS);
for(int x = 3; x < 16; x++){
for(int y = 8; y < 16; y++){
for(int z = 3; z < 16; z++){
returnedChunk.setType(x, y, z, 1);
}
}
}
}
}
this.chunkCache.add(worldX, worldY, worldZ, BlockChunkData.LOD_FULL_RES, returnedChunk);
}

View File

@ -5,7 +5,10 @@ import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.ServerEntityUtils;
import electrosphere.entity.types.terrain.BlockChunkEntity;
import electrosphere.entity.types.terrain.TerrainChunk;
import electrosphere.renderer.meshgen.BlockMeshgen;
import electrosphere.renderer.meshgen.BlockMeshgen.BlockMeshData;
import electrosphere.server.datacell.Realm;
import electrosphere.server.terrain.manager.ServerTerrainChunk;
import electrosphere.server.terrain.manager.ServerTerrainManager;
@ -22,6 +25,7 @@ public class PhysicsDataCell {
Vector3i worldPos;
Entity physicsEntity;
Entity blockPhysicsEntity;
DBody physicsObject;
@ -59,6 +63,8 @@ public class PhysicsDataCell {
public void retireCell(){
ServerEntityUtils.destroyEntity(physicsEntity);
this.physicsEntity = null;
ServerEntityUtils.destroyEntity(blockPhysicsEntity);
this.blockPhysicsEntity = null;
}
/**
@ -81,6 +87,16 @@ public class PhysicsDataCell {
physicsEntity = TerrainChunk.serverCreateTerrainChunkEntity(realm, realPos, weights, types);
physicsEntity.putData(EntityDataStrings.TERRAIN_IS_TERRAIN, true);
}
if(blockPhysicsEntity == null){
Vector3d realPos = new Vector3d(
worldPos.x * ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET,
worldPos.y * ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET,
worldPos.z * ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET
);
BlockMeshData meshData = BlockMeshgen.rasterize(realm.getServerWorldData().getServerBlockManager().getChunk(worldPos.x, worldPos.y, worldPos.z));
blockPhysicsEntity = BlockChunkEntity.serverCreateBlockChunkEntity(realm, realPos, meshData);
blockPhysicsEntity.putData(EntityDataStrings.TERRAIN_IS_TERRAIN, true);
}
// //then actually perform the attach
// physicsObject = PhysicsUtils.attachTerrainRigidBody(physicsEntity,heightmap,true);
// Realm realm = Globals.realmManager.getEntityRealm(physicsEntity);
@ -93,6 +109,7 @@ public class PhysicsDataCell {
public void destroyPhysics(){
Realm realm = Globals.realmManager.getEntityRealm(physicsEntity);
realm.getCollisionEngine().destroyPhysics(physicsEntity);
realm.getCollisionEngine().destroyPhysics(blockPhysicsEntity);
}
/**