diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index 896e70a7..03eae528 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -1391,6 +1391,7 @@ ServerGroundMovementTree concurrent modify fix TransvoxelModelGeneration allocation reduction More allocation reduction Vector pooling +Simplify WorldOctTree to reduce lag with large node counts diff --git a/src/main/java/electrosphere/client/terrain/cells/ClientDrawCellManager.java b/src/main/java/electrosphere/client/terrain/cells/ClientDrawCellManager.java index ab8ed648..e230a4cf 100644 --- a/src/main/java/electrosphere/client/terrain/cells/ClientDrawCellManager.java +++ b/src/main/java/electrosphere/client/terrain/cells/ClientDrawCellManager.java @@ -640,10 +640,14 @@ public class ClientDrawCellManager { this.recursivelyDestroy(node); //perform op + Globals.profiler.beginCpuSample("ClientDrawCellManager.join - Perform Op"); DrawCell newLeafCell = DrawCell.generateTerrainCell(node.getMinBound(),node.getData().lod); + Globals.profiler.beginCpuSample("ClientDrawCellManager.join - Perform Op - Tree join"); WorldOctTreeNode newLeaf = chunkTree.join(node, newLeafCell); + Globals.profiler.endCpuSample(); newLeaf.getData().transferChunkData(node.getData()); newLeaf.getData().setHasGenerated(false); + Globals.profiler.endCpuSample(); //update neighbors this.conditionalUpdateAdjacentNodes(newLeaf, newLeaf.getLevel()); diff --git a/src/main/java/electrosphere/engine/assetmanager/AssetManager.java b/src/main/java/electrosphere/engine/assetmanager/AssetManager.java index 0304e798..8ebeb1d4 100644 --- a/src/main/java/electrosphere/engine/assetmanager/AssetManager.java +++ b/src/main/java/electrosphere/engine/assetmanager/AssetManager.java @@ -92,6 +92,7 @@ public class AssetManager { public void loadAssetsInQueue(){ //models LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Load models"); + Globals.profiler.beginCpuSample("AssetManager.loadAssetsInQueue - Load Models"); for(String currentPath : modelsInQueue){ modelsInQueue.remove(currentPath); AIScene aiScene = ModelLoader.loadAIScene(currentPath); @@ -113,22 +114,28 @@ public class AssetManager { } } } + Globals.profiler.endCpuSample(); //textures from disk to gpu LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Load textures"); + Globals.profiler.beginCpuSample("AssetManager.loadAssetsInQueue - Load textures"); for(String currentPath : texturesInQueue){ texturesInQueue.remove(currentPath); texturesLoadedIntoMemory.put(currentPath, new Texture(Globals.renderingEngine.getOpenGLState(), currentPath)); } + Globals.profiler.endCpuSample(); //audio from disk LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Load audio"); + Globals.profiler.beginCpuSample("AssetManager.loadAssetsInQueue - Load audio"); if(Globals.audioEngine != null && Globals.audioEngine.initialized()){ for(String currentPath : audioInQueue){ audioInQueue.remove(currentPath); audioLoadedIntoMemory.put(currentPath, new AudioBuffer(currentPath)); } } + Globals.profiler.endCpuSample(); //shaders - LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Load shaders"); + LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Load visual shaders"); + Globals.profiler.beginCpuSample("AssetManager.loadAssetsInQueue - Load visual shaders"); for(ActorShaderMask currentShader : shadersInQueue){ shadersInQueue.remove(currentShader); String key = getShaderKey(currentShader.getVertexShaderPath(),currentShader.getFragmentShaderPath()); @@ -137,8 +144,10 @@ public class AssetManager { VisualShader.loadSpecificShader(currentShader.getVertexShaderPath(),currentShader.getFragmentShaderPath()) ); } + Globals.profiler.endCpuSample(); //compute shaders LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Load compute shaders"); + Globals.profiler.beginCpuSample("AssetManager.loadAssetsInQueue - Load compute shaders"); for(String computePath : computeShadersInQueue){ computeShadersInQueue.remove(computePath); String key = getComputeShaderKey(computePath); @@ -151,15 +160,19 @@ public class AssetManager { e.printStackTrace(); } } + Globals.profiler.endCpuSample(); //pose models LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Load pose models"); + Globals.profiler.beginCpuSample("AssetManager.loadAssetsInQueue - Load pose models"); for(String currentPath: poseModelsInQueue){ poseModelsInQueue.remove(currentPath); AIScene scene = ModelLoader.loadAIScene(currentPath); poseModelsLoadedIntoMemory.put(currentPath, new PoseModel(currentPath, scene)); } + Globals.profiler.endCpuSample(); //queued assets LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Load queued assets"); + Globals.profiler.beginCpuSample("AssetManager.loadAssetsInQueue - Load queued assets"); queuedAssetLock.lock(); for(QueuedAsset queuedAsset : queuedAssets){ queuedAsset.load(); @@ -171,14 +184,19 @@ public class AssetManager { } queuedAssets.clear(); queuedAssetLock.unlock(); + Globals.profiler.endCpuSample(); //allocate homogenous buffers LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Allocate homogenous buffers"); + Globals.profiler.beginCpuSample("AssetManager.loadAssetsInQueue - Allocate homogenous buffers"); this.allocateHomogenousBuffers(); + Globals.profiler.endCpuSample(); //allocate instance array buffers LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Allocate instance array buffers"); + Globals.profiler.beginCpuSample("AssetManager.loadAssetsInQueue - Allocate instance array buffers"); this.allocateInstanceArrayBuffers(); + Globals.profiler.endCpuSample(); //override meshes LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Override meshes"); diff --git a/src/main/java/electrosphere/renderer/pipelines/MainContentPipeline.java b/src/main/java/electrosphere/renderer/pipelines/MainContentPipeline.java index c734fcbc..43a2476f 100644 --- a/src/main/java/electrosphere/renderer/pipelines/MainContentPipeline.java +++ b/src/main/java/electrosphere/renderer/pipelines/MainContentPipeline.java @@ -116,9 +116,9 @@ public class MainContentPipeline implements RenderPipeline { scaleVec.set(EntityUtils.getScale(currentEntity)) ); //set actor value - currentActor.setAttribute(modelAttribute, modelTransformMatrix); + currentActor.setAttribute(modelAttribute, new Matrix4d(modelTransformMatrix)); //draw - currentActor.draw(renderPipelineState, cameraModifiedPosition); + currentActor.draw(renderPipelineState, new Vector3d(cameraModifiedPosition)); } else { currentActor.draw(renderPipelineState); } @@ -199,9 +199,9 @@ public class MainContentPipeline implements RenderPipeline { scaleVec.set(EntityUtils.getScale(currentEntity)) ); //set actor value - currentActor.setAttribute(modelAttribute, modelTransformMatrix); + currentActor.setAttribute(modelAttribute, new Matrix4d(modelTransformMatrix)); //draw - currentActor.draw(renderPipelineState, cameraModifiedPosition); + currentActor.draw(renderPipelineState, new Vector3d(cameraModifiedPosition)); } else { currentActor.draw(renderPipelineState); } diff --git a/src/main/java/electrosphere/renderer/pipelines/ShadowMapPipeline.java b/src/main/java/electrosphere/renderer/pipelines/ShadowMapPipeline.java index a8eca98d..f55f446f 100644 --- a/src/main/java/electrosphere/renderer/pipelines/ShadowMapPipeline.java +++ b/src/main/java/electrosphere/renderer/pipelines/ShadowMapPipeline.java @@ -113,14 +113,14 @@ public class ShadowMapPipeline implements RenderPipeline { //fetch actor Actor currentActor = EntityUtils.getActor(currentEntity); //calculate camera-modified vector3d - Vector3d cameraCenter = posVec.set(CameraEntityUtils.getCameraCenter(Globals.playerCamera)); - Vector3d cameraModifiedPosition = position.sub(cameraCenter); + Vector3d cameraCenter = scaleVec.set(CameraEntityUtils.getCameraCenter(Globals.playerCamera)); + Vector3d cameraModifiedPosition = posVec.set(position).sub(cameraCenter); //calculate and apply model transform modelTransformMatrix = modelTransformMatrix.identity(); modelTransformMatrix.translate(cameraModifiedPosition); modelTransformMatrix.rotate(EntityUtils.getRotation(currentEntity)); modelTransformMatrix.scale(scaleVec.set(EntityUtils.getScale(currentEntity))); - currentActor.applySpatialData(modelTransformMatrix,position); + currentActor.applySpatialData(new Matrix4d(modelTransformMatrix),new Vector3d(position)); //draw currentActor.draw(renderPipelineState,openGLState); } diff --git a/src/main/java/electrosphere/util/ds/octree/WorldOctTree.java b/src/main/java/electrosphere/util/ds/octree/WorldOctTree.java index 5a3b3e91..8ba330fa 100644 --- a/src/main/java/electrosphere/util/ds/octree/WorldOctTree.java +++ b/src/main/java/electrosphere/util/ds/octree/WorldOctTree.java @@ -1,11 +1,11 @@ package electrosphere.util.ds.octree; -import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import org.joml.Vector3i; +import electrosphere.engine.Globals; import io.github.studiorailgun.MathUtils; /** @@ -22,11 +22,6 @@ public class WorldOctTree { */ private WorldOctTreeNode root = null; - /** - * The list of all nodes in the tree - */ - List> nodes = null; - /** * The minimum position */ @@ -59,10 +54,8 @@ public class WorldOctTree { //calculate max level int dimRaw = max.x - min.x; this.maxLevel = (int)MathUtils.log2(dimRaw); - this.nodes = new ArrayList>(); this.root = new WorldOctTreeNode(this, 0, new Vector3i(min), new Vector3i(max)); this.root.setLeaf(true); - this.nodes.add(this.root); } /** @@ -112,11 +105,6 @@ public class WorldOctTree { //replace existing node replaceNode(existing,newContainer); - //update tracking - this.nodes.remove(existing); - this.nodes.add(newContainer); - this.nodes.addAll(newContainer.getChildren()); - return newContainer; } @@ -130,20 +118,23 @@ public class WorldOctTree { if(existing.isLeaf()){ throw new IllegalArgumentException("Tried to split non-leaf!"); } + Globals.profiler.beginCpuSample("WorldOctTree.join - allocation"); Vector3i min = existing.getMinBound(); Vector3i max = existing.getMaxBound(); int currentLevel = existing.getLevel(); WorldOctTreeNode newContainer = new WorldOctTreeNode<>(this, currentLevel, min, max); newContainer.setData(data); newContainer.setLeaf(true); + Globals.profiler.endCpuSample(); //replace existing node + Globals.profiler.beginCpuSample("WorldOctTree.join - replace"); this.replaceNode(existing,newContainer); + Globals.profiler.endCpuSample(); //update tracking - this.nodes.remove(existing); - this.nodes.removeAll(existing.getChildren()); - this.nodes.add(newContainer); + Globals.profiler.beginCpuSample("WorldOctTree.join - tracking"); + Globals.profiler.endCpuSample(); return newContainer; } @@ -191,10 +182,8 @@ public class WorldOctTree { * Clears the tree */ public void clear(){ - this.nodes.clear(); this.root = new WorldOctTreeNode(this, 0, new Vector3i(min), new Vector3i(max)); this.root.isLeaf = true; - this.nodes.add(this.root); } /** @@ -275,7 +264,22 @@ public class WorldOctTree { * @return The number of nodes */ public int getNodeCount(){ - return nodes.size(); + return this.recursivelyCountNotes(this.root); + } + + /** + * Recursively counts all nodes + * @param searchTarget The root node + * @return The number of nodes underneath this one + */ + private int recursivelyCountNotes(WorldOctTreeNode searchTarget){ + int rVal = 1; + if(searchTarget.children.size() > 0){ + for(WorldOctTreeNode child : searchTarget.children){ + rVal += this.recursivelyCountNotes(child); + } + } + return rVal; }