transparent block support
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
This commit is contained in:
parent
ef0adbe3e6
commit
a375e1a686
Binary file not shown.
|
Before Width: | Height: | Size: 200 KiB After Width: | Height: | Size: 144 KiB |
@ -1,3 +1,3 @@
|
||||
#maven.buildNumber.plugin properties file
|
||||
#Mon May 19 14:18:34 EDT 2025
|
||||
buildNumber=626
|
||||
#Mon May 19 19:19:06 EDT 2025
|
||||
buildNumber=627
|
||||
|
||||
@ -1906,6 +1906,7 @@ Major lighting shader organization rework
|
||||
Material albedo work
|
||||
Editor entities don't use charges on placing blocks
|
||||
Overhaul material loading - uses queued textures now
|
||||
Transparent block support
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
package electrosphere.client.block.cells;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.joml.Quaterniond;
|
||||
import org.joml.Vector3d;
|
||||
import org.joml.Vector3i;
|
||||
@ -38,7 +41,7 @@ public class BlockDrawCell {
|
||||
int lod;
|
||||
|
||||
//the main entity for the cell
|
||||
Entity modelEntity;
|
||||
List<Entity> modelEntities = new LinkedList<Entity>();
|
||||
|
||||
/**
|
||||
* The data for generating the visuals
|
||||
@ -132,9 +135,11 @@ public class BlockDrawCell {
|
||||
}
|
||||
this.chunkData = currentChunk;
|
||||
}
|
||||
Entity toDelete = this.modelEntity;
|
||||
modelEntity = BlockChunkEntity.clientCreateBlockChunkEntity(chunkData, notifyTarget, toDelete, lod, atlas, this.hasPolygons());
|
||||
ClientEntityUtils.initiallyPositionEntity(modelEntity, this.getRealPos(), new Quaterniond());
|
||||
List<Entity> toDelete = this.modelEntities;
|
||||
this.modelEntities = BlockChunkEntity.clientCreateBlockChunkEntity(chunkData, notifyTarget, toDelete, lod, atlas, this.hasPolygons());
|
||||
for(Entity ent : modelEntities){
|
||||
ClientEntityUtils.initiallyPositionEntity(ent, this.getRealPos(), new Quaterniond());
|
||||
}
|
||||
this.setHasGenerated(true);
|
||||
}
|
||||
|
||||
@ -180,27 +185,29 @@ public class BlockDrawCell {
|
||||
* Destroys a drawcell including its physics
|
||||
*/
|
||||
public void destroy(){
|
||||
if(modelEntity != null){
|
||||
Globals.clientState.clientScene.registerBehaviorTree(new BehaviorTree(){
|
||||
int framesSimulated = 0;
|
||||
public void simulate(float deltaTime) {
|
||||
if(framesSimulated < FRAMES_TO_WAIT_BEFORE_DESTRUCTION){
|
||||
framesSimulated++;
|
||||
} else {
|
||||
ClientEntityUtils.destroyEntity(modelEntity);
|
||||
Globals.clientState.clientScene.deregisterBehaviorTree(this);
|
||||
if(this.modelEntities != null){
|
||||
for(Entity ent : this.modelEntities){
|
||||
Globals.clientState.clientScene.registerBehaviorTree(new BehaviorTree(){
|
||||
int framesSimulated = 0;
|
||||
public void simulate(float deltaTime) {
|
||||
if(framesSimulated < FRAMES_TO_WAIT_BEFORE_DESTRUCTION){
|
||||
framesSimulated++;
|
||||
} else {
|
||||
ClientEntityUtils.destroyEntity(ent);
|
||||
Globals.clientState.clientScene.deregisterBehaviorTree(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the entity for the cell
|
||||
* @return The entity if it exists, null otherwise
|
||||
* Gets the list of entities for the cell
|
||||
* @return The list of entities if it exists, null otherwise
|
||||
*/
|
||||
public Entity getEntity(){
|
||||
return modelEntity;
|
||||
public List<Entity> getEntities(){
|
||||
return this.modelEntities;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -616,7 +616,8 @@ public class ClientBlockCellManager {
|
||||
public boolean shouldDestroy(WorldOctTreeNode<BlockDrawCell> node){
|
||||
return
|
||||
node.getData() != null &&
|
||||
node.getData().getEntity() != null
|
||||
node.getData().getEntities() != null &&
|
||||
node.getData().getEntities().size() > 0
|
||||
;
|
||||
}
|
||||
|
||||
@ -849,8 +850,8 @@ public class ClientBlockCellManager {
|
||||
*/
|
||||
public boolean hasGeneratedPhysics(int worldX, int worldY, int worldZ){
|
||||
BlockDrawCell cell = this.getDrawCell(worldX, worldY, worldZ);
|
||||
if(cell != null && cell.getEntity() != null){
|
||||
return PhysicsEntityUtils.containsDBody(cell.getEntity());
|
||||
if(cell != null && cell.getEntities() != null && cell.getEntities().size() > 0){
|
||||
return PhysicsEntityUtils.containsDBody(cell.getEntities().get(0));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package electrosphere.controls.cursor;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
import org.joml.Quaterniond;
|
||||
import org.joml.Vector3d;
|
||||
@ -477,8 +478,9 @@ public class CursorState {
|
||||
* @param fab The fab
|
||||
*/
|
||||
public void setSelectedFab(BlockFab fab){
|
||||
Map<Integer,Boolean> solidsMap = Globals.gameConfigCurrent.getBlockData().getSolidsMap();
|
||||
QueuedModel queuedModel = new QueuedModel(() -> {
|
||||
return BlockMeshgen.generateBlockModel(BlockMeshgen.rasterize(fab));
|
||||
return BlockMeshgen.generateBlockModel(BlockMeshgen.rasterize(fab,false,solidsMap));
|
||||
});
|
||||
Globals.assetManager.queuedAsset(queuedModel);
|
||||
EntityCreationUtils.makeEntityDrawablePreexistingModel(playerFabCursor, queuedModel.getPromisedPath());
|
||||
|
||||
@ -135,6 +135,7 @@ public class Config {
|
||||
config.raceMap = FileUtils.loadObjectFromAssetPath("Data/game/races.json", RaceMap.class);
|
||||
config.voxelData = FileUtils.loadObjectFromAssetPath("Data/game/voxelTypes.json", VoxelData.class);
|
||||
config.blockData = FileUtils.loadObjectFromAssetPath("Data/game/blockTypes.json", BlockData.class);
|
||||
config.blockData.constructSolidsMap();
|
||||
config.projectileTypeHolder = FileUtils.loadObjectFromAssetPath("Data/entity/projectile.json", ProjectileTypeHolder.class);
|
||||
config.hintData = FileUtils.loadObjectFromAssetPath("Data/tutorial/hints.json", HintDefinition.class);
|
||||
config.surfaceAudioCollection = FileUtils.loadObjectFromAssetPath("Data/audio/surface.json", SurfaceAudioCollection.class);
|
||||
|
||||
@ -1,14 +1,24 @@
|
||||
package electrosphere.data.block;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A list of all block types in game
|
||||
*/
|
||||
public class BlockData {
|
||||
//The set of all voxel types
|
||||
|
||||
/**
|
||||
* The set of all voxel types
|
||||
*/
|
||||
Set<BlockType> types;
|
||||
|
||||
/**
|
||||
* The map of block id -> boolean that stores whether the block should cutout transparent or blended transparent
|
||||
*/
|
||||
Map<Integer,Boolean> solidsMap = new HashMap<Integer,Boolean>();
|
||||
|
||||
/**
|
||||
* Gets all block types
|
||||
* @return The set of all block types
|
||||
@ -44,4 +54,27 @@ public class BlockData {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the solids map
|
||||
*/
|
||||
public void constructSolidsMap(){
|
||||
for(BlockType type : this.types){
|
||||
if(type.transparent != null && type.isTransparent()){
|
||||
solidsMap.put(type.getId(), false);
|
||||
} else {
|
||||
solidsMap.put(type.getId(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the solids map
|
||||
* @return The solids map
|
||||
*/
|
||||
public Map<Integer,Boolean> getSolidsMap(){
|
||||
return this.solidsMap;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
package electrosphere.entity.types.terrain;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
@ -16,6 +19,7 @@ import electrosphere.engine.Globals;
|
||||
import electrosphere.engine.assetmanager.queue.QueuedModel;
|
||||
import electrosphere.engine.threads.ThreadCounts;
|
||||
import electrosphere.entity.ClientEntityUtils;
|
||||
import electrosphere.entity.DrawableUtils;
|
||||
import electrosphere.entity.Entity;
|
||||
import electrosphere.entity.EntityCreationUtils;
|
||||
import electrosphere.entity.EntityDataStrings;
|
||||
@ -47,36 +51,40 @@ public class BlockChunkEntity {
|
||||
* @param hasPolygons true if the chunk has polygons to generate a model with, false otherwise
|
||||
* @return The block chunk entity
|
||||
*/
|
||||
public static Entity clientCreateBlockChunkEntity(
|
||||
public static List<Entity> clientCreateBlockChunkEntity(
|
||||
BlockChunkData chunkData,
|
||||
BlockDrawCell notifyTarget,
|
||||
Entity toDelete,
|
||||
List<Entity> toDelete,
|
||||
int levelOfDetail,
|
||||
BlockTextureAtlas atlas,
|
||||
boolean hasPolygons
|
||||
){
|
||||
Globals.profiler.beginAggregateCpuSample("BlockChunk.clientCreateBlockChunkEntity");
|
||||
List<Entity> rVal = new LinkedList<Entity>();
|
||||
|
||||
Entity rVal = EntityCreationUtils.createClientSpatialEntity();
|
||||
|
||||
Map<Integer,Boolean> solidsMap = Globals.gameConfigCurrent.getBlockData().getSolidsMap();
|
||||
//
|
||||
//Create the entity for rendering solid blocks
|
||||
Entity solidsEnt = EntityCreationUtils.createClientSpatialEntity();
|
||||
if(hasPolygons && chunkData.getType() != null && chunkData.getMetadata() != null){
|
||||
generationService.submit(() -> {
|
||||
BlockMeshData data;
|
||||
try {
|
||||
data = BlockMeshgen.rasterize(chunkData);
|
||||
if(Globals.clientState.clientScene.containsEntity(rVal)){
|
||||
data = BlockMeshgen.rasterize(chunkData, true, solidsMap);
|
||||
if(Globals.clientState.clientScene.containsEntity(solidsEnt)){
|
||||
String modelPath = Globals.assetManager.queuedAsset(new QueuedModel(() -> {
|
||||
return BlockMeshgen.generateBlockModel(data);
|
||||
}));
|
||||
EntityCreationUtils.makeEntityDrawablePreexistingModel(rVal, modelPath);
|
||||
EntityCreationUtils.makeEntityDrawablePreexistingModel(solidsEnt, modelPath);
|
||||
if(levelOfDetail == BlockChunkData.LOD_FULL_RES){
|
||||
PhysicsEntityUtils.clientAttachMultiShapeTriGeomRigidBody(rVal, data);
|
||||
CollisionObjUtils.clientPositionCharacter(rVal, new Vector3d(EntityUtils.getPosition(rVal)), new Quaterniond());
|
||||
PhysicsEntityUtils.clientAttachMultiShapeTriGeomRigidBody(solidsEnt, data);
|
||||
CollisionObjUtils.clientPositionCharacter(solidsEnt, new Vector3d(EntityUtils.getPosition(solidsEnt)), new Quaterniond());
|
||||
} else {
|
||||
EntityCreationUtils.bypassShadowPass(rVal);
|
||||
EntityCreationUtils.bypassVolumetics(rVal);
|
||||
EntityCreationUtils.bypassShadowPass(solidsEnt);
|
||||
EntityCreationUtils.bypassVolumetics(solidsEnt);
|
||||
}
|
||||
rVal.putData(EntityDataStrings.HAS_UNIQUE_MODEL, true);
|
||||
solidsEnt.putData(EntityDataStrings.HAS_UNIQUE_MODEL, true);
|
||||
} else {
|
||||
LoggerInterface.loggerEngine.DEBUG("Finished generating block polygons; however, entity has already been deleted.");
|
||||
}
|
||||
@ -84,7 +92,9 @@ public class BlockChunkEntity {
|
||||
notifyTarget.alertToGeneration();
|
||||
}
|
||||
if(toDelete != null){
|
||||
ClientEntityUtils.destroyEntity(toDelete);
|
||||
for(Entity target : toDelete){
|
||||
ClientEntityUtils.destroyEntity(target);
|
||||
}
|
||||
}
|
||||
} catch (Error e){
|
||||
LoggerInterface.loggerEngine.ERROR(e);
|
||||
@ -97,11 +107,68 @@ public class BlockChunkEntity {
|
||||
notifyTarget.alertToGeneration();
|
||||
}
|
||||
if(toDelete != null){
|
||||
ClientEntityUtils.destroyEntity(toDelete);
|
||||
for(Entity target : toDelete){
|
||||
ClientEntityUtils.destroyEntity(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
solidsEnt.putData(EntityDataStrings.TERRAIN_IS_TERRAIN, true);
|
||||
rVal.add(solidsEnt);
|
||||
|
||||
//
|
||||
//Create the entity for rendering solid blocks
|
||||
Entity transparentEnt = EntityCreationUtils.createClientSpatialEntity();
|
||||
if(hasPolygons && chunkData.getType() != null && chunkData.getMetadata() != null){
|
||||
generationService.submit(() -> {
|
||||
BlockMeshData data;
|
||||
try {
|
||||
data = BlockMeshgen.rasterize(chunkData, false, solidsMap);
|
||||
if(Globals.clientState.clientScene.containsEntity(transparentEnt)){
|
||||
String modelPath = Globals.assetManager.queuedAsset(new QueuedModel(() -> {
|
||||
return BlockMeshgen.generateBlockModel(data);
|
||||
}));
|
||||
EntityCreationUtils.makeEntityDrawablePreexistingModel(transparentEnt, modelPath);
|
||||
if(levelOfDetail == BlockChunkData.LOD_FULL_RES){
|
||||
PhysicsEntityUtils.clientAttachMultiShapeTriGeomRigidBody(transparentEnt, data);
|
||||
CollisionObjUtils.clientPositionCharacter(transparentEnt, new Vector3d(EntityUtils.getPosition(transparentEnt)), new Quaterniond());
|
||||
} else {
|
||||
EntityCreationUtils.bypassShadowPass(transparentEnt);
|
||||
EntityCreationUtils.bypassVolumetics(transparentEnt);
|
||||
}
|
||||
transparentEnt.putData(EntityDataStrings.HAS_UNIQUE_MODEL, true);
|
||||
DrawableUtils.makeEntityTransparent(transparentEnt);
|
||||
} else {
|
||||
LoggerInterface.loggerEngine.DEBUG("Finished generating block polygons; however, entity has already been deleted.");
|
||||
}
|
||||
if(notifyTarget != null){
|
||||
notifyTarget.alertToGeneration();
|
||||
}
|
||||
if(toDelete != null){
|
||||
for(Entity target : toDelete){
|
||||
ClientEntityUtils.destroyEntity(target);
|
||||
}
|
||||
}
|
||||
} catch (Error e){
|
||||
LoggerInterface.loggerEngine.ERROR(e);
|
||||
} catch(Exception e){
|
||||
LoggerInterface.loggerEngine.ERROR(e);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if(notifyTarget != null){
|
||||
notifyTarget.alertToGeneration();
|
||||
}
|
||||
if(toDelete != null){
|
||||
for(Entity target : toDelete){
|
||||
ClientEntityUtils.destroyEntity(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
transparentEnt.putData(EntityDataStrings.TERRAIN_IS_TERRAIN, true);
|
||||
rVal.add(transparentEnt);
|
||||
|
||||
|
||||
|
||||
rVal.putData(EntityDataStrings.TERRAIN_IS_TERRAIN, true);
|
||||
Globals.profiler.endCpuSample();
|
||||
return rVal;
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.joml.Vector2f;
|
||||
import org.joml.Vector3f;
|
||||
@ -66,18 +67,48 @@ public class BlockMeshgen {
|
||||
static final int SAMPLER_DATA_SIZE = 1;
|
||||
|
||||
|
||||
/**
|
||||
* Checks whether this block should be rasterized or not
|
||||
* @param data The data
|
||||
* @param x The x coordinate
|
||||
* @param y The y coordinate
|
||||
* @param z The z coordinate
|
||||
* @param solids true to rasterize solids, false to rasterize transparents
|
||||
* @param solidsMap The map of block type to solid status
|
||||
* @return true if it should be rasterized, false otherwise
|
||||
*/
|
||||
protected static boolean shouldRasterize(BlockMeshgenData data, int x, int y, int z, boolean solids, Map<Integer,Boolean> solidsMap){
|
||||
if(data.isEmpty(x, y, z)){
|
||||
return false;
|
||||
}
|
||||
if(solidsMap == null){
|
||||
return true;
|
||||
}
|
||||
return solids == solidsMap.get((int)data.getType(x, y, z));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the quad meshes for the provided data
|
||||
* @param quadMeshes The quad mesh list to fill
|
||||
* @param data The block data
|
||||
*/
|
||||
protected static void fillQuadMeshes(List<QuadMesh> quadMeshes, BlockMeshgenData data){
|
||||
BlockMeshgen.fillQuadMeshes(quadMeshes, data, true, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the quad meshes for the provided data
|
||||
* @param quadMeshes The quad mesh list to fill
|
||||
* @param data The block data
|
||||
*/
|
||||
protected static void fillQuadMeshes(List<QuadMesh> quadMeshes, BlockMeshgenData data, boolean solids, Map<Integer,Boolean> solidsMap){
|
||||
Vector3i dimensions = data.getDimensions();
|
||||
for(int z = 0; z < dimensions.z; z++){
|
||||
for(int x = 0; x < dimensions.x; x++){
|
||||
QuadMesh currentQuad = null;
|
||||
for(int y = 0; y < dimensions.y; y++){
|
||||
if(data.isEmpty(x, y, z)){
|
||||
if(!BlockMeshgen.shouldRasterize(data,x,y,z,solids,solidsMap)){
|
||||
if(currentQuad == null){
|
||||
continue;
|
||||
} else {
|
||||
@ -361,14 +392,16 @@ public class BlockMeshgen {
|
||||
/**
|
||||
* Rasterizes a block chunk data into mesh data
|
||||
* @param chunkData The block chunk data
|
||||
* @param solids true to rasterize solid blocks, false to rasterize transparent blocks
|
||||
* @param solidsMap The solids map
|
||||
* @return The mesh data
|
||||
*/
|
||||
public static BlockMeshData rasterize(BlockMeshgenData chunkData){
|
||||
public static BlockMeshData rasterize(BlockMeshgenData chunkData, boolean solids, Map<Integer,Boolean> solidsMap){
|
||||
BlockMeshData rVal = new BlockMeshData();
|
||||
|
||||
//calculate quad meshes
|
||||
List<QuadMesh> quadMeshes = new LinkedList<QuadMesh>();
|
||||
BlockMeshgen.fillQuadMeshes(quadMeshes, chunkData);
|
||||
BlockMeshgen.fillQuadMeshes(quadMeshes, chunkData, solids, solidsMap);
|
||||
|
||||
//allocate lists to store mesh data in
|
||||
List<Vector3f> verts = new LinkedList<Vector3f>();
|
||||
@ -470,6 +503,15 @@ public class BlockMeshgen {
|
||||
return rVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rasterizes a block chunk data into mesh data
|
||||
* @param chunkData The block chunk data
|
||||
* @return The mesh data
|
||||
*/
|
||||
public static BlockMeshData rasterize(BlockMeshgenData chunkData){
|
||||
return BlockMeshgen.rasterize(chunkData, true, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies vertex and index data from the combined array into a single shape
|
||||
* @param verts The list of vertices
|
||||
|
||||
Loading…
Reference in New Issue
Block a user