foliage manager fixes
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit
This commit is contained in:
parent
742c606540
commit
8430439509
@ -61,15 +61,19 @@ public class ClientFoliageManager {
|
||||
for(int x = -chunkRadius; x < chunkRadius+1; x++){
|
||||
for(int y = -chunkRadius; y < chunkRadius+1; y++){
|
||||
for(int z = -chunkRadius; z < chunkRadius+1; z++){
|
||||
Vector3i worldPos = Globals.clientWorldData.convertRealToWorldSpace(EntityUtils.getPosition(Globals.playerEntity));
|
||||
updatePosition(worldPos);
|
||||
Vector3i worldPos = Globals.clientWorldData.convertRealToWorldSpace(EntityUtils.getPosition(Globals.playerEntity)).add(x,y,z);
|
||||
if(Globals.clientWorldData.worldPosInBounds(worldPos)){
|
||||
this.updatePosition(worldPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Globals.profiler.beginCpuSample("ClientFoliageManager.update - destroy chunks");
|
||||
for(FoliageChunk chunk : this.chunkUpdateCache){
|
||||
chunk.destroy();
|
||||
}
|
||||
this.chunkUpdateCache.clear();
|
||||
Globals.profiler.endCpuSample();
|
||||
}
|
||||
Globals.profiler.endCpuSample();
|
||||
}
|
||||
|
||||
@ -22,8 +22,6 @@ import electrosphere.client.terrain.cache.ChunkData;
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.entity.Entity;
|
||||
import electrosphere.entity.EntityCreationUtils;
|
||||
import electrosphere.entity.EntityDataStrings;
|
||||
import electrosphere.entity.EntityTags;
|
||||
import electrosphere.entity.EntityUtils;
|
||||
import electrosphere.entity.state.foliage.AmbientFoliage;
|
||||
import electrosphere.entity.types.camera.CameraEntityUtils;
|
||||
@ -344,7 +342,7 @@ public class FoliageCell {
|
||||
EntityUtils.getRotation(grassEntity).set(0,0,0,1);
|
||||
EntityUtils.getScale(grassEntity).set(1,1,1);
|
||||
//add ambient foliage behavior tree
|
||||
AmbientFoliage.attachAmbientFoliageTree(grassEntity, 0.0f, foliageType.getGrowthModel().getGrowthRate());
|
||||
AmbientFoliage.attachAmbientFoliageTree(grassEntity, 1.0f, foliageType.getGrowthModel().getGrowthRate());
|
||||
this.addEntity(grassEntity);
|
||||
}
|
||||
}
|
||||
@ -384,9 +382,9 @@ public class FoliageCell {
|
||||
RenderPipelineState renderPipelineState = Globals.renderingEngine.getRenderPipelineState();
|
||||
OpenGLState openGLState = Globals.renderingEngine.getOpenGLState();
|
||||
|
||||
Vector3f cameraModifiedPosition = new Vector3f((float)realPosition.x,(float)realPosition.y,(float)realPosition.z).sub(CameraEntityUtils.getCameraCenter(Globals.playerCamera));
|
||||
Vector3f cameraModifiedPosition = new Vector3f((float)realPosition.x,(float)realPosition.y,(float)realPosition.z).sub(cameraCenter);
|
||||
//frustum check entire cell
|
||||
boolean shouldRender = true;//renderPipelineState.getFrustumIntersection().testSphere((float)(cameraModifiedPosition.x + boundingSphere.x), (float)(cameraModifiedPosition.y + boundingSphere.y), (float)(cameraModifiedPosition.z + boundingSphere.z), (float)(boundingSphere.r));
|
||||
boolean shouldRender = renderPipelineState.getFrustumIntersection().testSphere((float)(cameraModifiedPosition.x + boundingSphere.x), (float)(cameraModifiedPosition.y + boundingSphere.y), (float)(cameraModifiedPosition.z + boundingSphere.z), (float)(boundingSphere.r));
|
||||
if(shouldRender){
|
||||
//disable frustum check and instead perform at cell level
|
||||
boolean currentFrustumCheckState = renderPipelineState.shouldFrustumCheck();
|
||||
@ -398,7 +396,7 @@ public class FoliageCell {
|
||||
|
||||
|
||||
modelMatrix = modelMatrix.identity();
|
||||
cameraModifiedPosition = new Vector3f((float)grassPosition.x,(float)grassPosition.y,(float)grassPosition.z).sub(cameraCenter);
|
||||
// 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)));
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package electrosphere.client.foliagemanager;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.joml.Vector3d;
|
||||
import org.joml.Vector3i;
|
||||
@ -65,80 +64,100 @@ public class FoliageChunk {
|
||||
* Initializes all cells in the chunk
|
||||
*/
|
||||
public void initCells(){
|
||||
Vector3d playerPos = EntityUtils.getPosition(Globals.playerEntity);
|
||||
Globals.profiler.beginCpuSample("FoliageChunk.initCells");
|
||||
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));
|
||||
|
||||
//the sets to iterate through
|
||||
ChunkTreeNode<FoliageCell> rootNode = this.chunkTree.getRoot();
|
||||
List<ChunkTreeNode<FoliageCell>> openSet = new LinkedList<ChunkTreeNode<FoliageCell>>();
|
||||
List<ChunkTreeNode<FoliageCell>> toInit = new LinkedList<ChunkTreeNode<FoliageCell>>();
|
||||
openSet.add(rootNode);
|
||||
|
||||
//split into nodes
|
||||
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);
|
||||
openSet.addAll(container.getChildren());
|
||||
} else {
|
||||
//do nothing
|
||||
toInit.add(current);
|
||||
}
|
||||
}
|
||||
//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, 4 - current.getLevel(), 1.0f));
|
||||
current.getData().generate();
|
||||
}
|
||||
Globals.profiler.endCpuSample();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates all cells in the chunk
|
||||
*/
|
||||
public void updateCells(){
|
||||
Globals.profiler.beginCpuSample("FoliageChunk.updateCells");
|
||||
Vector3d playerPos = EntityUtils.getPosition(Globals.playerEntity);
|
||||
//the sets to iterate through
|
||||
ChunkTreeNode<FoliageCell> rootNode = this.chunkTree.getRoot();
|
||||
List<ChunkTreeNode<FoliageCell>> openSet = new LinkedList<ChunkTreeNode<FoliageCell>>();
|
||||
List<ChunkTreeNode<FoliageCell>> toInit = new LinkedList<ChunkTreeNode<FoliageCell>>();
|
||||
List<ChunkTreeNode<FoliageCell>> toCleanup = new LinkedList<ChunkTreeNode<FoliageCell>>();
|
||||
openSet.add(rootNode);
|
||||
this.recursivelyUpdateCells(rootNode, playerPos);
|
||||
//split into nodes
|
||||
while(openSet.size() > 0){
|
||||
ChunkTreeNode<FoliageCell> current = openSet.remove(0);
|
||||
// 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());
|
||||
}
|
||||
// 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();
|
||||
Globals.profiler.endCpuSample();
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively update child nodes
|
||||
* @param node The root node
|
||||
* @param playerPos The player's position
|
||||
*/
|
||||
private void recursivelyUpdateCells(ChunkTreeNode<FoliageCell> node, Vector3d playerPos){
|
||||
if(this.shouldSplit(playerPos, node)){
|
||||
//perform op
|
||||
ChunkTreeNode<FoliageCell> container = chunkTree.split(node);
|
||||
|
||||
//do deletions
|
||||
this.recursivelyDestroy(node);
|
||||
|
||||
//do creations
|
||||
container.getChildren().forEach(child -> {
|
||||
Vector3d realPos = new Vector3d(
|
||||
worldPos.x * ChunkData.CHUNK_SIZE + child.getMinBound().x,
|
||||
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));
|
||||
});
|
||||
} else if(this.shouldJoin(playerPos, node)) {
|
||||
//perform op
|
||||
ChunkTreeNode<FoliageCell> newLeaf = chunkTree.join(node);
|
||||
|
||||
//do deletions
|
||||
this.recursivelyDestroy(node);
|
||||
|
||||
//do creations
|
||||
newLeaf.convertToLeaf(new FoliageCell(worldPos, newLeaf.getMinBound(), realPos, 5 - newLeaf.getLevel(), 1.0f));
|
||||
} else if(shouldGenerate(playerPos, node)){
|
||||
node.getData().generate();
|
||||
} else if(!node.isLeaf()){
|
||||
new LinkedList<>(node.getChildren()).forEach(child -> recursivelyUpdateCells(child, playerPos));
|
||||
}
|
||||
//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));
|
||||
current.getData().generate();
|
||||
}
|
||||
//destroy orphan nodes
|
||||
for(ChunkTreeNode<FoliageCell> current : toCleanup){
|
||||
if(current.getData() != null){
|
||||
current.getData().destroy();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -196,9 +215,11 @@ public class FoliageChunk {
|
||||
public boolean shouldSplit(Vector3d pos, ChunkTreeNode<FoliageCell> node){
|
||||
//breaking out into dedicated function so can add case handling ie if we want
|
||||
//to combine fullres nodes into larger nodes to conserve on draw calls
|
||||
return this.getMinDistance(pos, node) <= FULL_RES_DIST &&
|
||||
return
|
||||
node.isLeaf() &&
|
||||
node.canSplit()
|
||||
node.getLevel() < ChunkTree.MAX_LEVEL &&
|
||||
node.canSplit() &&
|
||||
this.getMinDistance(pos, node) <= FULL_RES_DIST
|
||||
;
|
||||
}
|
||||
|
||||
@ -211,17 +232,56 @@ public class FoliageChunk {
|
||||
public boolean shouldJoin(Vector3d pos, ChunkTreeNode<FoliageCell> node){
|
||||
//breaking out into dedicated function so can add case handling ie if we want
|
||||
//to combine fullres nodes into larger nodes to conserve on draw calls
|
||||
return this.getMinDistance(pos, node) > FULL_RES_DIST &&
|
||||
!node.isLeaf()
|
||||
return
|
||||
node.getLevel() > 0 &&
|
||||
!node.isLeaf() &&
|
||||
this.getMinDistance(pos, node) > FULL_RES_DIST
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this cell should generate
|
||||
* @param pos the player's position
|
||||
* @param node the node
|
||||
* @return true if should generate, false otherwise
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the node should have destroy called on it
|
||||
* @param node The node
|
||||
* @return true if should destroy, false otherwise
|
||||
*/
|
||||
public boolean shouldDestroy(ChunkTreeNode<FoliageCell> node){
|
||||
return
|
||||
node.getData() != null &&
|
||||
node.getData().containedEntities.size() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the foliage chunk
|
||||
*/
|
||||
protected void destroy(){
|
||||
for(ChunkTreeNode<FoliageCell> leaf : this.chunkTree.getLeaves()){
|
||||
leaf.getData().destroy();
|
||||
this.recursivelyDestroy(this.chunkTree.getRoot());
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively destroy a tree
|
||||
* @param node The root of the tree
|
||||
*/
|
||||
private void recursivelyDestroy(ChunkTreeNode<FoliageCell> node){
|
||||
if(node.getChildren().size() > 0){
|
||||
node.getChildren().forEach(child -> recursivelyDestroy(child));
|
||||
}
|
||||
if(node.getData() != null){
|
||||
node.getData().destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,8 +289,19 @@ public class FoliageChunk {
|
||||
* Draws all cells in the chunk
|
||||
*/
|
||||
protected void draw(){
|
||||
for(ChunkTreeNode<FoliageCell> leaf : this.chunkTree.getLeaves()){
|
||||
leaf.getData().draw();
|
||||
recursivelyDraw(this.chunkTree.getRoot());
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively draws all nodes
|
||||
* @param node The root node
|
||||
*/
|
||||
private void recursivelyDraw(ChunkTreeNode<FoliageCell> node){
|
||||
if(node.getChildren().size() > 0){
|
||||
node.getChildren().forEach(child -> recursivelyDraw(child));
|
||||
}
|
||||
if(node.getData() != null){
|
||||
node.getData().draw();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -93,6 +93,21 @@ public class ClientWorldData {
|
||||
return convertChunkToRealSpace(world);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a world position is in bounds or not
|
||||
* @param worldPos The world position
|
||||
* @return true if is in bounds, false otherwise
|
||||
*/
|
||||
public boolean worldPosInBounds(Vector3i worldPos){
|
||||
return worldPos.x >= convertRealToWorld(worldMinPoint.x) &&
|
||||
worldPos.x < convertRealToWorld(worldMaxPoint.x) &&
|
||||
worldPos.y >= convertRealToWorld(worldMinPoint.y) &&
|
||||
worldPos.y < convertRealToWorld(worldMaxPoint.y) &&
|
||||
worldPos.z >= convertRealToWorld(worldMinPoint.z) &&
|
||||
worldPos.z < convertRealToWorld(worldMaxPoint.z)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a real space position to its world space equivalent
|
||||
* @param position The real space position
|
||||
|
||||
@ -447,6 +447,10 @@ public class Main {
|
||||
if(Globals.netMonitor != null){
|
||||
Globals.netMonitor.close();
|
||||
}
|
||||
//shutdown profiler
|
||||
if(Globals.profiler != null){
|
||||
Globals.profiler.destroy();
|
||||
}
|
||||
//shutdown ode
|
||||
if(initOde){
|
||||
OdeHelper.closeODE();
|
||||
|
||||
@ -69,4 +69,13 @@ public class Profiler {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the profiler
|
||||
*/
|
||||
public void destroy(){
|
||||
if(PROFILE){
|
||||
Remotery.rmt_DestroyGlobalInstance(pointer);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -29,7 +29,7 @@ public class TerrainProtocol implements ClientProtocolTemplate<TerrainMessage> {
|
||||
Globals.clientWorldData = new ClientWorldData(
|
||||
//Vector3f worldMinPoint, Vector3f worldMaxPoint, int dynamicInterpolationRatio, float randomDampener, int worldDiscreteSize
|
||||
new Vector3f(message.getworldMinX(),0,message.getworldMinY()),
|
||||
new Vector3f(message.getworldMaxX(),3,message.getworldMaxY()),
|
||||
new Vector3f(message.getworldMaxX(),32,message.getworldMaxY()),
|
||||
ChunkData.CHUNK_SIZE,
|
||||
message.getrandomDampener(),
|
||||
message.getworldSizeDiscrete()
|
||||
|
||||
@ -126,21 +126,6 @@ public class ChunkTree<T> {
|
||||
return this.root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of leaves in the tree
|
||||
*/
|
||||
public int getNumLeaves() {
|
||||
return this.getLeaves().size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all leaf nodes
|
||||
* @return All leaf nodes
|
||||
*/
|
||||
public List<ChunkTreeNode<T>> getLeaves(){
|
||||
return this.nodes.stream().filter(node -> node.isLeaf()).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A node in a chunk tree
|
||||
|
||||
@ -0,0 +1,10 @@
|
||||
package electrosphere.util.ds.octree;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* Unit testing for the chunk octree implementation
|
||||
*/
|
||||
public class ChunkTreeTests {
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user