Yeah sure. I have it set up so I can choose different shapes (single triangle, quad, 2_by_2, etc) so ignore the comparison stuff, but all the code is there for you to go through.
Notice I don’t re-create things in the loop un-necessarily and that I have a timer set up for the ray, because its pointless firing it so many times. And I have set a limit on the ray distance. You may want to change that.
Ray terrainCollisionRay;
CollisionResults collisionResults = new CollisionResults();
float delay = .05f;
float currentDelay = 0f;
// somewhere in your constructor or initializer..
terrainCollisionRay = new Ray();
terrainCollisionRay.setLimit(20f);
@Override
public void update(float tpf) {
currentDelay += tpf;
if (currentDelay >= delay) {
displayTerrainTriangle();
currentDelay = 0f;
}
if( worldLoc.needsUpdate() ) {
worldLoc.update();
}
}
private void displayTerrainTriangle() {
terrainCollisionRay.setOrigin(getApplication().getCamera().getLocation());
terrainCollisionRay.setDirection(getApplication().getCamera().getDirection());
terrainNode.collideWith(terrainCollisionRay, collisionResults);
if (collisionResults.size() < 1) {
return;
}
Triangle triangle = collisionResults.getClosestCollision().getTriangle(null);
updateSelection(new Vector3f[]{
collisionResults.getClosestCollision().getGeometry().localToWorld(triangle.get1(), null),
collisionResults.getClosestCollision().getGeometry().localToWorld(triangle.get2(), null),
collisionResults.getClosestCollision().getGeometry().localToWorld(triangle.get3(), null)
});
collisionResults.clear();
}
private void updateSelection(Vector3f[] vertices) {
// if they are the same, update the mesh,
// if not, create a new mesh.
if (this.currentSelectionType == this.lastSelectionType) {
SelectionUtils.updateMesh(terrainSelectionMesh, vertices);
terrainSelectionGeom.updateModelBound();
}
else {
this.terrainSelectionMesh = new Mesh();
SelectionUtils.createMesh(terrainSelectionMesh, vertices, currentSelectionType.getIndexes());
this.terrainSelectionGeom = new Geometry("terrain-selector-geom", this.terrainSelectionMesh);
this.terrainSelectionGeom.setMaterial(this.terrainSelectionMat);
// attach our selector to the world...
getState(TerrainState.class).getLandNode().attachChild(terrainSelectionGeom);
terrainSelectionGeom.updateModelBound();
this.lastSelectionType = this.currentSelectionType;
}
}
// a utility class that really shouldnt be static, but suffices for the purpose. don't copy me.
public final class SelectionUtils {
public static void createMesh(Mesh mesh, Vector3f[] vertices, int[] indexes) {
mesh.setBuffer(VertexBuffer.Type.Position, 3, BufferUtils.createFloatBuffer(vertices));
mesh.setBuffer(VertexBuffer.Type.Index, 3, BufferUtils.createIntBuffer(indexes));
mesh.updateBound();
}
public static void updateMesh(Mesh mesh, Vector3f[] vertices) {
FloatBuffer vBuf = (FloatBuffer)mesh.getBuffer(VertexBuffer.Type.Position).getData();
for (int i = 0; i < vertices.length; i++) {
BufferUtils.setInBuffer(vertices[i], vBuf, i);
}
mesh.setBuffer(VertexBuffer.Type.Position, 3, vBuf);
mesh.updateBound();
}
}
oh. and maybe you need this.
public enum SelectionType {
SINGLE_TRIANGLE(new int[]{ 2,0,1 }),
QUAD(new int[]{ 2,0,1, 1,3,2 }),
NONE(null);
private final int[] indexes;
SelectionType(int[] indexes) {
this.indexes = indexes;
}
public int[] getIndexes() {
return this.indexes;
}
}