[SOLVED] Picking in a big scene doesn't work very well

Hi everyone,

I have a large scene (749 nodes with each 2 spheres) generated from a JSON file, and I want to be able to do normal picking. but for some reason jME doesn’t want to. I can snipe a geometry at position 7.2, 7.0, 14.0 from up to 751 units away, but if I want a click on a geometry at position 28.5,28.6,0.3, I have to be within approximately 25 units.

I have absolutely no idea why this happens, so I did some searching on the forum. No one seemed to have reported this problem (or I have not searched long enough).

I’m also not sure what code could be responsible. For picking I basically copy-pasted the tutorial. If you need a certain bit of code, just ask for it.

Do you have any idea what could be causing this problem?

What do you hit when you make the shoot at 28.5,28.6,0.3 ? You need to hit something! Print out the name of the geometry you hit (not only the “pickupable” spheres).

Is your Ray long enough?

Maybe you hit an invisble game object for example the SkyBox geometry or something like that.

I already did some debugging. Forgot to mention it.
For each of those 749 nodes, I have a repr#id and a coll#id. The repr is the representation of the object, while the coll is invisible (cullmode: both) and is larger.

This is what happens:

  1. I click my mouse button
  2. The input is registered
  3. I collide with a ray
  4. The collision results are printed

The collision results are either a bunch of collisions with colls and reprs or empty.

That doesn’t make any sense to me. First of all, I can hit something from 751 wu away. Secondly, why would a ray have a length? Isn’t the whole point of having a ray to have a line that goes infinitely really, really far?

No, I do not have any invisible geometries (apart from the colls, which I’m trying to hit).

Normally, that’s absolutely true! I just meant that, because you can set the “length” with setLimit() when I remember correctly. However, this doesn’t seem to be the issue here :slight_smile:

I don’t know what the issue is, sorry…

Could you provide a test-case scenario which shows this strange behavior? Maybe it’s just some stupid bug in the engine but I don’t really think so…

Yep, you will get a lot more help debugging your code if you show us the code.

Picking works fine. I do it in way more complicated cases than you’ve described.

Note: Lemur has picking built in and then you wouldn’t have to worry about it. You can even use the picking without any of the other stuff if you want.

I created this test case:

package test;

import com.jme3.app.SimpleApplication;
import com.jme3.collision.CollisionResult;
import com.jme3.collision.CollisionResults;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Ray;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
import com.jme3.texture.Texture;

/**
 * Test class
 */
public class Main extends SimpleApplication implements ActionListener {

	public static void main( String... args ) {
		Main main = new Main();
		main.start();
	}
	
	public void simpleInitApp() {
		flyCam.setMoveSpeed(45f);
		flyCam.setDragToRotate(true);
		
		
		for(int i=0;i<749;i++) {
			createBox(i, false);
			createBox(i, true);
		}
		
		inputManager.addMapping("click", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
		inputManager.addListener(this, "click");
	}
    
    public void createBox(int i, boolean ghost) {
    	Box box = new Box(1, 1, 1);
        Geometry geom = new Geometry("repr#"+i, box);
        Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        mat.setColor("Color", ColorRGBA.Blue);
        
        Texture texture = assetManager.loadTexture("Textures/Monkey.png");
        mat.setTexture("ColorMap", texture);
        
        float x = FastMath.nextRandomFloat() * 50;
        float y = FastMath.nextRandomFloat() * 50;
        float z = FastMath.nextRandomFloat() * 50;
        Vector3f pos = new Vector3f(x,y,z);
        
        geom.setLocalTranslation(pos);
        
        if(ghost) {
        	geom.setName("coll#"+i);
        	geom.setLocalScale(1.1f);
        	//mat.getAdditionalRenderState().setFaceCullMode(FaceCullMode.FrontAndBack);
        }
        
        geom.setMaterial(mat);
        rootNode.attachChild(geom);
    }

	@Override
	public void onAction(String name, boolean isPressed, float tpf) {
		// TODO Auto-generated method stub
		if(isPressed) {
			System.out.println("input...");
			ray();
		}
	}
	
	public void ray() {
		CollisionResults results = new CollisionResults();
		
		Vector2f screenClick = inputManager.getCursorPosition();
		Vector3f spaceClick = cam.getWorldCoordinates(screenClick, 0f).clone();
		Vector3f dir = cam.getWorldCoordinates(screenClick, 1f).subtractLocal(spaceClick).normalizeLocal();
		
		Ray ray = new Ray(spaceClick, dir);
		
		rootNode.collideWith(ray, results);
		
		System.out.println(results);
		
		if(results.size() > 0) {
			CollisionResult c = results.getClosestCollision();
			System.out.println(c.getDistance());
			System.out.println(c.getGeometry().getLocalTranslation());
			System.out.println(c.getGeometry().getName().substring(4));
		}
	}
}

Sadly, it works.

I forgot to subtract in this line: Vector3f dir = cam.getWorldCoordinates(screenClick, 1f).subtractLocal(spaceClick).normalizeLocal(). That probably created precision errors or something.
:confused:

Well, no… it just made a direction that wasn’t really a direction and definitely not the direction you wanted. You needed an apple but instead you took an elephant and shrunk it down to fruit size. Results will certainly be confusing then.

However, glad you found the solutiom for your issue :grinning: