Dragging objects with the mouse?

Hi,



I would like to have mouse control so that I can drag objects (like boxes) around by grabing them with the mouse. I only need to have movement in a 2D plane, since I won't allow movement in the third direction. The reason I want to do this is that I'm trying to build a 3D modeling tool, and I need to have some kind of drag function. Anyone have any good ideas to how this can be implemented?



I'm new to jMonkey but I have been working at least a bit in OpenGL before using C and Nvideas shaders.



I would be glad if someone could help me out! :slight_smile:

I have at least figured out how I want to do it, I will do it like other 3D modeling programs like Maya and Blender, if I want to translate something, tre arrows comes up, one for each axis. If you drag one of the arrows the object will only move along the selected axis.



Now, the problem is that I don't really know how to know how much I should move the object. I would like some way to approximate how long I have dragged the mouse between pressing and then releasing the mouse button. I can do it with screen coordinates, but I want the distance in OpenGL.



Sure I could just scale the distance so that it would be a reasonable distance to move the object, but since it's possible to move around the camera I would also have to include the distance to the camera in the calculation… there must be some better way right?



I can't use raycastning either, as you do when you check which object  you click with the mouse, since when you release the mouse you doesn't neccissary point on an object.



I include a picture of how movement of a box looks like for the moment (even though the moving part isn't working correctly…)



anyone has any good ideas about this?

I think you first need to set up a measuring system in your scene, as you definitely need a grid to work on…  The camera moves in Maya, Blender, etc, which usually scales the ‘speed’ of the move accordingly, but there’s an underlying grid that can visually represent what has been moved. (so yes, distance from camera would be important) OR distance from grid…  if two objects are different distances from the camera, should they move in the same order of magnitude?



That said, check out the new com.jme.scene.measure package :slight_smile:

sbook said:

I think you first need to set up a measuring system in your scene, as you definitely need a grid to work on...  The camera moves in Maya, Blender, etc, which usually scales the 'speed' of the move accordingly, but there's an underlying grid that can visually represent what has been moved. (so yes, distance from camera would be important) OR distance from grid....  if two objects are different distances from the camera, should they move in the same order of magnitude?

That said, check out the new com.jme.scene.measure package :)


yeah, I've been thinking about a grid too, I'm not quite sure how to implement it though, I guess there's no built in functionallty in JME that I can use for this?

because what I can see the measure package only contains different lengthtypes (like meter, centimeter and so on) and functionality to convert between these?

I found a guide where they use this technique http://www.ziggyware.com/readarticle.php?article_id=189 , but they use C#/XNA which apperently seems to have some built in function for this.

when it comes to the distance from the camera and the magnitude of the move it would be nice to have "larger" moves when the objects are far away so it scales nicely, but it's not neccissary at this point. The most important know it to get the objects to move in a good way, since this is only a prototype at this stage.

I have an additional question about the way I'm implementing it now (which might be a bit easier to answer), and that is why I can't get it to move correctly. At the moment I check for the mouseposition for when I start do drag the object, and then check the mouse position again when I've stopped moving the object. I then translate the object with the difference in (if I move along the x-axis) the x value of the mouse postition.



I get the mouse position by the following:


 
Vector2f screenPos = new Vector2f();
screenPos.set(mouse.getHotSpotPosition().x, mouse.getHotSpotPosition().y);

Vector3f world1 = display.getWorldCoordinates(screenPos, 0);
Vector3f world2 = display.getWorldCoordinates(screenPos, 1);

Ray ray = new Ray(world1, world2.subtractLocal(world1).normalizeLocal());

Vector3f newPos = ray.getOrigin();



The problem is that it doesn't move as I think it should. if I drag several times (all the time in the same direction and with about the same length of the drag) it firstly moves very different lengths (it should move apporiximatly the same) and secondly it after a few drags changes the direction and goes bakwards!! Apperantly I must have missinterpreted something, because from how I have understood how this should work that backwardmovement should be impossible!!

this problem would probably still exist, even if I implement the above mentioned grid....

Anyone have an idea of what the problem could be?

Edit: I have realized why this doesn't work anyway, ray.getOrigin() will give me the position of the camera... But I don't know how to do it instead...

new update on the problem… I've almost got a good solution now, I'm currently using the "Closest Point of Approach", which means that I send out a ray from the mouse and then I find the closest point on, for an example the x-axis. Then I get two points on the x axis (one before the move, one after) and I then move the object by the difference between them.



Unfortunatly a new problem arose. If I get to far away with the object from the origin of the cooridinatesystem (and not close to any axis) the movement becomes strange and can sometimes move the object in the wrong direction. This happens because I do not compensate for the distance to the coordinatesystem.



The easiest way to solve this would be if I could use a local coordinatesystem (not the one called local in JME) which always has it's origin in the objects position (and maybe from there transform it to the ordinary coordinatesystem). Is this possible in JME? Or does anyone have an idea how to implement this?

Regarding the grid:



http://www.jmonkeyengine.com/wiki/doku.php?id=axis_and_grids


tnx for the grid link!



I solved the problem now. The solution I had was good, I just did a little mistake when implementing it.



I do wonder one thing though that seems a bit strange, how can the color be "destroyed" temporarly on objects? I use no lightning and solid colors. See example below. The first one looks as it should, but the second one is the exact same object during the same run after I changed the camera angle a bit… That shouldn't happen right?

I just realized that my solution isn't good until I know how to find out at which point a raycast intersects an object (in this case a jme arrow), is it possible to do this in some way? I think it must be, would be strange otherwise, but I can't find any function which can do that. The ray class can only do this with triangles… Maybe it's possible to get the triangle representation of an object? I can't find any function for this either, am I missing something?



At least it should be possible to do down at the LWJGL level?

you can get a TriMesh represented as an array of triangles by calling getMeshAsTrianlges on the TriMesh…

okay, that is what I would need, but can I convert for example an Arrow to a TriMesh?

as in the jme primitive Arrow class?

that arrow class is made up of a cylinder and a pyramid as far as i can remember…

so you would have to check your ray against both of these tri meshes…

yes, that's true, I tried to convert Arrow to TriMesh :slight_smile:



Strangly it doesn't find any intersections… I'll post the code. This is after it have found the arrow (or one of the parts of it):



TriMesh t = (TriMesh) pick.getPickData(i).getTargetMesh();

Triangle[] triangleArray = t.getMeshAsTriangles(null);
axisStart = null;
for (int j = 0; j < triangleArray.length; j++) {
       Triangle triangle = triangleArray[j];
       if (mouseRay.intersectWhere(triangle, axisStart)) {
            break;
       }

}

now I tried another use of TriMesh, but the problem is that I don't know exactly what it is I'm getting out from findTrianglePick. It's claiming in the doc that it returns the indices to the triangles, but since there's only two numbers in the returned array that's not possible… I'm guessing that it is the indexes in the triMesh of the triangles the ray hits?



I get out only two integers when I test against a cylinder, which would make sense, the ray passes one triangle into the cylinder and one out.



But the way I've done it bellow doesn't seem to generate the result I want… and I also found it a bit strange that the original cylinder didn't have the same WorldTranslation as the TriMesh it was cast to… Should it be like that?



TriMesh t = (TriMesh) pick.getPickData(i).getTargetMesh();

Triangle[] triangleArray = t.getMeshAsTriangles(null);
ArrayList<Integer> test = new ArrayList<Integer>();
t.findTrianglePick(mouseRay, test);
Vector3f[] vertices = new Vector3f[3];
t.getTriangle(test.get(0), vertices);

axisStart = vertices[0];