Move geometry by picking it and dragging by mouse

Hi,

I am trying to move geometry by picking it and dragging by mouse.
not sure whats wrong with this code… I am able to pick the geometry I want to move, but when I drag it, its not working as expected. see the video, code and output log below. (Ignore cross hair in video, it has nothing to do with function).
!! Cubes in Red, Green Yellow and Blue are geometrys I want to move. !!

    inputManager.addListener((ActionListener) (String name, boolean isPressed, float tpf) -> {

        if (name.equals("RIGHT_CLICK") && isPressed) {
            Material m = geom2.getMaterial();
            m.getAdditionalRenderState().setWireframe(!m.getAdditionalRenderState().isWireframe());
        }
        if (name.equals("LEFT_CLICK")) {
            Vector2f mouseCoords = new Vector2f(inputManager.getCursorPosition());
            Ray ray = new Ray(cam.getWorldCoordinates(mouseCoords, 0),
                    cam.getWorldCoordinates(mouseCoords, 1).subtractLocal(
                    cam.getWorldCoordinates(mouseCoords, 0)).normalizeLocal());

            CollisionResults results = new CollisionResults();
            int resCount = rootNode.collideWith(ray, results);
            if (isPressed) {

                if (resCount > 0) {
                    Geometry geo = results.getClosestCollision().getGeometry();
                    if (geo != null && geo.getName().startsWith("Point")) {
                        System.out.println(geo.getName() + " Selected.");
                        selectedGeometry = geo;
                        movePoint = true;
                    }
                }
            } else {
                movePoint = false;
            }

        }
        if (name.equals("RECORD") && isPressed) {
            recorderAppState.setQuality(.5f);
            recorderAppState.setEnabled(true);
            stateManager.attach(recorderAppState); //start recording
        }

    }, "RIGHT_CLICK", "LEFT_CLICK", "RECORD");
    inputManager.addListener(analogListener, "TRIGGER_ROTATEDRAG", "TRIGGER_UP", "TRIGGER_DOWN", "TRIGGER_LEFT", "TRIGGER_RIGHT");
}

private AnalogListener analogListener = new AnalogListener() {
    public void onAnalog(String name, float intensity, float tpf) {

        movePoint(tpf);

//            if (name.equals("TRIGGER_LEFT")) {
//                movePoint(tpf);
//            } else if (name.equals("TRIGGER_RIGHT")) {
//                movePoint(tpf);
//            } else if (name.equals("TRIGGER_UP")) {
//                movePoint(tpf);
//            } else if (name.equals("TRIGGER_DOWN")) {
//                movePoint(tpf);
//            }
    }

    private void movePoint(float tpf) {
        if (movePoint && selectedGeometry != null) {
            Vector2f mouseCoords = new Vector2f(inputManager.getCursorPosition());
            Vector3f p1 = selectedGeometry.getLocalTranslation().clone();
            Vector3f p2 = cam.getWorldCoordinates(mouseCoords, 0.0f);
            p2.setZ(0.0f);
            Vector3f p3 = selectedGeometry.worldToLocal(p2, null);
            p3.setZ(p1.z);
            System.out.println("Finl Trans: " + p3 + ", Mous Loc: " + p2 + ", Old Gom Loc: " + p1);
            selectedGeometry.setLocalTranslation(p3);
        }
    }
};

Here is output from “movePoint(…)” method.

Point Red Selected.
Finl Trans: (1.7533128, -1.7625176, 2.0), Mous Loc: (-0.24668714, 0.23748247, 0.0), Old Gom Loc: (-2.0, 2.0, 2.0)
Finl Trans: (-2.0, 1.9990796, 2.0), Mous Loc: (-0.24668714, 0.23656197, 0.0), Old Gom Loc: (1.7533128, -1.7625176, 2.0)
Finl Trans: (1.7533128, -1.7634381, 2.0), Mous Loc: (-0.24668714, 0.23564151, 0.0), Old Gom Loc: (-2.0, 1.9990796, 2.0)
Finl Trans: (-2.0, 1.9981592, 2.0), Mous Loc: (-0.24668714, 0.23472105, 0.0), Old Gom Loc: (1.7533128, -1.7634381, 2.0)
Finl Trans: (1.7533128, -1.765279, 2.0), Mous Loc: (-0.24668714, 0.23288009, 0.0), Old Gom Loc: (-2.0, 1.9981592, 2.0)
Finl Trans: (-2.0, 1.9972386, 2.0), Mous Loc: (-0.24668714, 0.23195958, 0.0), Old Gom Loc: (1.7533128, -1.765279, 2.0)
Finl Trans: (1.7533128, -1.7661995, 2.0), Mous Loc: (-0.24668714, 0.23103912, 0.0), Old Gom Loc: (-2.0, 1.9972386, 2.0)
Finl Trans: (-1.9990795, 1.9963181, 2.0), Mous Loc: (-0.2457667, 0.23011866, 0.0), Old Gom Loc: (1.7533128, -1.7661995, 2.0)
Finl Trans: (1.7533128, -1.7661995, 2.0), Mous Loc: (-0.2457667, 0.23011866, 0.0), Old Gom Loc: (-1.9990795, 1.9963181, 2.0)
Finl Trans: (-1.9990795, 1.9972386, 2.0), Mous Loc: (-0.2457667, 0.23103912, 0.0), Old Gom Loc: (1.7533128, -1.7661995, 2.0)
Finl Trans: (1.7533128, -1.765279, 2.0), Mous Loc: (-0.2457667, 0.23195958, 0.0), Old Gom Loc: (-1.9990795, 1.9972386, 2.0)
Finl Trans: (-1.9990795, 1.9990796, 2.0), Mous Loc: (-0.2457667, 0.23380055, 0.0), Old Gom Loc: (1.7533128, -1.765279, 2.0)
Finl Trans: (1.7533128, -1.7634381, 2.0), Mous Loc: (-0.2457667, 0.23564151, 0.0), Old Gom Loc: (-1.9990795, 1.9990796, 2.0)
Finl Trans: (-1.9990795, 2.0, 2.0), Mous Loc: (-0.2457667, 0.23656197, 0.0), Old Gom Loc: (1.7533128, -1.7634381, 2.0)
Finl Trans: (1.7533128, -1.761597, 2.0), Mous Loc: (-0.2457667, 0.23840293, 0.0), Old Gom Loc: (-1.9990795, 2.0, 2.0)
Finl Trans: (-2.0, 2.0009205, 2.0), Mous Loc: (-0.24668714, 0.23932339, 0.0), Old Gom Loc: (1.7533128, -1.761597, 2.0)
Finl Trans: (1.7533128, -1.7615972, 2.0), Mous Loc: (-0.24668714, 0.23932339, 0.0), Old Gom Loc: (-2.0, 2.0009205, 2.0)
Finl Trans: (-2.0009205, 2.001841, 2.0), Mous Loc: (-0.24760765, 0.2402439, 0.0), Old Gom Loc: (1.7533128, -1.7615972, 2.0)
Finl Trans: (1.7533128, -1.7615972, 2.0), Mous Loc: (-0.24760765, 0.2402439, 0.0), Old Gom Loc: (-2.0009205, 2.001841, 2.0)
Finl Trans: (-2.0018408, 2.0027616, 2.0), Mous Loc: (-0.2485281, 0.24116436, 0.0), Old Gom Loc: (1.7533128, -1.7615972, 2.0)
Finl Trans: (1.7533127, -1.7615973, 2.0), Mous Loc: (-0.2485281, 0.24116436, 0.0), Old Gom Loc: (-2.0018408, 2.0027616, 2.0)
Finl Trans: (-2.0027614, 2.0027616, 2.0), Mous Loc: (-0.2494486, 0.24116436, 0.0), Old Gom Loc: (1.7533127, -1.7615973, 2.0)
Finl Trans: (1.7523923, -1.7615973, 2.0), Mous Loc: (-0.25036904, 0.24116436, 0.0), Old Gom Loc: (-2.0027614, 2.0027616, 2.0)

Well, the above code seems kind of like nonsense to me.

Described line by line:
-get the world coordinates of the mouse right at the screen
-arbitrarily set z to 0 no matter where the camera or objects happen to be right now
-get that random point in geometry local space
-force the z to be the world z of the object (which makes no sense to the local space point anyway)
-set the local translation of the geometry to that… which also makes no sense because that’s a position in the geometry’s own local space… not its parents’.

If you want to move the object to the mouse cursor at the object’s z position then the math is very different than that.

First, find the mouse’s world position at the object’s ‘plane’:

float dist = selectedGeometry.getWorldTranslation().distance(camera.getLocation());
float projZ = camera.getViewToProjectionZ(dist);
Vector3f mouseWorld = camera.getWorldCoordinates(mouseCoords, projZ);

No, if your object is in the root then you can just set that location… if it’s not in the root the you’d need to get the local position relative to its parent… not to itself. (That would be like setting the position of your car inside of your car… doesn’t really make sense.)

Vector3f local = selectedGeometry.getParent().worldToLocal(mouseWorld);
selectedGeometry.setLocalTranslation(local);

Also note: you could probably remove like 90% of your posted code if you just use Lemur’s built in picking support. It works for 3D objects just as well as 2D.

Thanks fro resolving my “nonsense” work. can you show me how to make it using lemur’s built in picking support?

The math is the same once you’ve got your picking.

The easiest way to get started might be to skim this section of the docs:

…and maybe look at this example:

To quickly get started with Lemur and get the dependencies hooked up and so on, you can check here:

…and just stop after this:
GuiGlobals.initialize(this);

That line is all you need to initialize the built-in picking support. The first link I gave you talks about manually setting it up but if you call GuiGlobals.initialize(app) then you don’t have to do that.

After that, you can add a mouse listener or cursor listener to any JME Spatial.

If you get to that point, we can talk about whether you want to add a listener to every draggable spatial or one listener to the parent that contains them.

But note: for much of what you want to do, you might also be able to use Lemur’s built in default DragHandler (or at least cut and paste it)… then you don’t even have to do the math anymore.

CursorEventControl.addListenersToSpatial(selectableSpatial, new DragHandler());

I think I wrote it to deal with 3D and 2D… I could be misremembering but I can’t figure out why else it uses CursorListener instead of MouseListener.

What A Great Stuff…:chimpanzee_amused: It reminds me java event model…
BTW I didn’t add “GuiGlobals.initialize(this);” in code but its still working for mouse events.

How to make “mouseMoved” working for other buttons like BUTTON_MIDDLE or BUTTON_RIGHT.
currently its working only for BUTTON_LEFT.
here is my code.

    protected void click(MouseButtonEvent event, Spatial target, Spatial capture) {

        if (event.getButtonIndex() == MouseInput.BUTTON_MIDDLE) {
            movePoint = true;
        } else {
            movePoint = false;
        }
    }

    @Override
    public void mouseMoved(MouseMotionEvent event, Spatial target, Spatial capture) {
        if (movePoint) {
            CursorEventControl.addListenersToSpatial(target, new DragHandler());
        }
    }

I see “cursorButtonEvent” method in “DragHandler”. It returns void if BUTTON_LEFT is not pressed.
I think it will be more handy if press button is configurable like “new dragHandler(MouseInput.BUTTON_MIDDLE )”.

Well, you had to do something. Either you did that or you specifically added the app state… otherwise nothing is going to fire those events.

Well, just cut and paste DragHandler into your own class and do whatever processing you need. Yes, DragHandler could probably be expanded but it’s already doing the job for which it was intended… it just happens to also be convenient for users to use in some cases.

yep, I already did that for me. I just thought to share my opinion on it.