Sure…
import com.jme.app.SimpleGame;
import com.jme.bounding.BoundingBox;
import com.jme.input.FirstPersonHandler;
import com.jme.input.KeyBindingManager;
import com.jme.input.KeyInput;
import com.jme.input.MouseInput;
import com.jme.intersection.PickResults;
import com.jme.intersection.TrianglePickResults;
import com.jme.math.FastMath;
import com.jme.math.Quaternion;
import com.jme.math.Ray;
import com.jme.math.Triangle;
import com.jme.math.Vector2f;
import com.jme.math.Vector3f;
import com.jme.scene.Node;
import com.jme.scene.Spatial;
import com.jme.scene.TriMesh;
import com.jme.scene.shape.Sphere;
import com.jme.system.DisplaySystem;
import java.awt.Point;
import java.util.ArrayList;
public class PickTest extends SimpleGame {
final Node pickNode = new Node();
final float angle = 5 * FastMath.DEG_TO_RAD;
final Quaternion upRotation = new Quaternion().fromAngleAxis( angle, Vector3f.UNIT_X );
final Quaternion downRotation = new Quaternion().fromAngleAxis( -angle, Vector3f.UNIT_X );
final Quaternion leftRotation = new Quaternion().fromAngleAxis( angle, Vector3f.UNIT_Y );
final Quaternion rightRotation = new Quaternion().fromAngleAxis( -angle, Vector3f.UNIT_Y );
final MousePicker picker = new MousePicker();
//
boolean isTriangleAccurate = true;
public static void main( String[] args ) {
new PickTest();
}
public PickTest() {
this.setConfigShowMode( ConfigShowMode.AlwaysShow );
this.start();
}
@Override
protected void simpleUpdate() {
boolean updateNode = false;
if( KeyBindingManager.getKeyBindingManager().isValidCommand( "UP", false ) ){
pickNode.getLocalRotation().multLocal( upRotation );
updateNode = true;
}
if( KeyBindingManager.getKeyBindingManager().isValidCommand( "DOWN", false ) ){
pickNode.getLocalRotation().multLocal( downRotation );
updateNode = true;
}
if( KeyBindingManager.getKeyBindingManager().isValidCommand( "LEFT", false ) ){
pickNode.getLocalRotation().multLocal( leftRotation );
updateNode = true;
}
if( KeyBindingManager.getKeyBindingManager().isValidCommand( "RIGHT", false ) ){
pickNode.getLocalRotation().multLocal( rightRotation );
updateNode = true;
}
if( KeyBindingManager.getKeyBindingManager().isValidCommand( "TOGGLE_CAMERA", false ) ){
if( cam.isParallelProjection() ){
cameraPerspective();
} else{
cameraParallel();
}
}
if( KeyBindingManager.getKeyBindingManager().isValidCommand( "TOGGLE_TRI_ACCURATE", false ) ){
isTriangleAccurate = !isTriangleAccurate;
}
picker.setPickSpatial( rootNode );
picker.checkMousePicks( isTriangleAccurate );
if( picker.wasObjectPicked() ){
System.out.print( "Picked" + picker.getPickedObjectName() );
if( isTriangleAccurate ){
System.out.print( ": " + picker.getWorldPickLocation() );
}
System.out.print( "n" );
} else{
System.out.println( "" );
}
}
@Override
protected void simpleInitGame() {
KeyBindingManager.getKeyBindingManager().set( "TOGGLE_TRI_ACCURATE", KeyInput.KEY_RETURN );
KeyBindingManager.getKeyBindingManager().set( "TOGGLE_CAMERA", KeyInput.KEY_SPACE );
KeyBindingManager.getKeyBindingManager().set( "UP", KeyInput.KEY_NUMPAD8 );
KeyBindingManager.getKeyBindingManager().set( "DOWN", KeyInput.KEY_NUMPAD2 );
KeyBindingManager.getKeyBindingManager().set( "RIGHT", KeyInput.KEY_NUMPAD6 );
KeyBindingManager.getKeyBindingManager().set( "LEFT", KeyInput.KEY_NUMPAD4 );
MouseInput.get().setCursorVisible( true );
( (FirstPersonHandler) this.input ).setButtonPressRequired( true );
cameraParallel();
showBounds = true;
pickNode.attachChild( new Sphere( "sphere", 12, 12, 5 ) );
pickNode.setModelBound( new BoundingBox() );
pickNode.updateModelBound();
rootNode.attachChild( pickNode );
}
}
class MousePicker {
private String closestPickedName = null;
private TriMesh savedMesh = null;
private Spatial pickNode = null; // Typically this will be the rootNode
//
private final PickResults pickResults = new TrianglePickResults();
private final DisplaySystem display;
//
private final Ray ray = new Ray();
private final Vector2f screenPos = new Vector2f();
private final Vector2f cursorPosition = new Vector2f();
private final Vector3f worldPickLocation = new Vector3f();
private final Vector3f camLocation = new Vector3f();
private final Vector3f tempWorldPick = new Vector3f();
private final Vector3f[] tempTriVerticies = new Vector3f[ 3 ];
private final Triangle pickedTriangle = new Triangle( new Vector3f(), new Vector3f(), new Vector3f() );
private final Triangle tempTriangle = new Triangle( new Vector3f(), new Vector3f(), new Vector3f() );
//
private final ArrayList<String> pickedNames = new ArrayList();
private final ArrayList<Integer> tempTriIndicies = new ArrayList();
//
private boolean objectWasPicked = false, triangleWasPicked = false, wasTriangleAccurate = false;
private boolean useCanvas = false, useSuppliedRay = false;
//
public MousePicker() {
display = DisplaySystem.getDisplaySystem();
useCanvas = false;
pickResults.setCheckDistance( true );
}
public MousePicker( boolean useCanvas ) {
this();
this.useCanvas = useCanvas;
}
public MousePicker( boolean useCanvas, Spatial pickNode ) {
this( useCanvas );
setPickSpatial( pickNode );
}
public void setPickSpatial( Spatial spatial ) {
pickNode = spatial;
}
public boolean checkMousePicks() {
this.useSuppliedRay = false;
return checkMousePicks( false );
}
public boolean checkMousePicks( boolean triangleAccurate ) {
this.useSuppliedRay = false;
return runPicker( triangleAccurate );
}
public boolean checkMousePicks( boolean triangleAccurate, Point cursorPosition ) {
if( cursorPosition != null ){
this.cursorPosition.set( cursorPosition.x, cursorPosition.y );
}
this.useSuppliedRay = false;
return runPicker( triangleAccurate );
}
public boolean checkMousePicks( boolean triangleAccurate, final Ray suppliedRay ) {
ray.set( suppliedRay );
useSuppliedRay = true;
return runPicker( triangleAccurate );
}
private boolean runPicker( boolean triangleAccurate ) {
if( pickNode == null ){
return false;
}
clearPickResults();
wasTriangleAccurate = triangleAccurate;
float shortestDist = Float.MAX_VALUE;
if( !useSuppliedRay ){
camLocation.set( DisplaySystem.getDisplaySystem().getRenderer().getCamera().getLocation() );
if( useCanvas ){
screenPos.set( cursorPosition );
} else{
screenPos.set( MouseInput.get().getXAbsolute(), MouseInput.get().getYAbsolute() );
}
try{
display.getPickRay( screenPos, useCanvas, ray );
} catch( Exception e ){
return false;
}
} else{
camLocation.set( ray.getOrigin() );
}
pickNode.findPick( ray, pickResults );
if( pickResults.getNumber() <= 0 ){
return false;
}
objectWasPicked = true;
for( int i = 0; i < pickResults.getNumber(); i++ ){
Node parent = pickResults.getPickData( i ).getTargetMesh().getParent();
// itterate up through nodes while:
// parent is not null AND parent has name AND parent does not equal pickNode
while( parent.getParent() != null &&
parent.getParent().getName() != null &&
!parent.getParent().equals( pickNode ) ){
parent = parent.getParent();
}
pickedNames.add( parent.getName() );
if( triangleAccurate ){
final TriMesh mesh = (TriMesh) pickResults.getPickData( i ).getTargetMesh();
for( Integer triIndex : pickResults.getPickData( i ).getTargetTris() ){
// Get a single triangle and set the world transformations
mesh.getTriangle( triIndex, tempTriVerticies );
setTriVerticies( tempTriangle, tempTriVerticies, mesh );
if( ray.intersect( tempTriangle ) ){
// get the exact location (in World coordinates) of the pick
triangleWasPicked = true;
ray.intersectWhere( tempTriangle, tempWorldPick );
final float tempDist = tempWorldPick.distance( camLocation );
// check to make sure picked triangle is the closest possible triangle
if( tempDist < shortestDist ){
// Set pickedTriangle and then save target mesh
setPickedTriangle( tempTriVerticies );
worldPickLocation.set( tempWorldPick );
closestPickedName = pickedNames.get( pickedNames.size() - 1 );
shortestDist = tempDist;
savedMesh = mesh;
}
}
} // End Triangle Accurate
}
}
if( triangleAccurate ){
return triangleWasPicked;
}
return objectWasPicked;
}
public boolean wasObjectPicked() {
if( wasTriangleAccurate ){
return triangleWasPicked;
}
return objectWasPicked;
}
public String getPickedObjectName() {
if( wasTriangleAccurate ){
if( closestPickedName != null ){
return closestPickedName;
} else{
return "";
}
}
try{
return pickedNames.get( 0 );
} catch( Exception e ){
return "";
}
}
public ArrayList<String> getAllPickedObjects() {
return pickedNames;
}
public Triangle getPickedTriangle() {
if( triangleWasPicked ){
return pickedTriangle;
}
return null;
}
public TriMesh getSavedMesh() {
return savedMesh;
}
public Vector3f getWorldPickLocation() {
return worldPickLocation;
}
public void clearPickResults() {
triangleWasPicked = false;
objectWasPicked = false;
savedMesh = null;
closestPickedName = null;
pickResults.clear();
tempTriIndicies.clear();
pickedNames.clear();
worldPickLocation.set( 0, 0, 0 );
pickedTriangle.get( 0 ).set( 0, 0, 0 );
pickedTriangle.get( 1 ).set( 0, 0, 0 );
pickedTriangle.get( 2 ).set( 0, 0, 0 );
}
// Save the triangle in terms of its original mesh (no transformations)
private void setPickedTriangle( Vector3f[] verts ) {
for( int i = 0; i < verts.length; ++i ){
pickedTriangle.get( i ).setX( verts[i].getX() );
pickedTriangle.get( i ).setY( verts[i].getY() );
pickedTriangle.get( i ).setZ( verts[i].getZ() );
}
pickedTriangle.calculateCenter();
}
private void setTriVerticies( Triangle triangle, Vector3f[] verts, TriMesh mesh ) {
for( int i = 0; i < verts.length; ++i ){
mesh.localToWorld( verts[i], triangle.get( i ) );
}
triangle.calculateCenter();
}
}
(I have included the 'picker' class that I have developed, feel free to use it; you might have to change how the names are 'accumulated' though...)