From bdadc3c7394900afff70daee311c00ae434a6ba5 Mon Sep 17 00:00:00 2001 From: Dejvino Date: Wed, 25 Jan 2017 00:38:14 +0100 Subject: [PATCH] Map: Fine-grained terrain grid implemented. Now there is smoother loading and unloading of terrain tiles. --- src/roadtrip/view/FineTerrainGrid.java | 68 ++++++++++++++------------ src/roadtrip/view/GameWorldView.java | 20 +++++--- 2 files changed, 49 insertions(+), 39 deletions(-) diff --git a/src/roadtrip/view/FineTerrainGrid.java b/src/roadtrip/view/FineTerrainGrid.java index d80b3a0..ec33b5b 100644 --- a/src/roadtrip/view/FineTerrainGrid.java +++ b/src/roadtrip/view/FineTerrainGrid.java @@ -41,6 +41,7 @@ import com.jme3.math.FastMath; import com.jme3.math.Vector2f; import com.jme3.math.Vector3f; import com.jme3.scene.Spatial; +import com.jme3.scene.control.LodControl; import com.jme3.scene.control.UpdateControl; import com.jme3.terrain.Terrain; import com.jme3.terrain.geomipmap.LRUCache; @@ -122,10 +123,11 @@ public class FineTerrainGrid extends TerrainQuad { protected HeightMapGrid heightMapGrid; private TerrainGridTileLoader gridTileLoader; protected Vector3f[] quadIndex; - protected Set listeners = new HashSet(); + protected Set listeners = new HashSet<>(); protected Material material; //cache needs to be 1 row (4 cells) larger than what we care is cached - protected LRUCache cache = new LRUCache(20); + protected LRUCache cache = new LRUCache<>( + getSubdivisionsPerSide() * getSubdivisionsPerSide() + getSubdivisionsPerSide()); protected int cellsLoaded = 0; protected int[] gridOffset; protected boolean runOnce = false; @@ -134,6 +136,11 @@ public class FineTerrainGrid extends TerrainQuad { public int getSize() { return size; } + + public int getSubdivisionsPerSide() + { + return 8; + } protected class UpdateQuadCache implements Runnable { @@ -153,9 +160,9 @@ public class FineTerrainGrid extends TerrainQuad { * neighbours). */ public void run() { - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - int quadIdx = i * 4 + j; + for (int i = 0; i < getSubdivisionsPerSide(); i++) { + for (int j = 0; j < getSubdivisionsPerSide(); j++) { + int quadIdx = i * getSubdivisionsPerSide() + j; final Vector3f quadCell = location.add(quadIndex[quadIdx]); TerrainQuad q = cache.get(quadCell); if (q == null) { @@ -221,20 +228,18 @@ public class FineTerrainGrid extends TerrainQuad { } protected boolean isCenter(int quadIndex) { - return quadIndex == 9 || quadIndex == 5 || quadIndex == 10 || quadIndex == 6; + // The only thing that is not a center for us here are the edges of the grid. + int w = getSubdivisionsPerSide(); + // left / right edge + if (quadIndex % w == 0 || (quadIndex + 1) % w == 0) return false; + // top / down edge + if (quadIndex < w || quadIndex >= (w*w - w)) return false; + // center + return true; } protected int getQuadrant(int quadIndex) { - if (quadIndex == 5) { - return 1; - } else if (quadIndex == 9) { - return 2; - } else if (quadIndex == 6) { - return 3; - } else if (quadIndex == 10) { - return 4; - } - return 0; // error + return quadIndex + 1; // whatever, just not 0 } public FineTerrainGrid(String name, int patchSize, int maxVisibleSize, Vector3f scale, TerrainGridTileLoader terrainQuadGrid, @@ -268,8 +273,8 @@ public class FineTerrainGrid extends TerrainQuad { private void initData() { int maxVisibleSize = size; - this.quarterSize = maxVisibleSize >> 2; - this.quadSize = (maxVisibleSize + 1) >> 1; + this.quarterSize = maxVisibleSize / getSubdivisionsPerSide(); + this.quadSize = (maxVisibleSize / getSubdivisionsPerSide()) + 1; this.totalSize = maxVisibleSize; this.gridOffset = new int[]{0, 0}; @@ -282,11 +287,14 @@ public class FineTerrainGrid extends TerrainQuad { * | * z */ - this.quadIndex = new Vector3f[]{ - new Vector3f(-1, 0, -1), new Vector3f(0, 0, -1), new Vector3f(1, 0, -1), new Vector3f(2, 0, -1), - new Vector3f(-1, 0, 0), new Vector3f(0, 0, 0), new Vector3f(1, 0, 0), new Vector3f(2, 0, 0), - new Vector3f(-1, 0, 1), new Vector3f(0, 0, 1), new Vector3f(1, 0, 1), new Vector3f(2, 0, 1), - new Vector3f(-1, 0, 2), new Vector3f(0, 0, 2), new Vector3f(1, 0, 2), new Vector3f(2, 0, 2)}; + // generate a grid of quad positions + this.quadIndex = new Vector3f[getSubdivisionsPerSide() * getSubdivisionsPerSide()]; + int i = 0; + for (int z = -getSubdivisionsPerSide() / 2 + 1; z <= getSubdivisionsPerSide() / 2; z++) { + for (int x = -getSubdivisionsPerSide() / 2 + 1; x <= getSubdivisionsPerSide() / 2; x++) { + quadIndex[i++] = new Vector3f(x, 0, z); + } + } } @@ -357,7 +365,7 @@ public class FineTerrainGrid extends TerrainQuad { } protected void removeQuad(TerrainQuad q) { - if (q != null && ( (q.getQuadrant() > 0 && q.getQuadrant()<5) || q.getParent() != null) ) { + if (q != null && ( q.getParent() != null) ) { for (TerrainGridListener l : listeners) { l.tileDetached(getTileCell(q.getWorldTranslation()), q); } @@ -372,7 +380,6 @@ public class FineTerrainGrid extends TerrainQuad { * @param shifted quads are still attached to the parent and don't need to re-load */ protected void attachQuadAt(TerrainQuad q, int quadrant, Vector3f quadCell, boolean shifted) { - q.setQuadrant((short) quadrant); if (!shifted) this.attachChild(q); @@ -386,7 +393,6 @@ public class FineTerrainGrid extends TerrainQuad { } } updateModelBound(); - } @@ -412,17 +418,17 @@ public class FineTerrainGrid extends TerrainQuad { } int xMin = 0; - int xMax = 4; + int xMax = getSubdivisionsPerSide(); int yMin = 0; - int yMax = 4; + int yMax = getSubdivisionsPerSide(); if (dx == -1) { // camera moved to -X direction - xMax = 3; + xMax = getSubdivisionsPerSide() - 1; } else if (dx == 1) { // camera moved to +X direction xMin = 1; } if (dy == -1) { // camera moved to -Y direction - yMax = 3; + yMax = getSubdivisionsPerSide() - 1; } else if (dy == 1) { // camera moved to +Y direction yMin = 1; } @@ -432,7 +438,7 @@ public class FineTerrainGrid extends TerrainQuad { // either way in one of the axes (say X or Y axis) then they are all touched. for (int i = yMin; i < yMax; i++) { for (int j = xMin; j < xMax; j++) { - cache.get(camCell.add(quadIndex[i * 4 + j])); + cache.get(camCell.add(quadIndex[i * getSubdivisionsPerSide() + j])); } } diff --git a/src/roadtrip/view/GameWorldView.java b/src/roadtrip/view/GameWorldView.java index a95ef60..49f9161 100644 --- a/src/roadtrip/view/GameWorldView.java +++ b/src/roadtrip/view/GameWorldView.java @@ -16,6 +16,7 @@ import com.jme3.scene.Spatial; import com.jme3.terrain.geomipmap.*; import com.jme3.terrain.geomipmap.grid.FractalTileLoader; import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator; +import com.jme3.terrain.geomipmap.lodcalc.LodCalculator; import com.jme3.terrain.noise.ShaderUtils; import com.jme3.terrain.noise.basis.FilteredBasis; import com.jme3.terrain.noise.filter.IterativeFilter; @@ -35,7 +36,7 @@ import roadtrip.view.model.GameWorldState; */ public class GameWorldView { - public static boolean DEBUG = false;//true; + public static boolean DEBUG = true; private final GameWorldState state; @@ -157,10 +158,12 @@ public class GameWorldView { //terrain.terrainGrid.setLocalScale(2f, 1f, 2f); this.rootNode.attachChild(terrain.terrainGrid); - TerrainLodControl control = new FineTerrainGridLodControl(terrain.terrainGrid, camera); - control.setLodCalculator(new DistanceLodCalculator(patchSize + 1, 3.7f)); // patch size, and a multiplier - terrain.terrainGrid.addControl(control); - + final TerrainLodControl lodControl = new FineTerrainGridLodControl(terrain.terrainGrid, camera); + lodControl.setLodCalculator(new DistanceLodCalculator(patchSize + 1, 3.7f)); // patch size, and a multiplier + terrain.terrainGrid.addControl(lodControl); + + final Spatial treeModel = assetManager.loadModel("Models/tree.j3o"); + final FineTerrainGrid terrainGrid = terrain.terrainGrid; terrainGrid.addListener(new TerrainGridListener() { @@ -170,6 +173,7 @@ public class GameWorldView { @Override public void tileAttached(Vector3f cell, TerrainQuad quad) { + lodControl.forceUpdate(); while(quad.getControl(RigidBodyControl.class)!=null){ quad.removeControl(RigidBodyControl.class); } @@ -180,7 +184,8 @@ public class GameWorldView { String quadObjectsNodeKey = getQuadObjectsNodeKey(quad); Node objects = new Node(quadObjectsNodeKey); - populateQuadObjectsNode(quad, objects); + // TODO: fix + //populateQuadObjectsNode(quad, objects); rootNode.attachChild(objects); } @@ -189,7 +194,6 @@ public class GameWorldView { ProceduralMapQuadBlock mapQuadBlock = state.proceduralMap.getMapQuadBlock(quad); // Add map objects (for now - trees) - Spatial treeModel = assetManager.loadModel("Models/tree.j3o"); //System.out.println("Grid @ " + terrainGrid.getLocalTranslation() + " s " + terrainGrid.getLocalScale()); //System.out.println("Quad " + quad.getName() + " @ " + quad.getLocalTranslation()); for (MapObjectInstance mapObject : mapQuadBlock.getMapObjects()) { @@ -202,7 +206,7 @@ public class GameWorldView { if (control != null) { modelInstance.addControl(control); control.setPhysicsLocation(pos); - physicsSpace.add(control); + //physicsSpace.add(control); } objects.attachChild(modelInstance); }