I have a small problem here.
I have played around with mouse picking for some time now, but I can't just get it right.
I have a plane at y(0) that extends most of the scene. I'm trying to take screen coordinates (mouse) and turn them into world coordinates (that are on the plane, hence y can be ignored).
The problem, however, is that I can quite understand what coordinates getWorldCoordinates is returning. If my object is in the middle of the screen, and my mouse is on it, how do I transform the coordinates returned by getWorldCoordinates into coordinates that are on the plane? Does getWorldCoordinates do merely inverse projection or does it do z buffer test?
Just to make this clearer:
I can get it working if I view everything from above with only camera offset of (0, y, 0), but not when (x, y, z) for example.
Furthermore, if getWorldCoordinates doesn't do z-test, how should I go about it?
Mouse picking is a multi step dance; first get screen coords, then translate screen coords to world coords, take world coords and draw a ray, check if any thing was intersected by the ray inside the defined distance.
Here is a mouse picking class I use that supports triangle accurate picking, feel free to use it. Basically it's self contained, just create it and set the pick node (node to search), then call checkPicks( [true/false] );
import com.jme.input.MouseInput;
import com.jme.intersection.BoundingPickResults;
import com.jme.intersection.PickResults;
import com.jme.math.Ray;
import com.jme.math.Vector2f;
import com.jme.math.Vector3f;
import com.jme.scene.Node;
import com.jme.scene.TriMesh;
import com.jme.system.DisplaySystem;
import java.util.ArrayList;
public class MousePicker {
private TriMesh mesh = null;
private TriMesh savedMesh = null;
private Node pickNode = null; // Typically this will be the rootNode
private ArrayList<String> pickedNames = new ArrayList<String>( 1 );
private Vector2f screenPos = new Vector2f();
private Vector3f worldCoords = new Vector3f();
private Vector3f worldCoords2 = new Vector3f();
private Vector3f[] triangleVerticies = new Vector3f[ 3 ];
private boolean objectWasPicked = false, triangleWasPicked = false;
public MousePicker() {
}
public MousePicker( Node node ) {
pickNode = node;
}
public void setPickNode( Node node ) {
pickNode = node;
}
public boolean checkMousePicks() {
if( pickNode == null ){
return false;
}
return checkMousePicks( false );
}
public boolean checkMousePicks( boolean triangleAccurate ) {
if( pickNode == null ){
return false;
}
pickedNames.clear();
return runPicker( pickNode, triangleAccurate );
}
private boolean runPicker( Node node, boolean triangleAccurate ) {
savedMesh = null;
screenPos.set( MouseInput.get().getXAbsolute(), MouseInput.get().getYAbsolute() );
worldCoords.set( DisplaySystem.getDisplaySystem().getWorldCoordinates( screenPos, 0 ) );
worldCoords2.set( DisplaySystem.getDisplaySystem().getWorldCoordinates( screenPos, 1 ) );
Ray ray = new Ray( worldCoords, worldCoords2.subtractLocal( worldCoords ).normalizeLocal() );
PickResults results = new BoundingPickResults();
results.setCheckDistance( true );
node.findPick( ray, results );
if( results.getNumber() > 0 ){
objectWasPicked = true;
for( int i = 0; i < results.getNumber(); i++ ){
pickedNames.add( results.getPickData( i ).getTargetMesh().getParentGeom().getParent().getName() );
System.out.println( results.getPickData( i ).getTargetMesh().getParentGeom().getParent().getName() );
if( triangleAccurate ){
mesh = (TriMesh) results.getPickData( i ).getTargetMesh().getParentGeom();
for( int j = 0; j < mesh.getTriangleCount(); j++ ){
mesh.getTriangle( j, triangleVerticies );
triangleWasPicked = ( ray.intersect( triangleVerticies[0].addLocal( mesh.getWorldTranslation() ),
triangleVerticies[1].addLocal( mesh.getWorldTranslation() ),
triangleVerticies[2].addLocal( mesh.getWorldTranslation() ) ) );
if( triangleWasPicked ){
savedMesh = mesh;
return true;
}
}
}
}
}
return ( objectWasPicked || triangleWasPicked );
}
public boolean wasObjectPicked() {
return !pickedNames.isEmpty();
}
public void clearPickedResults() {
pickedNames.clear();
}
public boolean wasObjectPicked( String query ) {
return pickedNames.contains( query );
}
public String getAllPickedObjects() {
return pickedNames.toString();
}
public Vector3f[] getPickedTriangle() {
return triangleVerticies;
}
public TriMesh getSavedMesh() {
return savedMesh;
}
}
basixs said:
Mouse picking is a multi step dance; first get screen coords, then translate screen coords to world coords, take world coords and draw a ray, check if any thing was intersected by the ray inside the defined distance.
Here is a mouse picking class I use that supports triangle accurate picking, feel free to use it. Basically it's self contained, just create it and set the pick node (node to search), then call checkPicks( [true/false] );
...
How does this give me the world position of the mouse cursor? I am not really interested in the object that has been picked, but the accurate mouse position in the scene projected onto the XZ plane. Am I missing something obvious here?
I just spend a lame amount of time with the same question, but finally got my answer. Check out this thread - http://www.jmonkeyengine.com/jmeforum/index.php?topic=7517.0, it has code examples also.
You will just have to adjust which coordinates you take from the ray as I use the code for looking for X and Y where Z=0