fix block mesh ray cast bug
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good

This commit is contained in:
austin 2025-03-28 11:32:09 -04:00
parent 355abd0991
commit fcd2f1e0a7
8 changed files with 211 additions and 8 deletions

View File

@ -1353,6 +1353,7 @@ Fix TextureInstancedActor packing data texture incorrectly (column major instead
(03/28/2025)
Grass height variance with control from ui + file
Fix block mesh ray casting bug due to trimesh overlap
# TODO

View File

@ -23,7 +23,12 @@ import electrosphere.renderer.meshgen.BlockMeshgen.BlockMeshData;
import electrosphere.server.terrain.manager.ServerTerrainChunk;
import electrosphere.server.terrain.manager.ServerTerrainManager;
/**
* Handles networking for block-related messages on client
*/
public class ClientBlockManager {
//queues messages from server
List<TerrainMessage> messageQueue = new LinkedList<TerrainMessage>();

View File

@ -19,6 +19,7 @@ import org.ode4j.ode.DMass;
import org.ode4j.ode.DSphere;
import org.ode4j.ode.DTriMesh;
import electrosphere.entity.state.collidable.MultiShapeTriGeomData;
import electrosphere.entity.state.collidable.TriGeomData;
/**
@ -270,6 +271,35 @@ public class CollisionBodyCreation {
return body;
}
/**
* Creates an ode DBody from a mesh data set containing multiple shapes
* @param data The mesh data data
* @return The DBody
*/
public static DBody generateBodyFromMultiShapeMeshData(CollisionEngine collisionEngine, MultiShapeTriGeomData data, long categoryBits){
DBody body = null;
DGeom[] geoms = new DGeom[data.getData().size()];
//create trimeshes
int i = 0;
for(TriGeomData shapeData : data.getData()){
if(shapeData.getFaceElements().length > 0){
DTriMesh triMesh = collisionEngine.createTrimeshGeom(shapeData.getVertices(),shapeData.getFaceElements(),categoryBits);
geoms[i] = triMesh;
}
i++;
}
//create body from shapes
body = collisionEngine.createDBody(geoms);
collisionEngine.setKinematic(body);
collisionEngine.setGravityMode(body, false);
return body;
}
/**
* Generates a body from an AIScene
* @param scene The AIScene to generate a rigid body off of

View File

@ -17,6 +17,7 @@ import electrosphere.entity.EntityTags;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.ServerEntityUtils;
import electrosphere.entity.state.collidable.ClientCollidableTree;
import electrosphere.entity.state.collidable.MultiShapeTriGeomData;
import electrosphere.entity.state.collidable.ServerCollidableTree;
import electrosphere.entity.state.collidable.TriGeomData;
import electrosphere.entity.state.physicssync.ClientPhysicsSyncTree;
@ -504,6 +505,21 @@ public class PhysicsEntityUtils {
terrain.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable);
}
/**
* [CLIENT ONLY] Given an entity and a multi-shape trimesh description, create physics for the shapes and attach it to the entity
* @param terrain The entity
* @param data The trimesh description
* @return The rigid body created (note, attachment has already been performed)
*/
public static void clientAttachMultiShapeTriGeomRigidBody(Entity terrain, MultiShapeTriGeomData data){
DBody terrainBody = CollisionBodyCreation.generateBodyFromMultiShapeMeshData(Globals.clientSceneWrapper.getCollisionEngine(), data, Collidable.TYPE_STATIC_BIT);
CollisionBodyCreation.setAutoDisable(Globals.clientSceneWrapper.getCollisionEngine(), terrainBody, true, LINEAR_THRESHOLD, ANGULAR_THRESHOLD, STEP_THRESHOLD);
Collidable collidable = new Collidable(terrain,Collidable.TYPE_STATIC, false);
Globals.clientSceneWrapper.getCollisionEngine().registerCollisionObject(terrainBody, collidable);
PhysicsEntityUtils.setDBody(terrain,terrainBody);
terrain.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable);
}
/**
* [SERVER ONLY] Given an entity and a terrain chunk description, create physics for the chunk and attach it to the entity
@ -522,6 +538,23 @@ public class PhysicsEntityUtils {
return terrainBody;
}
/**
* [SERVER ONLY] Given an entity and a multi-shape trimesh description, create physics for the shapes and attach it to the entity
* @param terrain The entity
* @param data The trimesh description
* @return The rigid body created (note, attachment has already been performed)
*/
public static DBody serverAttachMultiShapeTriGeomRigidBody(Entity terrain, MultiShapeTriGeomData data){
Realm realm = Globals.realmManager.getEntityRealm(terrain);
DBody terrainBody = CollisionBodyCreation.generateBodyFromMultiShapeMeshData(realm.getCollisionEngine(),data,Collidable.TYPE_STATIC_BIT);
CollisionBodyCreation.setAutoDisable(realm.getCollisionEngine(), terrainBody, true, LINEAR_THRESHOLD, ANGULAR_THRESHOLD, STEP_THRESHOLD);
realm.getCollisionEngine().registerCollisionObject(terrainBody, new Collidable(terrain,Collidable.TYPE_STATIC, false));
PhysicsEntityUtils.setDBody(terrain,terrainBody);
return terrainBody;
}
/**
* Repositions all active physics-scoped entities on a given realm
* @param collisionEngine The realm's collision engine

View File

@ -0,0 +1,16 @@
package electrosphere.entity.state.collidable;
import java.util.Collection;
/**
* A tri geom data set that contains multiple shapes
*/
public interface MultiShapeTriGeomData {
/**
* Gets the data for the tri geom shapes
* @return The data
*/
public Collection<TriGeomData> getData();
}

View File

@ -67,7 +67,7 @@ public class BlockChunkEntity {
}));
EntityCreationUtils.makeEntityDrawablePreexistingModel(rVal, modelPath);
if(levelOfDetail == BlockChunkData.LOD_FULL_RES){
PhysicsEntityUtils.clientAttachTriGeomRigidBody(rVal, data);
PhysicsEntityUtils.clientAttachMultiShapeTriGeomRigidBody(rVal, data);
CollisionObjUtils.clientPositionCharacter(rVal, new Vector3d(EntityUtils.getPosition(rVal)), new Quaterniond());
} else {
EntityCreationUtils.bypassShadowPass(rVal);
@ -112,7 +112,7 @@ public class BlockChunkEntity {
*/
public static void serverCreateBlockChunkEntity(Entity entity, BlockMeshData blockChunkData){
if(blockChunkData.getVertices().length > 0){
PhysicsEntityUtils.serverAttachTriGeomRigidBody(entity, blockChunkData);
PhysicsEntityUtils.serverAttachMultiShapeTriGeomRigidBody(entity, blockChunkData);
Realm realm = Globals.realmManager.getEntityRealm(entity);
DBody terrainBody = PhysicsEntityUtils.getDBody(entity);
Vector3d entityPos = EntityUtils.getPosition(entity);

View File

@ -208,6 +208,7 @@ public class TerrainProtocol implements ClientProtocolTemplate<TerrainMessage> {
if(Globals.clientBlockManager.containsChunkDataAtWorldPoint(worldPos.x, worldPos.y, worldPos.z, ChunkData.NO_STRIDE)){
BlockChunkData data = Globals.clientBlockManager.getChunkDataAtWorldPoint(worldPos.x, worldPos.y, worldPos.z, ChunkData.NO_STRIDE);
if(data != null){
System.out.println("Set " + message.getvoxelX() + " " + message.getvoxelY() + " " + message.getvoxelZ() + " to " + message.getblockType());
data.setType(
message.getvoxelX(),
message.getvoxelY(),

View File

@ -2,6 +2,7 @@ package electrosphere.renderer.meshgen;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
@ -13,6 +14,7 @@ import org.lwjgl.opengl.GL40;
import electrosphere.client.block.BlockChunkData;
import electrosphere.engine.Globals;
import electrosphere.entity.state.collidable.MultiShapeTriGeomData;
import electrosphere.entity.state.collidable.TriGeomData;
import electrosphere.renderer.model.Material;
import electrosphere.renderer.model.Mesh;
@ -311,6 +313,9 @@ public class BlockMeshgen {
//sort
Collections.sort(quadMeshes);
int lastVertexCount = 0;
int lastFaceCount = 0;
//generate volumes
QuadMesh quad1 = null;
QuadMesh quad2 = null;
@ -325,6 +330,11 @@ public class BlockMeshgen {
} else {
BlockMeshgen.meshifyBox(verts,normals,uvs,indices,samplers,quad1,zEnd,quad1.type,verts.size());
quad1 = quad2;
BlockSingleShape blockSingleShape = BlockMeshgen.copyDataToShape(verts,indices,lastVertexCount,lastFaceCount);
lastVertexCount = verts.size();
lastFaceCount = indices.size();
rVal.shapeData.add(blockSingleShape);
break;
}
}
@ -332,6 +342,10 @@ public class BlockMeshgen {
}
if(quad1 != null){
BlockMeshgen.meshifyBox(verts,normals,uvs,indices,samplers,quad1,zEnd,quad1.type,verts.size());
BlockSingleShape blockSingleShape = BlockMeshgen.copyDataToShape(verts,indices,lastVertexCount,lastFaceCount);
lastVertexCount = verts.size();
lastFaceCount = indices.size();
rVal.shapeData.add(blockSingleShape);
}
//
@ -389,6 +403,28 @@ public class BlockMeshgen {
return rVal;
}
/**
* Copies vertex and index data from the combined array into a single shape
* @param verts The list of vertices
* @param indices The list of indices
* @param lastVertCount The last vertex position that was copied
* @param lastFaceCount The last index position that was copied
* @return The data containing a single shape's worth of geometry data
*/
private static BlockSingleShape copyDataToShape(List<Vector3f> verts, List<Integer> indices, int lastVertCount, int lastFaceCount){
BlockSingleShape blockSingleShape = new BlockSingleShape((verts.size() - lastVertCount),(indices.size() - lastFaceCount));
for(int i = lastVertCount; i < verts.size(); i++){
Vector3f vert = verts.get(i);
blockSingleShape.vertices[(i - lastVertCount) * 3 + 0] = vert.x;
blockSingleShape.vertices[(i - lastVertCount) * 3 + 1] = vert.y;
blockSingleShape.vertices[(i - lastVertCount) * 3 + 2] = vert.z;
}
for(int i = lastFaceCount; i < indices.size(); i++){
blockSingleShape.faceElements[i - lastFaceCount] = indices.get(i) - lastVertCount;
}
return blockSingleShape;
}
/**
* Generates a mesh based on a block mesh data object
* @param data The block mesh data object
@ -492,36 +528,117 @@ public class BlockMeshgen {
return rVal;
}
/**
* Contains the geom data for a single shape in the block mesh
*/
public static class BlockSingleShape implements TriGeomData {
/**
* The verts
*/
float[] vertices;
/**
* The faces
*/
int[] faceElements;
/**
* Constructor
* @param vertCount The number of verts
* @param faceCount The number of faces
*/
public BlockSingleShape(int vertCount, int faceCount){
vertices = new float[vertCount * 3];
faceElements = new int[faceCount];
}
@Override
public float[] getVertices() {
return vertices;
}
@Override
public int[] getFaceElements() {
return faceElements;
}
}
/**
* The final rasterization data that is emitted
*/
public static class BlockMeshData implements TriGeomData {
//the verts
public static class BlockMeshData implements TriGeomData, MultiShapeTriGeomData {
/**
* Vertex data in array form
*/
float[] vertices;
//normals
/**
* Normal data in array form
*/
float[] normals;
//faces
/**
* Face data in array form
*/
int[] faceElements;
//UVs
/**
* UV data in array form
*/
float[] uvs;
//The samplers for each quad
/**
* Sampler data in array form
*/
int[] samplers;
/**
* Data broken out by each shape
*/
List<TriGeomData> shapeData = new LinkedList<TriGeomData>();
/**
* Buffer of vertex data
*/
FloatBuffer vertBuffer;
/**
* Buffer of normal data
*/
FloatBuffer normalBuffer;
/**
* Buffer of face data
*/
IntBuffer faceBuffer;
/**
* Buffer of UV data
*/
FloatBuffer uvBuffer;
/**
* Buffer of sampler data
*/
IntBuffer samplerBuffer;
@Override
public float[] getVertices() {
return vertices;
}
@Override
public int[] getFaceElements() {
return faceElements;
}
@Override
public Collection<TriGeomData> getData() {
return shapeData;
}
}
/**