So, after a break, I downloaded jMonkeyEngine 3.0, installed the jME3 AI Library from the plugins. Then I tried to make the simplest NavMesh on a terrain that I could, and see what happens.
Its kinda sorta working, but I am not sure its generating the NavMesh properly - the pathfinding is pretty much ignoring hills. I am just plain out of ideas
Here is a screenshot of my simple terrain, the green sphere is the starting vector and the red sphere is the end vector. I draw a blue line between all the waypoints (of which there are always 4 - 2 at the start vector and 2 at the end vector). I snagged the code from the picking tutorial so when I click the waypoints are recalculated and the red sphere placed where I clicked:
Here is the log:
run:
Nov 18, 2015 8:36:43 PM java.util.prefs.WindowsPreferences <init>
WARNING: Could not open/create prefs root node Software\JavaSoft\Prefs at root 0x80000002. Windows RegCreateKeyEx(...) returned error code 5.
Nov 18, 2015 8:36:45 PM com.jme3.system.JmeDesktopSystem initialize
INFO: Running on jMonkeyEngine 3.0.10
Nov 18, 2015 8:36:45 PM com.jme3.system.Natives extractNativeLibs
INFO: Extraction Directory: C:\Users\Jacob\Documents\jMonkeyEngine Projects\navmeshtest3.0
Nov 18, 2015 8:36:46 PM com.jme3.system.lwjgl.LwjglContext printContextInitInfo
INFO: Lwjgl 2.9.0 context running on thread LWJGL Renderer Thread
Nov 18, 2015 8:36:46 PM com.jme3.system.lwjgl.LwjglContext printContextInitInfo
INFO: Adapter: nvd3dumx,nvwgf2umx,nvwgf2umx,nvwgf2umx
Nov 18, 2015 8:36:46 PM com.jme3.system.lwjgl.LwjglContext printContextInitInfo
INFO: Driver Version: 10.18.13.5891
Nov 18, 2015 8:36:46 PM com.jme3.system.lwjgl.LwjglContext printContextInitInfo
INFO: Vendor: NVIDIA Corporation
Nov 18, 2015 8:36:46 PM com.jme3.system.lwjgl.LwjglContext printContextInitInfo
INFO: OpenGL Version: 4.5.0 NVIDIA 358.91
Nov 18, 2015 8:36:46 PM com.jme3.system.lwjgl.LwjglContext printContextInitInfo
INFO: Renderer: GeForce GTX 960/PCIe/SSE2
Nov 18, 2015 8:36:46 PM com.jme3.system.lwjgl.LwjglContext printContextInitInfo
INFO: GLSL Ver: 4.50 NVIDIA
Nov 18, 2015 8:36:46 PM com.jme3.asset.AssetConfig loadText
WARNING: Cannot find loader com.jme3.scene.plugins.blender.BlenderModelLoader
WARNING: Found unknown Windows version: Windows 8
Attempting to use default windows plug-in.
Loading: net.java.games.input.DirectAndRawInputEnvironmentPlugin
Nov 18, 2015 8:36:46 PM com.jme3.audio.lwjgl.LwjglAudioRenderer initInThread
INFO: Audio Device: OpenAL Soft
Nov 18, 2015 8:36:46 PM com.jme3.audio.lwjgl.LwjglAudioRenderer initInThread
INFO: Audio Vendor: OpenAL Community
Nov 18, 2015 8:36:46 PM com.jme3.audio.lwjgl.LwjglAudioRenderer initInThread
INFO: Audio Renderer: OpenAL Soft
Nov 18, 2015 8:36:46 PM com.jme3.audio.lwjgl.LwjglAudioRenderer initInThread
INFO: Audio Version: 1.1 ALSOFT 1.15.1
Nov 18, 2015 8:36:46 PM com.jme3.audio.lwjgl.LwjglAudioRenderer initInThread
INFO: AudioRenderer supports 64 channels
Nov 18, 2015 8:36:46 PM com.jme3.audio.lwjgl.LwjglAudioRenderer initInThread
INFO: Audio effect extension version: 1.0
Nov 18, 2015 8:36:46 PM com.jme3.audio.lwjgl.LwjglAudioRenderer initInThread
INFO: Audio max auxilary sends: 4
Warning, normal of the plane faces downward!!!
Warning, normal of the plane faces downward!!!
-------- 8< MANY ERRORS --------
Warning, normal of the plane faces downward!!!
Warning, normal of the plane faces downward!!!
Navigating to (-33.63971, 0.0, -14.722342)
---------------------- drawing the path to (-33.63971, 0.0, -14.722342) ----------------------
computePath true numwaypoints 4
-- drawing line from (0.0, 1.0, 0.0) to (0.0, 1.0, 0.0)
-- drawing line from (0.0, 1.0, 0.0) to (-33.63971, 0.0, -14.722342)
-- drawing line from (-33.63971, 0.0, -14.722342) to (-33.63971, 0.0, -14.722342)
Navigating to (0.6174187, 1.4975667E-6, -19.15402)
---------------------- drawing the path to (0.6174187, 1.4975667E-6, -19.15402) ----------------------
computePath true numwaypoints 4
-- drawing line from (0.0, 1.0, 0.0) to (0.0, 1.0, 0.0)
-- drawing line from (0.0, 1.0, 0.0) to (0.6174187, 1.4975667E-6, -19.15402)
-- drawing line from (0.6174187, 1.4975667E-6, -19.15402) to (0.6174187, 1.4975667E-6, -19.15402)
Navigating to (6.468271, 0.0, 3.6891866)
---------------------- drawing the path to (6.468271, 0.0, 3.6891866) ----------------------
computePath true numwaypoints 4
-- drawing line from (0.0, 1.0, 0.0) to (0.0, 1.0, 0.0)
-- drawing line from (0.0, 1.0, 0.0) to (6.468271, 0.0, 3.6891866)
-- drawing line from (6.468271, 0.0, 3.6891866) to (6.468271, 0.0, 3.6891866)
Navigating to (-10.664963, 0.0032653809, 21.562746)
---------------------- drawing the path to (-10.664963, 0.0032653809, 21.562746) ----------------------
computePath true numwaypoints 4
-- drawing line from (0.0, 1.0, 0.0) to (0.0, 1.0, 0.0)
-- drawing line from (0.0, 1.0, 0.0) to (-10.664963, 0.0032653809, 21.562746)
-- drawing line from (-10.664963, 0.0032653809, 21.562746) to (-10.664963, 0.0032653809, 21.562746)
Navigating to (-17.053392, 0.0, 35.465214)
---------------------- drawing the path to (-17.053392, 0.0, 35.465214) ----------------------
computePath true numwaypoints 4
-- drawing line from (0.0, 1.0, 0.0) to (0.0, 1.0, 0.0)
-- drawing line from (0.0, 1.0, 0.0) to (-17.053392, 0.0, 35.465214)
-- drawing line from (-17.053392, 0.0, 35.465214) to (-17.053392, 0.0, 35.465214)
Navigating to (-28.099236, 0.0, 27.934511)
---------------------- drawing the path to (-28.099236, 0.0, 27.934511) ----------------------
computePath true numwaypoints 5
-- drawing line from (0.0, 1.0, 0.0) to (0.0, 1.0, 0.0)
-- drawing line from (0.0, 1.0, 0.0) to (-27.0, -0.0, 27.0)
-- drawing line from (-27.0, -0.0, 27.0) to (-28.099236, 0.0, 27.934511)
-- drawing line from (-28.099236, 0.0, 27.934511) to (-28.099236, 0.0, 27.934511)
Navigating to (-36.994263, 0.0, 17.938808)
---------------------- drawing the path to (-36.994263, 0.0, 17.938808) ----------------------
computePath true numwaypoints 5
-- drawing line from (0.0, 1.0, 0.0) to (0.0, 1.0, 0.0)
-- drawing line from (0.0, 1.0, 0.0) to (-17.0, 0.07108292, 18.0)
-- drawing line from (-17.0, 0.07108292, 18.0) to (-36.994263, 0.0, 17.938808)
-- drawing line from (-36.994263, 0.0, 17.938808) to (-36.994263, 0.0, 17.938808)
Navigating to (-17.046722, 14.656652, 9.358051)
---------------------- drawing the path to (-17.046722, 14.656652, 9.358051) ----------------------
computePath true numwaypoints 4
-- drawing line from (0.0, 1.0, 0.0) to (0.0, 1.0, 0.0)
-- drawing line from (0.0, 1.0, 0.0) to (-17.046722, 14.656652, 9.358051)
-- drawing line from (-17.046722, 14.656652, 9.358051) to (-17.046722, 14.656652, 9.358051)
Navigating to (-16.151163, 15.918786, 8.657517)
---------------------- drawing the path to (-16.151163, 15.918786, 8.657517) ----------------------
computePath true numwaypoints 4
-- drawing line from (0.0, 1.0, 0.0) to (0.0, 1.0, 0.0)
-- drawing line from (0.0, 1.0, 0.0) to (-16.151163, 15.918786, 8.657517)
-- drawing line from (-16.151163, 15.918786, 8.657517) to (-16.151163, 15.918786, 8.657517)
Navigating to (-23.259264, 1.1920929E-7, -2.3510997)
---------------------- drawing the path to (-23.259264, 1.1920929E-7, -2.3510997) ----------------------
computePath true numwaypoints 4
-- drawing line from (0.0, 1.0, 0.0) to (0.0, 1.0, 0.0)
-- drawing line from (0.0, 1.0, 0.0) to (-23.259264, 1.1920929E-7, -2.3510997)
-- drawing line from (-23.259264, 1.1920929E-7, -2.3510997) to (-23.259264, 1.1920929E-7, -2.3510997)
Navigating to (-40.682274, 0.0, -12.367432)
---------------------- drawing the path to (-40.682274, 0.0, -12.367432) ----------------------
computePath true numwaypoints 4
-- drawing line from (0.0, 1.0, 0.0) to (0.0, 1.0, 0.0)
-- drawing line from (0.0, 1.0, 0.0) to (-40.682274, 0.0, -12.367432)
-- drawing line from (-40.682274, 0.0, -12.367432) to (-40.682274, 0.0, -12.367432)
BUILD SUCCESSFUL (total time: 7 minutes 42 seconds)
Here is my code:
package mygame;
import com.jme3.ai.navmesh.NavMesh;
import com.jme3.ai.navmesh.NavMeshPathfinder;
import com.jme3.ai.navmesh.Path;
import com.jme3.app.SimpleApplication;
import com.jme3.collision.CollisionResults;
import com.jme3.font.BitmapText;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Ray;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Line;
import com.jme3.scene.shape.Sphere;
import com.jme3.terrain.geomipmap.TerrainQuad;
import com.jme3.terrain.heightmap.AbstractHeightMap;
import com.jme3.terrain.heightmap.ImageBasedHeightMap;
import com.jme3.texture.Texture;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import jme3tools.optimize.GeometryBatchFactory;
/**
* test
*
* @author normenhansen
*/
public class Main extends SimpleApplication {
private TerrainQuad terrain;
Material mat_terrain;
Spatial endSphere;
NavMeshPathfinder navi;
public static void main(String[] args) {
Main app = new Main();
app.start();
}
@Override
public void simpleInitApp() {
initCrossHairs(); // a "+" in the middle of the screen to help aiming
initKeys(); // load custom key mappings
Vector3f startvec = new Vector3f(0, 1, 0);
Vector3f endvecdefault = new Vector3f(320, 5, 320);
mat_terrain = new Material(assetManager, "Common/MatDefs/Terrain/Terrain.j3md");
mat_terrain.setTexture("Alpha", assetManager.loadTexture("Textures/alphamap.png"));
Texture rock = assetManager.loadTexture("Textures/grid8.png");
rock.setWrap(Texture.WrapMode.Repeat);
mat_terrain.setTexture("Tex3", rock);
mat_terrain.setFloat("Tex3Scale", 512f);
Texture heightMapImage = assetManager.loadTexture("Textures/small_1.png");
AbstractHeightMap heightmap = new ImageBasedHeightMap(heightMapImage.getImage());
heightmap.load();
heightmap.smooth(1f);
int patchSize = 129;
terrain = new TerrainQuad("my terrain", patchSize, 129, heightmap.getHeightMap());
terrain.setMaterial(mat_terrain);
terrain.setLocalTranslation(0, 0, 0);
terrain.setLocalScale(1, 1, 1);
rootNode.attachChild(terrain);
Material mat_brick = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat_brick.setTexture("ColorMap", assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.jpg"));
Material matstart = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
matstart.setColor("Color", ColorRGBA.Green);
Material matend = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
matend.setColor("Color", ColorRGBA.Red);
Spatial startSphere = new Geometry("start", new Sphere(100, 100, 1));
startSphere.setMaterial(matstart);
startSphere.setLocalTranslation(startvec);
endSphere = new Geometry("end", new Sphere(100, 100, 1));
endSphere.setMaterial(matend);
endSphere.setLocalTranslation(endvecdefault);
rootNode.attachChild(startSphere);
rootNode.attachChild(endSphere);
flyCam.setMoveSpeed(500);
Mesh mesh = new Mesh();
GeometryBatchFactory.mergeGeometries(findGeometries(terrain, new LinkedList<Geometry>()), mesh);
NavMesh navMesh = new NavMesh(mesh);
navi = new NavMeshPathfinder(navMesh);
navi.setPosition(startvec);
navi.setEntityRadius(1);
//doClick(endvecdefault);
}
@Override
public void simpleUpdate(float tpf) {
//TODO: add update code
}
@Override
public void simpleRender(RenderManager rm) {
//TODO: add render code
}
private List<Geometry> findGeometries(Node node, List<Geometry> geoms) {
for (Iterator<Spatial> it = node.getChildren().iterator(); it.hasNext();) {
Spatial spatial = it.next();
if (spatial instanceof Geometry) {
geoms.add((Geometry) spatial);
} else if (spatial instanceof Node) {
findGeometries((Node) spatial, geoms);
}
}
return geoms;
}
/**
* A centred plus sign to help the player aim.
*/
protected void initCrossHairs() {
setDisplayStatView(false);
guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
BitmapText ch = new BitmapText(guiFont, false);
ch.setSize(guiFont.getCharSet().getRenderedSize() * 2);
ch.setText("+"); // crosshairs
ch.setLocalTranslation( // center
settings.getWidth() / 2 - ch.getLineWidth() / 2, settings.getHeight() / 2 + ch.getLineHeight() / 2, 0);
guiNode.attachChild(ch);
}
/**
* Declaring the "Shoot" action and mapping to its triggers.
*/
private void initKeys() {
inputManager.addMapping("Shoot",
new KeyTrigger(KeyInput.KEY_SPACE), // trigger 1: spacebar
new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); // trigger 2: left-button click
inputManager.addListener(actionListener, "Shoot");
}
public void computeNavigationPath(Vector3f endvec) {
boolean computePath = navi.computePath(endvec);
System.out.println("");
System.out.println("---------------------- drawing the path to " + endvec + " ----------------------");
System.out.println("computePath " + computePath + " numwaypoints " + navi.getPath().getWaypoints().size());
Iterator it = navi.getPath().iterator();
Vector3f previous = null;
while (it.hasNext()) {
Path.Waypoint wp = (Path.Waypoint) it.next();
if (previous != null) {
Line line = new Line(previous, wp.getPosition());
Geometry drawLine = new Geometry("aline", line);
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.setColor("Color", ColorRGBA.Blue);
drawLine.setMaterial(mat);
System.out.println(" -- drawing line from " + previous + " to " + wp.getPosition());
rootNode.attachChild(drawLine);
}
previous = wp.getPosition();
}
}
/**
* Defining the "Shoot" action: Determine what was hit and how to respond.
*/
private ActionListener actionListener = new ActionListener() {
public void onAction(String name, boolean keyPressed, float tpf) {
if (name.equals("Shoot") && !keyPressed) {
// 1. Reset results list.
CollisionResults results = new CollisionResults();
// 2. Aim the ray from cam loc to cam direction.
Ray ray = new Ray(cam.getLocation(), cam.getDirection());
// 3. Collect intersections between Ray and Shootables in results list.
rootNode.collideWith(ray, results);
// 5. Use the results (we mark the hit object)
if (results.size() > 0) {
Vector3f closest = results.getClosestCollision().getContactPoint();
endSphere.setLocalTranslation(closest);
rootNode.attachChild(endSphere);
System.out.println("Navigating to " + closest);
computeNavigationPath(closest);
} else {
// No hits? Then remove the red sphere.
rootNode.detachChild(endSphere);
}
}
}
};
}