TerrainGrid added to terrain package, test included

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7483 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
ant..om 14 years ago
parent 9489d43098
commit 34a47debb9
  1. 216
      engine/src/terrain/com/jme3/terrain/geomipmap/TerrainGrid.java
  2. 17
      engine/src/terrain/com/jme3/terrain/geomipmap/TerrainGridListener.java
  3. 14
      engine/src/terrain/com/jme3/terrain/geomipmap/UpdatedTerrainPatch.java
  4. 68
      engine/src/terrain/com/jme3/terrain/heightmap/Grayscale16BitHeightMap.java
  5. 19
      engine/src/terrain/com/jme3/terrain/heightmap/HeightMapGrid.java
  6. 61
      engine/src/terrain/com/jme3/terrain/heightmap/ImageBasedHeightMapGrid.java
  7. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_0_-512.png
  8. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_0_0.png
  9. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_0_1024.png
  10. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_0_1536.png
  11. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_0_2048.png
  12. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_0_2560.png
  13. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_0_3072.png
  14. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_0_512.png
  15. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_1024_-512.png
  16. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_1024_0.png
  17. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_1024_1024.png
  18. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_1024_1536.png
  19. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_1024_2048.png
  20. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_1024_2560.png
  21. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_1024_3072.png
  22. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_1024_512.png
  23. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_1536_-512.png
  24. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_1536_0.png
  25. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_1536_1024.png
  26. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_1536_1536.png
  27. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_1536_2048.png
  28. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_1536_2560.png
  29. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_1536_3072.png
  30. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_1536_512.png
  31. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_2048_-512.png
  32. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_2048_0.png
  33. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_2048_1024.png
  34. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_2048_1536.png
  35. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_2048_2048.png
  36. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_2048_2560.png
  37. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_2048_3072.png
  38. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_2048_512.png
  39. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_512_-512.png
  40. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_512_0.png
  41. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_512_1024.png
  42. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_512_1536.png
  43. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_512_2048.png
  44. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_512_2560.png
  45. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_512_3072.png
  46. BIN
      engine/src/test-data/Textures/Terrain/grid/mountains_512_512.png
  47. 184
      engine/src/test/jme3test/terrain/TerrainGridTest.java

@ -0,0 +1,216 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.jme3.terrain.geomipmap;
import com.jme3.bullet.PhysicsSpace;
import com.jme3.bullet.collision.shapes.HeightfieldCollisionShape;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.terrain.heightmap.HeightMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import com.jme3.material.Material;
import com.jme3.math.FastMath;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.terrain.geomipmap.lodcalc.LodCalculatorFactory;
import com.jme3.terrain.geomipmap.lodcalc.LodDistanceCalculatorFactory;
import com.jme3.terrain.heightmap.HeightMapGrid;
/**
* @author Anthyon
*/
public class TerrainGrid extends TerrainQuad {
private static Logger log = Logger.getLogger(TerrainGrid.class.getCanonicalName());
private Vector3f currentCell;
private int quarterSize;
private int quadSize;
private HeightMapGrid heightMapGrid;
private Vector3f[] quadOrigins;
private Vector3f[] quadIndex;
private Map<String, TerrainGridListener> listeners = new HashMap<String, TerrainGridListener>();
private Material material;
public TerrainGrid(String name, int patchSize, int size, Vector3f stepScale, HeightMapGrid heightMapGrid, int totalSize,
Vector2f offset, float offsetAmount, LodCalculatorFactory lodCalculatorFactory) {
this.name = name;
this.patchSize = patchSize;
this.size = size;
this.quarterSize = size >> 2;
this.quadSize = (size + 1) >> 1;
this.stepScale = stepScale;
this.heightMapGrid = heightMapGrid;
heightMapGrid.setSize(this.quadSize);
this.totalSize = totalSize;
this.offset = offset;
this.offsetAmount = offsetAmount;
this.lodCalculatorFactory = lodCalculatorFactory;
if (lodCalculatorFactory == null) {
lodCalculatorFactory = new LodDistanceCalculatorFactory();
}
this.quadOrigins = new Vector3f[]{new Vector3f(-this.quarterSize, 0, -this.quarterSize).mult(this.stepScale),
new Vector3f(-this.quarterSize, 0, this.quarterSize).mult(this.stepScale),
new Vector3f(this.quarterSize, 0, -this.quarterSize).mult(this.stepScale),
new Vector3f(this.quarterSize, 0, this.quarterSize).mult(this.stepScale)};
this.quadIndex = new Vector3f[]{new Vector3f(0, 0, 0), new Vector3f(0, 0, 1), new Vector3f(1, 0, 0), new Vector3f(1, 0, 1)};
updateChildrens(Vector3f.ZERO);
}
public TerrainGrid(String name, int patchSize, int size, Vector3f scale, HeightMapGrid heightMapGrid,
LodCalculatorFactory lodCalculatorFactory) {
this(name, patchSize, size, scale, heightMapGrid, size, new Vector2f(), 0, lodCalculatorFactory);
}
public TerrainGrid(String name, int patchSize, int totalSize, HeightMapGrid heightMapGrid, LodCalculatorFactory lodCalculatorFactory) {
this(name, patchSize, totalSize, Vector3f.UNIT_XYZ, heightMapGrid, lodCalculatorFactory);
}
public TerrainGrid(String name, int patchSize, int totalSize, HeightMapGrid heightMapGrid) {
this(name, patchSize, totalSize, heightMapGrid, null);
}
public TerrainGrid() {
}
@Override
public void update(List<Vector3f> locations) {
// for now, only the first camera is handled.
// to accept more, there are two ways:
// 1: every camera has an associated grid, then the location is not enough to identify which camera location has changed
// 2: grids are associated with locations, and no incremental update is done, we load new grids for new locations, and unload those that are not needed anymore
Vector3f cam = locations.get(0);
Vector3f camCell = this.getCell(cam);
if (!camCell.equals(this.currentCell)) {
this.updateChildrens(camCell);
for (TerrainGridListener l : this.listeners.values()) {
l.gridMoved(camCell);
}
}
super.update(locations);
}
public Vector3f getCell(Vector3f location) {
final Vector3f v = location.clone().divideLocal(this.getLocalScale().mult(this.quadSize)).add(0.5f, 0, 0.5f);
return new Vector3f(FastMath.floor(v.x), FastMath.floor(v.y), FastMath.floor(v.z));
}
protected void removeQuad(int idx) {
this.detachChild(this.getQuad(idx));
}
protected void moveQuad(int from, int to) {
this.removeQuad(to);
TerrainQuad fq = this.getQuad(from);
fq.setQuadrant((short) to);
fq.setLocalTranslation(this.quadOrigins[to - 1]);
}
protected TerrainQuad createQuadAt(Vector3f location, int quadrant) {
final HeightMap heightMapAt = this.heightMapGrid.getHeightMapAt(location);
TerrainQuad q = new TerrainQuad(this.getName() + "Quad" + location, this.patchSize, this.quadSize, heightMapAt == null ? null : heightMapAt.getHeightMap(), this.lodCalculatorFactory);
q.setLocalTranslation(this.quadOrigins[quadrant - 1]);
q.setMaterial(this.material);
q.setQuadrant((short) quadrant);
return q;
}
private void updateChildrens(Vector3f cam) {
RigidBodyControl control = getControl(RigidBodyControl.class);
PhysicsSpace space = null;
if (control != null) {
space = control.getPhysicsSpace();
space.remove(this);
this.removeControl(control);
}
int dx = (int) cam.x;
int dz = (int) cam.z;
if (this.currentCell != null) {
dx -= (int) (this.currentCell.x);
dz -= (int) (this.currentCell.z);
}
if (this.currentCell == null || FastMath.abs(dx) > 1 || FastMath.abs(dz) > 1 || (dx != 0 && dz != 0)) {
if (this.currentCell != null) {
// in case of teleport, otherwise the FastMath.abs(delta) should
// never be greater than 1
this.removeQuad(1);
this.removeQuad(2);
this.removeQuad(3);
this.removeQuad(4);
}
this.attachChild(this.createQuadAt(cam.add(this.quadIndex[0]).mult(this.quadSize - 1), 1));
this.attachChild(this.createQuadAt(cam.add(this.quadIndex[1]).mult(this.quadSize - 1), 2));
this.attachChild(this.createQuadAt(cam.add(this.quadIndex[2]).mult(this.quadSize - 1), 3));
this.attachChild(this.createQuadAt(cam.add(this.quadIndex[3]).mult(this.quadSize - 1), 4));
} else if (dx == 0) {
if (dz < 0) {
// move north
this.moveQuad(1, 2);
this.moveQuad(3, 4);
this.attachChild(this.createQuadAt(cam.add(this.quadIndex[0]).mult(this.quadSize - 1), 1));
this.attachChild(this.createQuadAt(cam.add(this.quadIndex[2]).mult(this.quadSize - 1), 3));
} else {
// move south
this.moveQuad(2, 1);
this.moveQuad(4, 3);
this.attachChild(this.createQuadAt(cam.add(this.quadIndex[1]).mult(this.quadSize - 1), 2));
this.attachChild(this.createQuadAt(cam.add(this.quadIndex[3]).mult(this.quadSize - 1), 4));
}
} else if (dz == 0) {
if (dx < 0) {
// move west
this.moveQuad(1, 3);
this.moveQuad(2, 4);
this.attachChild(this.createQuadAt(cam.add(this.quadIndex[0]).mult(this.quadSize - 1), 1));
this.attachChild(this.createQuadAt(cam.add(this.quadIndex[1]).mult(this.quadSize - 1), 2));
} else {
// move east
this.moveQuad(3, 1);
this.moveQuad(4, 2);
this.attachChild(this.createQuadAt(cam.add(this.quadIndex[2]).mult(this.quadSize - 1), 3));
this.attachChild(this.createQuadAt(cam.add(this.quadIndex[3]).mult(this.quadSize - 1), 4));
}
} else {
// rare situation to enter into a diagonally placed cell
// could not get into this part while testing, as it is handled by moving first
// in either horizontally or vertically than the other way
// I handle it in the first IF
}
this.currentCell = cam;
this.setLocalTranslation(cam.mult(2 * this.quadSize));
if (control != null) {
control = new RigidBodyControl(new HeightfieldCollisionShape(getHeightMap(), getLocalScale()), 0);
this.addControl(control);
space.add(this);
}
}
public void addListener(String id, TerrainGridListener listener) {
this.listeners.put(id, listener);
}
public Vector3f getCurrentCell() {
return this.currentCell;
}
public void removeListener(String id) {
this.listeners.remove(id);
}
@Override
public void setMaterial(Material mat) {
this.material = mat;
super.setMaterial(mat);
}
public void setQuadSize(int quadSize) {
this.quadSize = quadSize;
}
}

@ -0,0 +1,17 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.jme3.terrain.geomipmap;
import com.jme3.math.Vector3f;
/**
*
* @author Anthyon
*/
public interface TerrainGridListener {
public void gridMoved(Vector3f newCenter);
}

@ -39,12 +39,12 @@ import com.jme3.scene.VertexBuffer.Type;
/** /**
* Stores a terrain patch's details so the LOD background thread can update * Stores a terrain patch's details so the LOD background thread can update
* the actual terrain patch back on the ogl thread. * the actual terrain patch back on the ogl thread.
* *
* @author Brent Owens * @author Brent Owens
* *
*/ */
public class UpdatedTerrainPatch { public class UpdatedTerrainPatch {
private TerrainPatch updatedPatch; private TerrainPatch updatedPatch;
private int newLod; private int newLod;
private int previousLod; private int previousLod;
@ -52,12 +52,12 @@ public class UpdatedTerrainPatch {
private IntBuffer newIndexBuffer; private IntBuffer newIndexBuffer;
private boolean reIndexNeeded = false; private boolean reIndexNeeded = false;
private boolean fixEdges = false; private boolean fixEdges = false;
public UpdatedTerrainPatch(TerrainPatch updatedPatch, int newLod) { public UpdatedTerrainPatch(TerrainPatch updatedPatch, int newLod) {
this.updatedPatch = updatedPatch; this.updatedPatch = updatedPatch;
this.newLod = newLod; this.newLod = newLod;
} }
public UpdatedTerrainPatch(TerrainPatch updatedPatch, int newLod, int prevLOD, boolean reIndexNeeded) { public UpdatedTerrainPatch(TerrainPatch updatedPatch, int newLod, int prevLOD, boolean reIndexNeeded) {
this.updatedPatch = updatedPatch; this.updatedPatch = updatedPatch;
this.newLod = newLod; this.newLod = newLod;
@ -70,14 +70,14 @@ public class UpdatedTerrainPatch {
public String getName() { public String getName() {
return updatedPatch.getName(); return updatedPatch.getName();
} }
protected boolean lodChanged() { protected boolean lodChanged() {
if (reIndexNeeded && previousLod != newLod) if (reIndexNeeded && previousLod != newLod)
return true; return true;
else else
return false; return false;
} }
protected TerrainPatch getUpdatedPatch() { protected TerrainPatch getUpdatedPatch() {
return updatedPatch; return updatedPatch;
} }
@ -174,7 +174,7 @@ public class UpdatedTerrainPatch {
updatedPatch.setLodTop(topLod); updatedPatch.setLodTop(topLod);
updatedPatch.setLodLeft(leftLod); updatedPatch.setLodLeft(leftLod);
updatedPatch.setLodBottom(bottomLod); updatedPatch.setLodBottom(bottomLod);
if (reIndexNeeded || fixEdges) { if (newIndexBuffer != null && (reIndexNeeded || fixEdges)) {
updatedPatch.setPreviousLod(previousLod); updatedPatch.setPreviousLod(previousLod);
updatedPatch.getMesh().clearBuffer(Type.Index); updatedPatch.getMesh().clearBuffer(Type.Index);
updatedPatch.getMesh().setBuffer(Type.Index, 3, newIndexBuffer); updatedPatch.getMesh().setBuffer(Type.Index, 3, newIndexBuffer);

@ -0,0 +1,68 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.jme3.terrain.heightmap;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
/**
*
* @author Anthyon
*/
public class Grayscale16BitHeightMap extends AbstractHeightMap {
private BufferedImage image;
public Grayscale16BitHeightMap() {
}
public Grayscale16BitHeightMap(BufferedImage image) {
this.image = image;
}
public Grayscale16BitHeightMap(String filename) {
this(new File(filename));
}
public Grayscale16BitHeightMap(File file) {
try {
this.image = ImageIO.read(file);
} catch (IOException ex) {
Logger.getLogger(Grayscale16BitHeightMap.class.getName()).log(Level.SEVERE, null, ex);
}
}
@Override
public boolean load() {
return load(false, false);
}
public boolean load(boolean flipX, boolean flipY) {
int imageWidth = image.getWidth();
int imageHeight = image.getHeight();
if (imageWidth != imageHeight) {
throw new RuntimeException("imageWidth: " + imageWidth
+ " != imageHeight: " + imageHeight);
}
Object out = new short[imageWidth * imageHeight];
out = image.getData().getDataElements(0, 0, imageWidth, imageHeight, out);
short[] values = (short[]) out;
heightData = new float[imageWidth * imageHeight];
int i = 0;
for (int y = 0; y < imageHeight; y++) {
for (int x = 0; x < imageWidth; x++, i++) {
heightData[i] = heightScale * (values[i] & 0x0000FFFF) / 65536f;
}
}
return true;
}
}

@ -0,0 +1,19 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.jme3.terrain.heightmap;
import com.jme3.math.Vector3f;
/**
*
* @author Anthyon
*/
public interface HeightMapGrid {
public HeightMap getHeightMapAt(Vector3f location);
public void setSize(int size);
}

@ -0,0 +1,61 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.jme3.terrain.heightmap;
import com.jme3.asset.AssetManager;
import com.jme3.asset.AssetNotFoundException;
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import com.jme3.texture.Texture;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import javax.imageio.ImageIO;
import jme3tools.converters.ImageToAwt;
/**
*
* @author Anthyon
*/
public class ImageBasedHeightMapGrid implements HeightMapGrid {
private final String textureBase;
private final String textureExt;
private final AssetManager assetManager;
private int size;
public ImageBasedHeightMapGrid(String textureBase, String textureExt, AssetManager assetManager) {
this.textureBase = textureBase;
this.textureExt = textureExt;
this.assetManager = assetManager;
}
public HeightMap getHeightMapAt(Vector3f location) {
// HEIGHTMAP image (for the terrain heightmap)
int x = (int) (FastMath.floor(location.x / this.size) * this.size);
int z = (int) (FastMath.floor(location.z / this.size) * this.size);
AbstractHeightMap heightmap = null;
try {
final InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream(textureBase + "_" + x + "_" + z + "." + textureExt);
BufferedImage im = null;
if (stream != null) {
im = ImageIO.read(stream);
} else {
im = new BufferedImage(size, size, BufferedImage.TYPE_USHORT_GRAY);
}
// CREATE HEIGHTMAP
heightmap = new Grayscale16BitHeightMap(im);
heightmap.setHeightScale(256);
heightmap.load();
} catch (IOException e) {
} catch (AssetNotFoundException e) {
}
return heightmap;
}
public void setSize(int size) {
this.size = size - 1;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 437 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 424 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 358 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 415 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 438 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 430 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 420 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 445 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 395 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 420 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 336 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 428 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 428 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 420 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 436 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 446 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 436 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 429 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 416 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 430 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 432 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 424 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 439 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 426 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 432 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 425 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 424 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 381 KiB

@ -0,0 +1,184 @@
package jme3test.terrain;
import java.util.ArrayList;
import java.util.List;
import com.jme3.app.SimpleApplication;
import com.jme3.app.state.ScreenshotAppState;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.collision.shapes.HeightfieldCollisionShape;
import com.jme3.bullet.control.CharacterControl;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.terrain.geomipmap.TerrainGrid;
import com.jme3.terrain.geomipmap.TerrainLodControl;
import com.jme3.terrain.geomipmap.TerrainQuad;
import com.jme3.terrain.heightmap.ImageBasedHeightMapGrid;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture.WrapMode;
public class TerrainGridTest extends SimpleApplication {
private Material mat_terrain;
private TerrainQuad terrain;
private float grassScale = 64;
private float dirtScale = 16;
private float rockScale = 128;
public static void main(final String[] args) {
TerrainGridTest app = new TerrainGridTest();
app.start();
}
private CharacterControl player3;
@Override
public void simpleInitApp() {
this.flyCam.setMoveSpeed(100f);
ScreenshotAppState state = new ScreenshotAppState();
this.stateManager.attach(state);
// TERRAIN TEXTURE material
mat_terrain = new Material(assetManager, "Common/MatDefs/Terrain/Terrain.j3md");
mat_terrain.setBoolean("useTriPlanarMapping", false);
// ALPHA map (for splat textures)
mat_terrain.setTexture("Alpha", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png"));
// GRASS texture
Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg");
grass.setWrap(WrapMode.Repeat);
mat_terrain.setTexture("Tex1", grass);
mat_terrain.setFloat("Tex1Scale", grassScale);
// DIRT texture
Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg");
dirt.setWrap(WrapMode.Repeat);
mat_terrain.setTexture("Tex2", dirt);
mat_terrain.setFloat("Tex2Scale", dirtScale);
// ROCK texture
Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg");
rock.setWrap(WrapMode.Repeat);
mat_terrain.setTexture("Tex3", rock);
mat_terrain.setFloat("Tex3Scale", rockScale);
this.terrain = new TerrainGrid("terrain", 65, 1025, new ImageBasedHeightMapGrid("Textures/Terrain/grid/mountains", "png",
this.assetManager));
this.terrain.setMaterial(this.mat_terrain);
this.terrain.setLocalTranslation(0, 0, 0);
this.terrain.setLocalScale(2f, 1f, 2f);
this.rootNode.attachChild(this.terrain);
List<Camera> cameras = new ArrayList<Camera>();
cameras.add(this.getCamera());
TerrainLodControl control = new TerrainLodControl(this.terrain, cameras);
this.terrain.addControl(control);
BulletAppState bulletAppState = new BulletAppState();
stateManager.attach(bulletAppState);
RigidBodyControl body = new RigidBodyControl(new HeightfieldCollisionShape(terrain.getHeightMap(), terrain.getLocalScale()), 0);
terrain.addControl(body);
bulletAppState.getPhysicsSpace().add(terrain);
this.getCamera().setLocation(new Vector3f(0, 256, 0));
this.viewPort.setBackgroundColor(new ColorRGBA(0.7f, 0.8f, 1f, 1f));
CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(0.5f, 1.8f, 1);
this.player3 = new CharacterControl(capsuleShape, 0.5f);
this.player3.setJumpSpeed(20);
this.player3.setFallSpeed(30);
this.player3.setGravity(30);
this.player3.setPhysicsLocation(new Vector3f(0, 256, 0));
bulletAppState.getPhysicsSpace().add(this.player3);
this.initKeys();
}
private void initKeys() {
// You can map one or several inputs to one named action
this.inputManager.addMapping("Lefts", new KeyTrigger(KeyInput.KEY_A));
this.inputManager.addMapping("Rights", new KeyTrigger(KeyInput.KEY_D));
this.inputManager.addMapping("Ups", new KeyTrigger(KeyInput.KEY_W));
this.inputManager.addMapping("Downs", new KeyTrigger(KeyInput.KEY_S));
this.inputManager.addMapping("Jumps", new KeyTrigger(KeyInput.KEY_SPACE));
this.inputManager.addMapping("Gravity", new KeyTrigger(KeyInput.KEY_G));
this.inputManager.addListener(this.actionListener, "Lefts");
this.inputManager.addListener(this.actionListener, "Rights");
this.inputManager.addListener(this.actionListener, "Ups");
this.inputManager.addListener(this.actionListener, "Downs");
this.inputManager.addListener(this.actionListener, "Jumps");
this.inputManager.addListener(this.actionListener, "Gravity");
}
private boolean left;
private boolean right;
private boolean up;
private boolean down;
private final ActionListener actionListener = new ActionListener() {
@Override
public void onAction(final String name, final boolean keyPressed, final float tpf) {
if (name.equals("Lefts")) {
if (keyPressed) {
TerrainGridTest.this.left = true;
} else {
TerrainGridTest.this.left = false;
}
} else if (name.equals("Rights")) {
if (keyPressed) {
TerrainGridTest.this.right = true;
} else {
TerrainGridTest.this.right = false;
}
} else if (name.equals("Ups")) {
if (keyPressed) {
TerrainGridTest.this.up = true;
} else {
TerrainGridTest.this.up = false;
}
} else if (name.equals("Downs")) {
if (keyPressed) {
TerrainGridTest.this.down = true;
} else {
TerrainGridTest.this.down = false;
}
} else if (name.equals("Jumps")) {
TerrainGridTest.this.player3.jump();
}
}
};
private final Vector3f walkDirection = new Vector3f();
@Override
public void simpleUpdate(final float tpf) {
Vector3f camDir = this.cam.getDirection().clone().multLocal(0.6f);
Vector3f camLeft = this.cam.getLeft().clone().multLocal(0.4f);
this.walkDirection.set(0, 0, 0);
if (this.left) {
this.walkDirection.addLocal(camLeft);
}
if (this.right) {
this.walkDirection.addLocal(camLeft.negate());
}
if (this.up) {
this.walkDirection.addLocal(camDir);
}
if (this.down) {
this.walkDirection.addLocal(camDir.negate());
}
this.player3.setWalkDirection(this.walkDirection);
this.cam.setLocation(this.player3.getPhysicsLocation());
}
}
Loading…
Cancel
Save