Problem implementing Drag and drop

I’m having problems implementing drag and drop functionality over X and Y axis. Selecting object is working fine. The problem is how to set the new location after releasing left mouse button. Something is wrong when I convert cursor position (2d) to world coordiates (3d). I want to move the selected object according to XY axis keeping object’s original Z value. I’m converting cursor position using following code:

[java]
final Vector2f click2d = TestDragAndDrop.this.inputManager.getCursorPosition();
final Vector3f click3d = TestDragAndDrop.this.cam.getWorldCoordinates(
new Vector2f(click2d.x, click2d.y), 0f).clone();
TestDragAndDrop.this.selectedGeom.setLocalTranslation(click3d);

[/java]

click3d shows values < 0

Full code

[java]
/*

  • Copyright © 2009-2012 jMonkeyEngine
  • All rights reserved.
  • Redistribution and use in source and binary forms, with or without
  • modification, are permitted provided that the following conditions are
  • met:
    • Redistributions of source code must retain the above copyright
  • notice, this list of conditions and the following disclaimer.
    • Redistributions in binary form must reproduce the above copyright
  • notice, this list of conditions and the following disclaimer in the
  • documentation and/or other materials provided with the distribution.
    • Neither the name of ‘jMonkeyEngine’ nor the names of its contributors
  • may be used to endorse or promote products derived from this software
  • without specific prior written permission.
  • THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  • “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  • TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  • PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  • CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  • EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  • PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  • PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  • LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  • NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  • SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    */

package com.jme3.physics.dyn4j.tests.miscellaneous;

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.Ray;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.shape.Box;

/**

  • Sample 8 - how to let the user pick (select) objects in the scene using the mouse or key presses. Can be used for

  • shooting, opening doors, etc.
    */
    public class TestDragAndDrop extends SimpleApplication {

    public static void main(final String[] args) {
    final TestDragAndDrop app = new TestDragAndDrop();
    app.start();
    }

    private Node shootables;
    private Geometry selectedGeom;

    @Override
    public void simpleInitApp() {
    this.flyCam.setEnabled(false);
    this.inputManager.setCursorVisible(true);

     initKeys();
    
     this.shootables = new Node("Shootables");
     this.rootNode.attachChild(this.shootables);
     this.shootables.attachChild(makeCube("cube", 1, 1, 1));
     this.rootNode.attachChild(makeFloor());
    

    }

    private void initKeys() {
    this.inputManager.addMapping(“Shoot”, new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
    this.inputManager.addListener(this.actionListener, “Shoot”);
    }

    private final ActionListener actionListener = new ActionListener() {

     @Override
     public void onAction(final String name, final boolean keyPressed, final float tpf) {
         if (name.equals("Shoot")) {
             if (keyPressed) {
                 final Vector2f click2d = TestDragAndDrop.this.inputManager.getCursorPosition();
                 final Vector3f click3d = TestDragAndDrop.this.cam.getWorldCoordinates(
                         new Vector2f(click2d.x, click2d.y), 0f).clone();
                 final Vector3f dir = TestDragAndDrop.this.cam
                         .getWorldCoordinates(new Vector2f(click2d.x, click2d.y), 1f).subtractLocal(click3d)
                         .normalizeLocal();
    
                 System.out.println("click2d" + click2d);
                 System.out.println("click3d" + click3d);
                 System.out.println("dir" + dir);
    
                 // 1. Reset results list.
                 final CollisionResults results = new CollisionResults();
                 // 2. Aim the ray from cam loc to cam direction.
                 final Ray ray = new Ray(click3d, dir);
    
                 // 3. Collect intersections between Ray and Shootables in results list.
                 TestDragAndDrop.this.shootables.collideWith(ray, results);
    
                 // 5. Use the results (we mark the hit object)
                 if (results.size() &gt; 0) {
                     // The closest collision point is what was truly hit:
                     final CollisionResult closest = results.getClosestCollision();
                     // Let's interact - we mark the hit with a red dot.
                     TestDragAndDrop.this.selectedGeom = closest.getGeometry();
                 } else {
                     // // No hits? Then remove the red mark.
                     TestDragAndDrop.this.selectedGeom = null;
                 }
             } else {
                 final Vector2f click2d = TestDragAndDrop.this.inputManager.getCursorPosition();
                 final Vector3f click3d = TestDragAndDrop.this.cam.getWorldCoordinates(
                         new Vector2f(click2d.x, click2d.y), 0f).clone();
                 if (TestDragAndDrop.this.selectedGeom != null) {
                     click3d.z = TestDragAndDrop.this.selectedGeom.getLocalTranslation().clone().z;
                     TestDragAndDrop.this.selectedGeom.setLocalTranslation(click3d);
                 }
             }
         }
     }
    

    };

    protected Geometry makeCube(final String name, final float x, final float y, final float z) {
    final Box box = new Box(1, 1, 1);
    final Geometry cube = new Geometry(name, box);
    cube.setLocalTranslation(x, y, z);
    final Material mat1 = new Material(this.assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);
    mat1.setColor(“Color”, ColorRGBA.randomColor());
    cube.setMaterial(mat1);
    return cube;
    }

    protected Geometry makeFloor() {
    final Box box = new Box(15, .2f, 15);
    final Geometry floor = new Geometry(“the Floor”, box);
    floor.setLocalTranslation(0, -4, -5);
    final Material mat1 = new Material(this.assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);
    mat1.setColor(“Color”, ColorRGBA.Gray);
    floor.setMaterial(mat1);
    return floor;
    }

}
[/java]

What do you suppose the 0 means in this line of code?:
final Vector3f click3d = TestDragAndDrop.this.cam.getWorldCoordinates(
new Vector2f(click2d.x, click2d.y), 0f)

http://hub.jmonkeyengine.org/javadoc/com/jme3/renderer/Camera.html#getWorldCoordinates(com.jme3.math.Vector2f,%20float)

@pspeed

My understanding is that I should to pass projectionZPos value as follow:

[java]
final float viewZPos = TestDragAndDrop.this.selectedGeom.getWorldTranslation().clone().z;
final Vector3f click3d = TestDragAndDrop.this.cam.getWorldCoordinates(
new Vector2f(click2d.x, click2d.y),
TestDragAndDrop.this.cam.getViewToProjectionZ(viewZPos)).clone();

[/java]
But that didn’t fix the problem.
Sorry, I don’t understand how to convert from screen coord to view coord. I will need to read more about that.

It’s the depth. So you’d have to calculate the distance of the 3D point along the view vector. Dot product is your friend.

Note: Lemur already has code for dragging if you just wanted to look at that. It’s DragHandler math is just straight JME.

1 Like

@pspeed

I looked for code example on sdk code but I didn’t find it. That was before your reply.
Then I took a look to DragHamdler (as you suggested and I was able to solve my problem. Thanks!!

PS: something is wrong with quote post functionality!!! It does not let me reply using Quote button. Don’t know why!