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()); | ||||
|             } | ||||
|         } | ||||
|         //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(); | ||||
|             } | ||||
|         } | ||||
|         //     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)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -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