mirror of
https://github.com/Dejvino/roadtrip
synced 2024-11-21 23:42:35 +00:00
Map: Fine-grained terrain grid implemented. Now there is smoother loading and unloading of terrain tiles.
This commit is contained in:
parent
c9a5429193
commit
bdadc3c739
@ -41,6 +41,7 @@ import com.jme3.math.FastMath;
|
|||||||
import com.jme3.math.Vector2f;
|
import com.jme3.math.Vector2f;
|
||||||
import com.jme3.math.Vector3f;
|
import com.jme3.math.Vector3f;
|
||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
|
import com.jme3.scene.control.LodControl;
|
||||||
import com.jme3.scene.control.UpdateControl;
|
import com.jme3.scene.control.UpdateControl;
|
||||||
import com.jme3.terrain.Terrain;
|
import com.jme3.terrain.Terrain;
|
||||||
import com.jme3.terrain.geomipmap.LRUCache;
|
import com.jme3.terrain.geomipmap.LRUCache;
|
||||||
@ -122,10 +123,11 @@ public class FineTerrainGrid extends TerrainQuad {
|
|||||||
protected HeightMapGrid heightMapGrid;
|
protected HeightMapGrid heightMapGrid;
|
||||||
private TerrainGridTileLoader gridTileLoader;
|
private TerrainGridTileLoader gridTileLoader;
|
||||||
protected Vector3f[] quadIndex;
|
protected Vector3f[] quadIndex;
|
||||||
protected Set<TerrainGridListener> listeners = new HashSet<TerrainGridListener>();
|
protected Set<TerrainGridListener> listeners = new HashSet<>();
|
||||||
protected Material material;
|
protected Material material;
|
||||||
//cache needs to be 1 row (4 cells) larger than what we care is cached
|
//cache needs to be 1 row (4 cells) larger than what we care is cached
|
||||||
protected LRUCache<Vector3f, TerrainQuad> cache = new LRUCache<Vector3f, TerrainQuad>(20);
|
protected LRUCache<Vector3f, TerrainQuad> cache = new LRUCache<>(
|
||||||
|
getSubdivisionsPerSide() * getSubdivisionsPerSide() + getSubdivisionsPerSide());
|
||||||
protected int cellsLoaded = 0;
|
protected int cellsLoaded = 0;
|
||||||
protected int[] gridOffset;
|
protected int[] gridOffset;
|
||||||
protected boolean runOnce = false;
|
protected boolean runOnce = false;
|
||||||
@ -134,6 +136,11 @@ public class FineTerrainGrid extends TerrainQuad {
|
|||||||
public int getSize() {
|
public int getSize() {
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getSubdivisionsPerSide()
|
||||||
|
{
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
|
||||||
protected class UpdateQuadCache implements Runnable {
|
protected class UpdateQuadCache implements Runnable {
|
||||||
|
|
||||||
@ -153,9 +160,9 @@ public class FineTerrainGrid extends TerrainQuad {
|
|||||||
* neighbours).
|
* neighbours).
|
||||||
*/
|
*/
|
||||||
public void run() {
|
public void run() {
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < getSubdivisionsPerSide(); i++) {
|
||||||
for (int j = 0; j < 4; j++) {
|
for (int j = 0; j < getSubdivisionsPerSide(); j++) {
|
||||||
int quadIdx = i * 4 + j;
|
int quadIdx = i * getSubdivisionsPerSide() + j;
|
||||||
final Vector3f quadCell = location.add(quadIndex[quadIdx]);
|
final Vector3f quadCell = location.add(quadIndex[quadIdx]);
|
||||||
TerrainQuad q = cache.get(quadCell);
|
TerrainQuad q = cache.get(quadCell);
|
||||||
if (q == null) {
|
if (q == null) {
|
||||||
@ -221,20 +228,18 @@ public class FineTerrainGrid extends TerrainQuad {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isCenter(int quadIndex) {
|
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) {
|
protected int getQuadrant(int quadIndex) {
|
||||||
if (quadIndex == 5) {
|
return quadIndex + 1; // whatever, just not 0
|
||||||
return 1;
|
|
||||||
} else if (quadIndex == 9) {
|
|
||||||
return 2;
|
|
||||||
} else if (quadIndex == 6) {
|
|
||||||
return 3;
|
|
||||||
} else if (quadIndex == 10) {
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
return 0; // error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public FineTerrainGrid(String name, int patchSize, int maxVisibleSize, Vector3f scale, TerrainGridTileLoader terrainQuadGrid,
|
public FineTerrainGrid(String name, int patchSize, int maxVisibleSize, Vector3f scale, TerrainGridTileLoader terrainQuadGrid,
|
||||||
@ -268,8 +273,8 @@ public class FineTerrainGrid extends TerrainQuad {
|
|||||||
|
|
||||||
private void initData() {
|
private void initData() {
|
||||||
int maxVisibleSize = size;
|
int maxVisibleSize = size;
|
||||||
this.quarterSize = maxVisibleSize >> 2;
|
this.quarterSize = maxVisibleSize / getSubdivisionsPerSide();
|
||||||
this.quadSize = (maxVisibleSize + 1) >> 1;
|
this.quadSize = (maxVisibleSize / getSubdivisionsPerSide()) + 1;
|
||||||
this.totalSize = maxVisibleSize;
|
this.totalSize = maxVisibleSize;
|
||||||
this.gridOffset = new int[]{0, 0};
|
this.gridOffset = new int[]{0, 0};
|
||||||
|
|
||||||
@ -282,11 +287,14 @@ public class FineTerrainGrid extends TerrainQuad {
|
|||||||
* |
|
* |
|
||||||
* z
|
* z
|
||||||
*/
|
*/
|
||||||
this.quadIndex = new Vector3f[]{
|
// generate a grid of quad positions
|
||||||
new Vector3f(-1, 0, -1), new Vector3f(0, 0, -1), new Vector3f(1, 0, -1), new Vector3f(2, 0, -1),
|
this.quadIndex = new Vector3f[getSubdivisionsPerSide() * getSubdivisionsPerSide()];
|
||||||
new Vector3f(-1, 0, 0), new Vector3f(0, 0, 0), new Vector3f(1, 0, 0), new Vector3f(2, 0, 0),
|
int i = 0;
|
||||||
new Vector3f(-1, 0, 1), new Vector3f(0, 0, 1), new Vector3f(1, 0, 1), new Vector3f(2, 0, 1),
|
for (int z = -getSubdivisionsPerSide() / 2 + 1; z <= getSubdivisionsPerSide() / 2; z++) {
|
||||||
new Vector3f(-1, 0, 2), new Vector3f(0, 0, 2), new Vector3f(1, 0, 2), new Vector3f(2, 0, 2)};
|
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) {
|
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) {
|
for (TerrainGridListener l : listeners) {
|
||||||
l.tileDetached(getTileCell(q.getWorldTranslation()), q);
|
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
|
* @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) {
|
protected void attachQuadAt(TerrainQuad q, int quadrant, Vector3f quadCell, boolean shifted) {
|
||||||
|
|
||||||
q.setQuadrant((short) quadrant);
|
q.setQuadrant((short) quadrant);
|
||||||
if (!shifted)
|
if (!shifted)
|
||||||
this.attachChild(q);
|
this.attachChild(q);
|
||||||
@ -386,7 +393,6 @@ public class FineTerrainGrid extends TerrainQuad {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateModelBound();
|
updateModelBound();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -412,17 +418,17 @@ public class FineTerrainGrid extends TerrainQuad {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int xMin = 0;
|
int xMin = 0;
|
||||||
int xMax = 4;
|
int xMax = getSubdivisionsPerSide();
|
||||||
int yMin = 0;
|
int yMin = 0;
|
||||||
int yMax = 4;
|
int yMax = getSubdivisionsPerSide();
|
||||||
if (dx == -1) { // camera moved to -X direction
|
if (dx == -1) { // camera moved to -X direction
|
||||||
xMax = 3;
|
xMax = getSubdivisionsPerSide() - 1;
|
||||||
} else if (dx == 1) { // camera moved to +X direction
|
} else if (dx == 1) { // camera moved to +X direction
|
||||||
xMin = 1;
|
xMin = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dy == -1) { // camera moved to -Y direction
|
if (dy == -1) { // camera moved to -Y direction
|
||||||
yMax = 3;
|
yMax = getSubdivisionsPerSide() - 1;
|
||||||
} else if (dy == 1) { // camera moved to +Y direction
|
} else if (dy == 1) { // camera moved to +Y direction
|
||||||
yMin = 1;
|
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.
|
// 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 i = yMin; i < yMax; i++) {
|
||||||
for (int j = xMin; j < xMax; j++) {
|
for (int j = xMin; j < xMax; j++) {
|
||||||
cache.get(camCell.add(quadIndex[i * 4 + j]));
|
cache.get(camCell.add(quadIndex[i * getSubdivisionsPerSide() + j]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ import com.jme3.scene.Spatial;
|
|||||||
import com.jme3.terrain.geomipmap.*;
|
import com.jme3.terrain.geomipmap.*;
|
||||||
import com.jme3.terrain.geomipmap.grid.FractalTileLoader;
|
import com.jme3.terrain.geomipmap.grid.FractalTileLoader;
|
||||||
import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator;
|
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.ShaderUtils;
|
||||||
import com.jme3.terrain.noise.basis.FilteredBasis;
|
import com.jme3.terrain.noise.basis.FilteredBasis;
|
||||||
import com.jme3.terrain.noise.filter.IterativeFilter;
|
import com.jme3.terrain.noise.filter.IterativeFilter;
|
||||||
@ -35,7 +36,7 @@ import roadtrip.view.model.GameWorldState;
|
|||||||
*/
|
*/
|
||||||
public class GameWorldView {
|
public class GameWorldView {
|
||||||
|
|
||||||
public static boolean DEBUG = false;//true;
|
public static boolean DEBUG = true;
|
||||||
|
|
||||||
private final GameWorldState state;
|
private final GameWorldState state;
|
||||||
|
|
||||||
@ -157,10 +158,12 @@ public class GameWorldView {
|
|||||||
//terrain.terrainGrid.setLocalScale(2f, 1f, 2f);
|
//terrain.terrainGrid.setLocalScale(2f, 1f, 2f);
|
||||||
this.rootNode.attachChild(terrain.terrainGrid);
|
this.rootNode.attachChild(terrain.terrainGrid);
|
||||||
|
|
||||||
TerrainLodControl control = new FineTerrainGridLodControl(terrain.terrainGrid, camera);
|
final TerrainLodControl lodControl = new FineTerrainGridLodControl(terrain.terrainGrid, camera);
|
||||||
control.setLodCalculator(new DistanceLodCalculator(patchSize + 1, 3.7f)); // patch size, and a multiplier
|
lodControl.setLodCalculator(new DistanceLodCalculator(patchSize + 1, 3.7f)); // patch size, and a multiplier
|
||||||
terrain.terrainGrid.addControl(control);
|
terrain.terrainGrid.addControl(lodControl);
|
||||||
|
|
||||||
|
final Spatial treeModel = assetManager.loadModel("Models/tree.j3o");
|
||||||
|
|
||||||
final FineTerrainGrid terrainGrid = terrain.terrainGrid;
|
final FineTerrainGrid terrainGrid = terrain.terrainGrid;
|
||||||
terrainGrid.addListener(new TerrainGridListener() {
|
terrainGrid.addListener(new TerrainGridListener() {
|
||||||
|
|
||||||
@ -170,6 +173,7 @@ public class GameWorldView {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tileAttached(Vector3f cell, TerrainQuad quad) {
|
public void tileAttached(Vector3f cell, TerrainQuad quad) {
|
||||||
|
lodControl.forceUpdate();
|
||||||
while(quad.getControl(RigidBodyControl.class)!=null){
|
while(quad.getControl(RigidBodyControl.class)!=null){
|
||||||
quad.removeControl(RigidBodyControl.class);
|
quad.removeControl(RigidBodyControl.class);
|
||||||
}
|
}
|
||||||
@ -180,7 +184,8 @@ public class GameWorldView {
|
|||||||
|
|
||||||
String quadObjectsNodeKey = getQuadObjectsNodeKey(quad);
|
String quadObjectsNodeKey = getQuadObjectsNodeKey(quad);
|
||||||
Node objects = new Node(quadObjectsNodeKey);
|
Node objects = new Node(quadObjectsNodeKey);
|
||||||
populateQuadObjectsNode(quad, objects);
|
// TODO: fix
|
||||||
|
//populateQuadObjectsNode(quad, objects);
|
||||||
rootNode.attachChild(objects);
|
rootNode.attachChild(objects);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,7 +194,6 @@ public class GameWorldView {
|
|||||||
ProceduralMapQuadBlock mapQuadBlock = state.proceduralMap.getMapQuadBlock(quad);
|
ProceduralMapQuadBlock mapQuadBlock = state.proceduralMap.getMapQuadBlock(quad);
|
||||||
|
|
||||||
// Add map objects (for now - trees)
|
// 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("Grid @ " + terrainGrid.getLocalTranslation() + " s " + terrainGrid.getLocalScale());
|
||||||
//System.out.println("Quad " + quad.getName() + " @ " + quad.getLocalTranslation());
|
//System.out.println("Quad " + quad.getName() + " @ " + quad.getLocalTranslation());
|
||||||
for (MapObjectInstance mapObject : mapQuadBlock.getMapObjects()) {
|
for (MapObjectInstance mapObject : mapQuadBlock.getMapObjects()) {
|
||||||
@ -202,7 +206,7 @@ public class GameWorldView {
|
|||||||
if (control != null) {
|
if (control != null) {
|
||||||
modelInstance.addControl(control);
|
modelInstance.addControl(control);
|
||||||
control.setPhysicsLocation(pos);
|
control.setPhysicsLocation(pos);
|
||||||
physicsSpace.add(control);
|
//physicsSpace.add(control);
|
||||||
}
|
}
|
||||||
objects.attachChild(modelInstance);
|
objects.attachChild(modelInstance);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user