scaled foliage cell generation
This commit is contained in:
parent
8430439509
commit
5e06dbe786
1
.gitignore
vendored
1
.gitignore
vendored
@ -14,6 +14,7 @@
|
||||
/NetArranger-*.jar
|
||||
/lwjglx-debug-*.jar
|
||||
/hs_err_pid*
|
||||
/replay_pid*
|
||||
/trace.log
|
||||
|
||||
.classpath
|
||||
|
||||
@ -128,7 +128,10 @@ public class ClientFoliageManager {
|
||||
* @return true if all are ready, false otherwise
|
||||
*/
|
||||
public boolean dependenciesAreReady(){
|
||||
return Globals.clientWorldData != null;
|
||||
return
|
||||
Globals.clientWorldData != null &&
|
||||
Globals.drawCellManager != null
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -122,22 +122,30 @@ public class FoliageCell {
|
||||
*/
|
||||
int scale;
|
||||
|
||||
//position of the foliage cell in world coordinates
|
||||
/**
|
||||
* Position of the foliage cell in world coordinates
|
||||
*/
|
||||
protected Vector3i worldPosition;
|
||||
//position of the foliage cell in local coordinates
|
||||
|
||||
/**
|
||||
* Position of the foliage cell in local coordinates
|
||||
*/
|
||||
protected Vector3i voxelPosition;
|
||||
//the real position of this cell, stored so we don't constantly have to recalculate
|
||||
|
||||
/**
|
||||
* The real position of this cell, stored so we don't constantly have to recalculate
|
||||
*/
|
||||
protected Vector3d realPosition;
|
||||
//constituent entities
|
||||
|
||||
/**
|
||||
* Constituent entities
|
||||
*/
|
||||
protected Set<Entity> containedEntities;
|
||||
|
||||
//template bounding shere used for checking frustum for this cell
|
||||
static Sphered boundingSphere = new Sphered(0.5,0.5,0.5,2);
|
||||
|
||||
/**
|
||||
* The density of the cell
|
||||
* Template bounding shere used for checking frustum for this cell
|
||||
*/
|
||||
protected float density;
|
||||
static Sphered boundingSphere = new Sphered(0.5,0.5,0.5,2);
|
||||
|
||||
/**
|
||||
* Inits the foliage cell data
|
||||
@ -157,12 +165,11 @@ public class FoliageCell {
|
||||
* @param worldPos The position of the foliage cell in world coordinates
|
||||
* @param voxelPos The position of the foliage cell in voxel coordinates
|
||||
*/
|
||||
protected FoliageCell(Vector3i worldPos, Vector3i voxelPos, Vector3d realPos, int scale, float density){
|
||||
protected FoliageCell(Vector3i worldPos, Vector3i voxelPos, Vector3d realPos, int scale){
|
||||
this.worldPosition = worldPos;
|
||||
this.voxelPosition = voxelPos;
|
||||
this.realPosition = realPos;
|
||||
this.scale = scale;
|
||||
this.density = density;
|
||||
this.containedEntities = new HashSet<Entity>();
|
||||
}
|
||||
|
||||
@ -198,34 +205,94 @@ public class FoliageCell {
|
||||
boolean shouldGenerate = false;
|
||||
//get foliage types supported
|
||||
ChunkData data = Globals.clientTerrainManager.getChunkDataAtWorldPoint(worldPosition);
|
||||
List<String> foliageTypesSupported = null;
|
||||
if(data != null && voxelPosition.y + 1 < ServerTerrainChunk.CHUNK_DIMENSION){
|
||||
foliageTypesSupported = Globals.gameConfigCurrent.getVoxelData().getTypeFromId(data.getType(voxelPosition)).getAmbientFoliage();
|
||||
boolean airAbove = data.getType(voxelPosition.x,voxelPosition.y+1,voxelPosition.z) == 0;
|
||||
if(foliageTypesSupported != null && airAbove && scale < 2){
|
||||
shouldGenerate = true;
|
||||
}
|
||||
if(data == null){
|
||||
return;
|
||||
}
|
||||
if(voxelPosition.y + 1 >= ServerTerrainChunk.CHUNK_DIMENSION){
|
||||
return;
|
||||
}
|
||||
if(!Globals.drawCellManager.generatedPhysics(worldPosition)){
|
||||
return;
|
||||
}
|
||||
List<String> foliageTypesSupported = Globals.gameConfigCurrent.getVoxelData().getTypeFromId(data.getType(voxelPosition)).getAmbientFoliage();
|
||||
boolean airAbove = data.getType(voxelPosition.x,voxelPosition.y+1,voxelPosition.z) == 0;
|
||||
if(foliageTypesSupported != null && airAbove && scale < 3){
|
||||
shouldGenerate = true;
|
||||
}
|
||||
if(shouldGenerate){
|
||||
|
||||
//get type
|
||||
String foliageTypeName = foliageTypesSupported.get(placementRandomizer.nextInt() % foliageTypesSupported.size());
|
||||
FoliageType foliageType = Globals.gameConfigCurrent.getFoliageMap().getFoliage(foliageTypeName);
|
||||
|
||||
//create cell and buffer
|
||||
int FINAL_SPACING = (int)(TARGET_FOLIAGE_SPACING * density);
|
||||
ByteBuffer buffer = BufferUtils.createByteBuffer(FINAL_SPACING * FINAL_SPACING * SINGLE_FOLIAGE_DATA_SIZE_BYTES);
|
||||
ByteBuffer buffer = BufferUtils.createByteBuffer(TARGET_FOLIAGE_PER_CELL * SINGLE_FOLIAGE_DATA_SIZE_BYTES);
|
||||
FloatBuffer floatBufferView = buffer.asFloatBuffer();
|
||||
int drawCount = 0;
|
||||
for(int x = 0; x < scale; x++){
|
||||
for(int y = 0; y < scale; y++){
|
||||
for(int z = 0; z < scale; z++){
|
||||
drawCount = drawCount + insertBlades(x, y, z, floatBufferView, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
// drawCount = drawCount + this.insertBlades(0, 0, 0, floatBufferView, data);
|
||||
if(drawCount > 0){
|
||||
buffer.position(0);
|
||||
buffer.limit(TARGET_FOLIAGE_PER_CELL * SINGLE_FOLIAGE_DATA_SIZE_BYTES);
|
||||
//construct data texture
|
||||
Texture dataTexture = new Texture(Globals.renderingEngine.getOpenGLState(),buffer,SINGLE_FOLIAGE_DATA_SIZE_BYTES / 4,TARGET_FOLIAGE_PER_CELL);
|
||||
|
||||
//create entity
|
||||
Entity grassEntity = EntityCreationUtils.createClientSpatialEntity();
|
||||
|
||||
TextureInstancedActor.attachTextureInstancedActor(grassEntity, foliageType.getModelPath(), vertexPath, fragmentPath, dataTexture, drawCount);
|
||||
EntityUtils.getPosition(grassEntity).set(realPosition);
|
||||
EntityUtils.getRotation(grassEntity).set(0,0,0,1);
|
||||
EntityUtils.getScale(grassEntity).set(1,1,1);
|
||||
//add ambient foliage behavior tree
|
||||
AmbientFoliage.attachAmbientFoliageTree(grassEntity, 1.0f, foliageType.getGrowthModel().getGrowthRate());
|
||||
this.addEntity(grassEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert blades of grass into the entity
|
||||
* @param vX the x offset of the voxel
|
||||
* @param vY the y offset of the voxel
|
||||
* @param vZ the z offset of the voxel
|
||||
* @param floatBufferView the gpu data buffer
|
||||
* @param chunkData the chunk data
|
||||
* @return the number of blades of grass added
|
||||
*/
|
||||
protected int insertBlades(int vX, int vY, int vZ, FloatBuffer floatBufferView, ChunkData chunkData){
|
||||
int rVal = 0;
|
||||
|
||||
//get positions offset
|
||||
Vector3d voxelRealPos = new Vector3d(realPosition).add(vX,vY,vZ);
|
||||
Vector3i currVoxelPos = new Vector3i(voxelPosition).add(vY,vY,vZ);
|
||||
|
||||
//check that the current voxel even supports foliage
|
||||
boolean shouldGenerate = false;
|
||||
List<String> foliageTypesSupported = null;
|
||||
if(chunkData != null && currVoxelPos.y + 1 < ServerTerrainChunk.CHUNK_DIMENSION){
|
||||
foliageTypesSupported = Globals.gameConfigCurrent.getVoxelData().getTypeFromId(chunkData.getType(currVoxelPos)).getAmbientFoliage();
|
||||
boolean airAbove = chunkData.getType(currVoxelPos.x,currVoxelPos.y+1,currVoxelPos.z) == 0;
|
||||
if(foliageTypesSupported != null && airAbove){
|
||||
shouldGenerate = true;
|
||||
}
|
||||
}
|
||||
if(shouldGenerate){
|
||||
//construct simple grid to place foliage on
|
||||
Vector3d sample_00 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(realPosition).add(-0.5,SAMPLE_START_HEIGHT,-0.5), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||
Vector3d sample_01 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(realPosition).add(-0.5,SAMPLE_START_HEIGHT, 0), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||
Vector3d sample_02 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(realPosition).add(-0.5,SAMPLE_START_HEIGHT, 0.5), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||
Vector3d sample_10 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(realPosition).add( 0,SAMPLE_START_HEIGHT,-0.5), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||
Vector3d sample_11 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(realPosition).add( 0,SAMPLE_START_HEIGHT, 0), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||
Vector3d sample_12 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(realPosition).add( 0,SAMPLE_START_HEIGHT, 0.5), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||
Vector3d sample_20 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(realPosition).add( 0.5,SAMPLE_START_HEIGHT,-0.5), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||
Vector3d sample_21 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(realPosition).add( 0.5,SAMPLE_START_HEIGHT, 0), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||
Vector3d sample_22 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(realPosition).add( 0.5,SAMPLE_START_HEIGHT, 0.5), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||
Vector3d sample_00 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(voxelRealPos).add(-0.5,SAMPLE_START_HEIGHT,-0.5), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||
Vector3d sample_01 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(voxelRealPos).add(-0.5,SAMPLE_START_HEIGHT, 0), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||
Vector3d sample_02 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(voxelRealPos).add(-0.5,SAMPLE_START_HEIGHT, 0.5), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||
Vector3d sample_10 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(voxelRealPos).add( 0,SAMPLE_START_HEIGHT,-0.5), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||
Vector3d sample_11 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(voxelRealPos).add( 0,SAMPLE_START_HEIGHT, 0), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||
Vector3d sample_12 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(voxelRealPos).add( 0,SAMPLE_START_HEIGHT, 0.5), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||
Vector3d sample_20 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(voxelRealPos).add( 0.5,SAMPLE_START_HEIGHT,-0.5), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||
Vector3d sample_21 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(voxelRealPos).add( 0.5,SAMPLE_START_HEIGHT, 0), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||
Vector3d sample_22 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(voxelRealPos).add( 0.5,SAMPLE_START_HEIGHT, 0.5), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||
//get the heights of each sample
|
||||
float height_11 = (float)(sample_11 != null ? sample_11.y : 0);
|
||||
float height_00 = (float)(sample_00 != null ? sample_00.y : height_11);
|
||||
@ -244,14 +311,13 @@ public class FoliageCell {
|
||||
//if we don't find data for the center sample, can't place grass so don't create entity
|
||||
if(sample_11 != null){
|
||||
//generate positions to place
|
||||
int drawCount = 0;
|
||||
for(int x = 0; x < FINAL_SPACING; x++){
|
||||
for(int z = 0; z < FINAL_SPACING; z++){
|
||||
for(int x = 0; x < TARGET_FOLIAGE_SPACING; x=x+scale){
|
||||
for(int z = 0; z < TARGET_FOLIAGE_SPACING; z=z+scale){
|
||||
//get position to place
|
||||
double rand1 = placementRandomizer.nextDouble();
|
||||
double rand2 = placementRandomizer.nextDouble();
|
||||
double relativePositionOnGridX = x / (1.0 * FINAL_SPACING) + rand1 / FINAL_SPACING;
|
||||
double relativePositionOnGridZ = z / (1.0 * FINAL_SPACING) + rand2 / FINAL_SPACING;
|
||||
double relativePositionOnGridX = x / (1.0 * TARGET_FOLIAGE_SPACING) + rand1 / TARGET_FOLIAGE_SPACING;
|
||||
double relativePositionOnGridZ = z / (1.0 * TARGET_FOLIAGE_SPACING) + rand2 / TARGET_FOLIAGE_SPACING;
|
||||
double offsetX = relativePositionOnGridX - 0.5;
|
||||
double offsetZ = relativePositionOnGridZ - 0.5;
|
||||
//determine quadrant we're placing in
|
||||
@ -320,32 +386,18 @@ public class FoliageCell {
|
||||
offsetY = offsetY - realPosition.y;
|
||||
double rotVar = placementRandomizer.nextDouble() * Math.PI * 2;
|
||||
double rotVar2 = placementRandomizer.nextDouble();
|
||||
floatBufferView.put((float)offsetX);
|
||||
floatBufferView.put((float)offsetY);
|
||||
floatBufferView.put((float)offsetZ);
|
||||
floatBufferView.put((float)offsetX + vX);
|
||||
floatBufferView.put((float)offsetY + vY);
|
||||
floatBufferView.put((float)offsetZ + vZ);
|
||||
floatBufferView.put((float)rotVar);
|
||||
floatBufferView.put((float)rotVar2);
|
||||
drawCount++;
|
||||
rVal++;
|
||||
}
|
||||
}
|
||||
}
|
||||
buffer.position(0);
|
||||
buffer.limit(FINAL_SPACING * FINAL_SPACING * SINGLE_FOLIAGE_DATA_SIZE_BYTES);
|
||||
//construct data texture
|
||||
Texture dataTexture = new Texture(Globals.renderingEngine.getOpenGLState(),buffer,SINGLE_FOLIAGE_DATA_SIZE_BYTES / 4,FINAL_SPACING * FINAL_SPACING);
|
||||
|
||||
//create entity
|
||||
Entity grassEntity = EntityCreationUtils.createClientSpatialEntity();
|
||||
|
||||
TextureInstancedActor.attachTextureInstancedActor(grassEntity, foliageType.getModelPath(), vertexPath, fragmentPath, dataTexture, drawCount);
|
||||
EntityUtils.getPosition(grassEntity).set(realPosition);
|
||||
EntityUtils.getRotation(grassEntity).set(0,0,0,1);
|
||||
EntityUtils.getScale(grassEntity).set(1,1,1);
|
||||
//add ambient foliage behavior tree
|
||||
AmbientFoliage.attachAmbientFoliageTree(grassEntity, 1.0f, foliageType.getGrowthModel().getGrowthRate());
|
||||
this.addEntity(grassEntity);
|
||||
}
|
||||
}
|
||||
return rVal;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -396,7 +448,6 @@ public class FoliageCell {
|
||||
|
||||
|
||||
modelMatrix = modelMatrix.identity();
|
||||
// cameraModifiedPosition = new Vector3f((float)grassPosition.x,(float)grassPosition.y,(float)grassPosition.z).sub(cameraCenter);
|
||||
modelMatrix.translate(cameraModifiedPosition);
|
||||
modelMatrix.rotate(new Quaterniond(grassRotation));
|
||||
modelMatrix.scale(new Vector3d(EntityUtils.getScale(entity)));
|
||||
@ -500,16 +551,4 @@ public class FoliageCell {
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* Gets whether the voxel type supports foliage or not
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
private boolean typeSupportsFoliage(int type){
|
||||
if(Globals.gameConfigCurrent.getVoxelData().getTypeFromId(type) != null){
|
||||
return Globals.gameConfigCurrent.getVoxelData().getTypeFromId(type).getAmbientFoliage() != null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package electrosphere.client.foliagemanager;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import org.joml.Vector3d;
|
||||
@ -10,6 +11,7 @@ import electrosphere.engine.Globals;
|
||||
import electrosphere.entity.EntityUtils;
|
||||
import electrosphere.util.ds.octree.ChunkTree;
|
||||
import electrosphere.util.ds.octree.ChunkTree.ChunkTreeNode;
|
||||
import electrosphere.util.math.GeomUtils;
|
||||
|
||||
/**
|
||||
* A whole chunk of foliage
|
||||
@ -25,7 +27,12 @@ public class FoliageChunk {
|
||||
/**
|
||||
* The distance to draw at full resolution
|
||||
*/
|
||||
static final double FULL_RES_DIST = 15;
|
||||
static final double FULL_RES_DIST = 20;
|
||||
|
||||
/**
|
||||
* The distance for half resolution
|
||||
*/
|
||||
static final double HALF_RES_DIST = 40;
|
||||
|
||||
/**
|
||||
* The octree holding all the chunks to evaluate
|
||||
@ -68,6 +75,7 @@ public class FoliageChunk {
|
||||
this.currentChunkData = Globals.clientTerrainManager.getChunkDataAtWorldPoint(worldPos);
|
||||
// //evaluate top cells if chunk above this one exists
|
||||
this.aboveChunkData = Globals.clientTerrainManager.getChunkDataAtWorldPoint(new Vector3i(worldPos).add(0,1,0));
|
||||
this.updateCells();
|
||||
Globals.profiler.endCpuSample();
|
||||
}
|
||||
|
||||
@ -78,47 +86,13 @@ public class FoliageChunk {
|
||||
Globals.profiler.beginCpuSample("FoliageChunk.updateCells");
|
||||
Vector3d playerPos = EntityUtils.getPosition(Globals.playerEntity);
|
||||
//the sets to iterate through
|
||||
ChunkTreeNode<FoliageCell> rootNode = this.chunkTree.getRoot();
|
||||
this.recursivelyUpdateCells(rootNode, playerPos);
|
||||
//split into nodes
|
||||
// Globals.profiler.beginCpuSample("FoliageChunk.updateCells - evaluate split/join");
|
||||
// while(openSet.size() > 0){
|
||||
// ChunkTreeNode<FoliageCell> current = openSet.remove(0);
|
||||
|
||||
// if(this.shouldSplit(playerPos, current)){
|
||||
// //add children for this one
|
||||
// ChunkTreeNode<FoliageCell> container = chunkTree.split(current);
|
||||
// toInit.addAll(container.getChildren());
|
||||
// toCleanup.add(current);
|
||||
// } else if(this.shouldJoin(playerPos, current)) {
|
||||
// //add children for this one
|
||||
// ChunkTreeNode<FoliageCell> newLeaf = chunkTree.join(current);
|
||||
// toCleanup.addAll(current.getChildren());
|
||||
// toCleanup.add(current);
|
||||
// toInit.add(newLeaf);
|
||||
// } else if(!current.isLeaf()){
|
||||
// openSet.addAll(current.getChildren());
|
||||
// }
|
||||
// }
|
||||
// Globals.profiler.endCpuSample();
|
||||
// Globals.profiler.beginCpuSample("FoliageChunk.updateCells - generate");
|
||||
// //init end-nodes as leaves
|
||||
// for(ChunkTreeNode<FoliageCell> current : toInit){
|
||||
// Vector3d realPos = Globals.clientWorldData.convertWorldToRealSpace(worldPos).add(new Vector3d(current.getMinBound()));
|
||||
// current.convertToLeaf(new FoliageCell(worldPos, current.getMinBound(), realPos, 5 - current.getLevel(), 1.0f));
|
||||
// if(this.shouldGenerate(playerPos,current)){
|
||||
// current.getData().generate();
|
||||
// }
|
||||
// }
|
||||
// Globals.profiler.endCpuSample();
|
||||
// Globals.profiler.beginCpuSample("FoliageChunk.updateCells - destroy");
|
||||
// //destroy orphan nodes
|
||||
// for(ChunkTreeNode<FoliageCell> current : toCleanup){
|
||||
// if(current.getData() != null){
|
||||
// current.getData().destroy();
|
||||
// }
|
||||
// }
|
||||
// Globals.profiler.endCpuSample();
|
||||
boolean updated = true;
|
||||
int attempts = 0;
|
||||
while(updated && attempts < 3){
|
||||
ChunkTreeNode<FoliageCell> rootNode = this.chunkTree.getRoot();
|
||||
updated = this.recursivelyUpdateCells(rootNode, playerPos);
|
||||
attempts++;
|
||||
}
|
||||
Globals.profiler.endCpuSample();
|
||||
}
|
||||
|
||||
@ -127,7 +101,8 @@ public class FoliageChunk {
|
||||
* @param node The root node
|
||||
* @param playerPos The player's position
|
||||
*/
|
||||
private void recursivelyUpdateCells(ChunkTreeNode<FoliageCell> node, Vector3d playerPos){
|
||||
private boolean recursivelyUpdateCells(ChunkTreeNode<FoliageCell> node, Vector3d playerPos){
|
||||
boolean updated = false;
|
||||
if(this.shouldSplit(playerPos, node)){
|
||||
//perform op
|
||||
ChunkTreeNode<FoliageCell> container = chunkTree.split(node);
|
||||
@ -142,8 +117,9 @@ public class FoliageChunk {
|
||||
worldPos.y * ChunkData.CHUNK_SIZE + child.getMinBound().y,
|
||||
worldPos.z * ChunkData.CHUNK_SIZE + child.getMinBound().z
|
||||
);
|
||||
child.convertToLeaf(new FoliageCell(worldPos, child.getMinBound(), realPos, 5 - child.getLevel(), 1.0f));
|
||||
child.convertToLeaf(new FoliageCell(worldPos, child.getMinBound(), realPos, 5 - child.getLevel()));
|
||||
});
|
||||
updated = true;
|
||||
} else if(this.shouldJoin(playerPos, node)) {
|
||||
//perform op
|
||||
ChunkTreeNode<FoliageCell> newLeaf = chunkTree.join(node);
|
||||
@ -152,12 +128,19 @@ public class FoliageChunk {
|
||||
this.recursivelyDestroy(node);
|
||||
|
||||
//do creations
|
||||
newLeaf.convertToLeaf(new FoliageCell(worldPos, newLeaf.getMinBound(), realPos, 5 - newLeaf.getLevel(), 1.0f));
|
||||
newLeaf.convertToLeaf(new FoliageCell(worldPos, newLeaf.getMinBound(), realPos, 5 - newLeaf.getLevel()));
|
||||
updated = true;
|
||||
} else if(shouldGenerate(playerPos, node)){
|
||||
node.getData().generate();
|
||||
updated = true;
|
||||
} else if(!node.isLeaf()){
|
||||
new LinkedList<>(node.getChildren()).forEach(child -> recursivelyUpdateCells(child, playerPos));
|
||||
List<ChunkTreeNode<FoliageCell>> children = new LinkedList<ChunkTreeNode<FoliageCell>>(node.getChildren());
|
||||
for(ChunkTreeNode<FoliageCell> child : children){
|
||||
boolean childUpdate = recursivelyUpdateCells(child, playerPos);
|
||||
updated = childUpdate || updated;
|
||||
}
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -169,41 +152,15 @@ public class FoliageChunk {
|
||||
public double getMinDistance(Vector3d pos, ChunkTreeNode<FoliageCell> node){
|
||||
Vector3i min = node.getMinBound();
|
||||
Vector3i max = node.getMaxBound();
|
||||
|
||||
double minX = min.x + realPos.x;
|
||||
double minY = min.y + realPos.y;
|
||||
double minZ = min.z + realPos.z;
|
||||
|
||||
double maxX = max.x + realPos.x;
|
||||
double maxY = max.y + realPos.y;
|
||||
double maxZ = max.z + realPos.z;
|
||||
if(Math.abs(pos.x - minX) < Math.abs(pos.x - maxX)){
|
||||
if(Math.abs(pos.y - minY) < Math.abs(pos.y - maxY)){
|
||||
if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){
|
||||
return pos.distance(minX,minY,minZ);
|
||||
} else {
|
||||
return pos.distance(minX,minY,maxZ);
|
||||
}
|
||||
} else {
|
||||
if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){
|
||||
return pos.distance(minX,maxY,minZ);
|
||||
} else {
|
||||
return pos.distance(minX,maxY,maxZ);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(Math.abs(pos.y - minY) < Math.abs(pos.y - maxY)){
|
||||
if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){
|
||||
return pos.distance(maxX,minY,minZ);
|
||||
} else {
|
||||
return pos.distance(maxX,minY,maxZ);
|
||||
}
|
||||
} else {
|
||||
if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){
|
||||
return pos.distance(maxX,maxY,minZ);
|
||||
} else {
|
||||
return pos.distance(maxX,maxY,maxZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
return GeomUtils.getMinDistanceAABB(pos, new Vector3d(minX,minY,minZ), new Vector3d(maxX,maxY,maxZ));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -217,9 +174,18 @@ public class FoliageChunk {
|
||||
//to combine fullres nodes into larger nodes to conserve on draw calls
|
||||
return
|
||||
node.isLeaf() &&
|
||||
node.getLevel() < ChunkTree.MAX_LEVEL &&
|
||||
node.canSplit() &&
|
||||
this.getMinDistance(pos, node) <= FULL_RES_DIST
|
||||
(
|
||||
(
|
||||
node.getLevel() < ChunkTree.MAX_LEVEL - 1 &&
|
||||
this.getMinDistance(pos, node) <= HALF_RES_DIST
|
||||
)
|
||||
||
|
||||
(
|
||||
node.getLevel() < ChunkTree.MAX_LEVEL &&
|
||||
this.getMinDistance(pos, node) <= FULL_RES_DIST
|
||||
)
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
@ -235,7 +201,16 @@ public class FoliageChunk {
|
||||
return
|
||||
node.getLevel() > 0 &&
|
||||
!node.isLeaf() &&
|
||||
this.getMinDistance(pos, node) > FULL_RES_DIST
|
||||
(
|
||||
(
|
||||
node.getLevel() == ChunkTree.MAX_LEVEL &&
|
||||
this.getMinDistance(pos, node) > FULL_RES_DIST
|
||||
)
|
||||
||
|
||||
(
|
||||
this.getMinDistance(pos, node) > HALF_RES_DIST
|
||||
)
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
@ -247,11 +222,23 @@ public class FoliageChunk {
|
||||
*/
|
||||
public boolean shouldGenerate(Vector3d pos, ChunkTreeNode<FoliageCell> node){
|
||||
return
|
||||
node.getLevel() == ChunkTree.MAX_LEVEL &&
|
||||
node.isLeaf() &&
|
||||
node.getData() != null &&
|
||||
node.getData().containedEntities.size() < 1 &&
|
||||
this.getMinDistance(pos, node) <= FULL_RES_DIST;
|
||||
(
|
||||
(
|
||||
node.getLevel() == ChunkTree.MAX_LEVEL
|
||||
// &&
|
||||
// this.getMinDistance(pos, node) <= FULL_RES_DIST
|
||||
)
|
||||
||
|
||||
(
|
||||
node.getLevel() == ChunkTree.MAX_LEVEL - 1
|
||||
&&
|
||||
this.getMinDistance(pos, node) <= HALF_RES_DIST
|
||||
)
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -262,7 +249,8 @@ public class FoliageChunk {
|
||||
public boolean shouldDestroy(ChunkTreeNode<FoliageCell> node){
|
||||
return
|
||||
node.getData() != null &&
|
||||
node.getData().containedEntities.size() > 0;
|
||||
node.getData().containedEntities.size() > 0
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -3,7 +3,6 @@ package electrosphere.client.terrain.cells;
|
||||
import org.joml.Quaterniond;
|
||||
import org.joml.Vector3d;
|
||||
import org.joml.Vector3i;
|
||||
import org.ode4j.ode.DBody;
|
||||
|
||||
import electrosphere.client.terrain.cache.ChunkData;
|
||||
import electrosphere.collision.CollisionEngine;
|
||||
@ -36,9 +35,6 @@ public class DrawCell {
|
||||
|
||||
//the main entity for the cell
|
||||
Entity modelEntity;
|
||||
|
||||
//the physics mesh
|
||||
DBody physicsObject;
|
||||
|
||||
//Allocated once instead of continuously, used to generate the visual/physics models
|
||||
float[][][] weights = new float[ChunkData.CHUNK_DATA_GENERATOR_SIZE][ChunkData.CHUNK_DATA_GENERATOR_SIZE][ChunkData.CHUNK_DATA_GENERATOR_SIZE];
|
||||
|
||||
@ -490,6 +490,20 @@ public class DrawCellManager {
|
||||
atlas = voxelTextureAtlas;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the draw cell at the given world position has generated physics
|
||||
* @param worldPos The world position
|
||||
* @return true if has generated physics, false otherwise
|
||||
*/
|
||||
public boolean generatedPhysics(Vector3i worldPos){
|
||||
String key = this.getCellKey(worldPos.x, worldPos.y, worldPos.z);
|
||||
if(!keyCellMap.containsKey(key)){
|
||||
return false;
|
||||
}
|
||||
DrawCell cell = this.keyCellMap.get(key);
|
||||
return cell.modelEntity != null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
transvoxel algorithm spacing management
|
||||
|
||||
105
src/main/java/electrosphere/util/math/GeomUtils.java
Normal file
105
src/main/java/electrosphere/util/math/GeomUtils.java
Normal file
@ -0,0 +1,105 @@
|
||||
package electrosphere.util.math;
|
||||
|
||||
import org.joml.Vector3d;
|
||||
|
||||
/**
|
||||
* Utilities for dealing with geometry
|
||||
*/
|
||||
public class GeomUtils {
|
||||
|
||||
/**
|
||||
* Gets the minimum distance from a point to an axis aligned cube
|
||||
* @param pos the position to check against
|
||||
* @param cubeMin The min position of the cube
|
||||
* @param cubeMax The max position of the cube
|
||||
* @return the distance
|
||||
*/
|
||||
public static double getMinDistanceAABB(Vector3d pos, Vector3d cubeMin, Vector3d cubeMax){
|
||||
double minX = cubeMin.x;
|
||||
double minY = cubeMin.y;
|
||||
double minZ = cubeMin.z;
|
||||
double maxX = cubeMax.x;
|
||||
double maxY = cubeMax.y;
|
||||
double maxZ = cubeMax.z;
|
||||
if(pos.x > minX && pos.x < maxX){
|
||||
if(pos.y > minY && pos.y < maxY){
|
||||
if(pos.z > minZ && pos.z < maxZ){
|
||||
return 0;
|
||||
} else if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){
|
||||
return pos.distance(pos.x,pos.y,minZ);
|
||||
} else {
|
||||
return pos.distance(pos.x,pos.y,maxZ);
|
||||
}
|
||||
} else if(Math.abs(pos.y - minY) < Math.abs(pos.y - maxY)){
|
||||
if(pos.z > minZ && pos.z < maxZ){
|
||||
return pos.distance(pos.x,minY,pos.z);
|
||||
} else if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){
|
||||
return pos.distance(pos.x,minY,minZ);
|
||||
} else {
|
||||
return pos.distance(pos.x,minY,maxZ);
|
||||
}
|
||||
} else {
|
||||
if(pos.z > minZ && pos.z < maxZ){
|
||||
return pos.distance(pos.x,maxY,pos.z);
|
||||
} else if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){
|
||||
return pos.distance(pos.x,maxY,minZ);
|
||||
} else {
|
||||
return pos.distance(pos.x,maxY,maxZ);
|
||||
}
|
||||
}
|
||||
} else if(Math.abs(pos.x - minX) < Math.abs(pos.x - maxX)){
|
||||
if(pos.y > minY && pos.y < maxY){
|
||||
if(pos.z > minZ && pos.z < maxZ){
|
||||
return pos.distance(minX,pos.y,pos.z);
|
||||
} else if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){
|
||||
return pos.distance(minX,pos.y,minZ);
|
||||
} else {
|
||||
return pos.distance(minX,pos.y,maxZ);
|
||||
}
|
||||
} else if(Math.abs(pos.y - minY) < Math.abs(pos.y - maxY)){
|
||||
if(pos.z > minZ && pos.z < maxZ){
|
||||
return pos.distance(minX,minY,pos.z);
|
||||
} else if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){
|
||||
return pos.distance(minX,minY,minZ);
|
||||
} else {
|
||||
return pos.distance(minX,minY,maxZ);
|
||||
}
|
||||
} else {
|
||||
if(pos.z > minZ && pos.z < maxZ){
|
||||
return pos.distance(minX,maxY,pos.z);
|
||||
} else if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){
|
||||
return pos.distance(minX,maxY,minZ);
|
||||
} else {
|
||||
return pos.distance(minX,maxY,maxZ);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(pos.y > minY && pos.y < maxY){
|
||||
if(pos.z > minZ && pos.z < maxZ){
|
||||
return pos.distance(maxX,pos.y,pos.z);
|
||||
} else if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){
|
||||
return pos.distance(maxX,pos.y,minZ);
|
||||
} else {
|
||||
return pos.distance(maxX,pos.y,maxZ);
|
||||
}
|
||||
} else if(Math.abs(pos.y - minY) < Math.abs(pos.y - maxY)){
|
||||
if(pos.z > minZ && pos.z < maxZ){
|
||||
return pos.distance(maxX,minY,pos.z);
|
||||
} else if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){
|
||||
return pos.distance(maxX,minY,minZ);
|
||||
} else {
|
||||
return pos.distance(maxX,minY,maxZ);
|
||||
}
|
||||
} else {
|
||||
if(pos.z > minZ && pos.z < maxZ){
|
||||
return pos.distance(maxX,maxY,pos.z);
|
||||
} else if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){
|
||||
return pos.distance(maxX,maxY,minZ);
|
||||
} else {
|
||||
return pos.distance(maxX,maxY,maxZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
44
src/test/java/electrosphere/util/math/GeomUtilsTests.java
Normal file
44
src/test/java/electrosphere/util/math/GeomUtilsTests.java
Normal file
@ -0,0 +1,44 @@
|
||||
package electrosphere.util.math;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import org.joml.Vector3d;
|
||||
|
||||
import electrosphere.test.annotations.UnitTest;
|
||||
|
||||
/**
|
||||
* Tests for geometry utils
|
||||
*/
|
||||
public class GeomUtilsTests {
|
||||
|
||||
@UnitTest
|
||||
public void test_getMinDistanceAABB_center_0(){
|
||||
assertEquals(0, GeomUtils.getMinDistanceAABB(new Vector3d(1,1,1), new Vector3d(0,0,0), new Vector3d(2,2,2)));
|
||||
}
|
||||
|
||||
@UnitTest
|
||||
public void test_getMinDistanceAABB_xSide_1(){
|
||||
assertEquals(1, GeomUtils.getMinDistanceAABB(new Vector3d(3,0,0), new Vector3d(0,0,0), new Vector3d(2,2,2)));
|
||||
}
|
||||
|
||||
@UnitTest
|
||||
public void test_getMinDistanceAABB_ySide_1(){
|
||||
assertEquals(1, GeomUtils.getMinDistanceAABB(new Vector3d(0,3,0), new Vector3d(0,0,0), new Vector3d(2,2,2)));
|
||||
}
|
||||
|
||||
@UnitTest
|
||||
public void test_getMinDistanceAABB_zSide_1(){
|
||||
assertEquals(1, GeomUtils.getMinDistanceAABB(new Vector3d(0,0,3), new Vector3d(0,0,0), new Vector3d(2,2,2)));
|
||||
}
|
||||
|
||||
@UnitTest
|
||||
public void test_getMinDistanceAABB_angle_1(){
|
||||
assertEquals(Math.sqrt(2), GeomUtils.getMinDistanceAABB(new Vector3d(3,3,1), new Vector3d(0,0,0), new Vector3d(2,2,2)));
|
||||
}
|
||||
|
||||
@UnitTest
|
||||
public void test_getMinDistanceAABB_angle_2(){
|
||||
assertEquals(Math.sqrt(3), GeomUtils.getMinDistanceAABB(new Vector3d(3,3,3), new Vector3d(0,0,0), new Vector3d(2,2,2)));
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user