Constant speed for dragging of 3D objects by mouse

Started by
12 comments, last by Endurion 8 years, 8 months ago

I am implementing dragging 3D object by mouse in my engine.

I have the following formulas:

1. I get length of the vector from camera to object

2. Calculate angles like FOV/width (for X axis) * mouseDelta.X

3. Find triangle side length like var x = Math.Tan(angleX)*distance;

4. multiply X *= frame time;

So, I receive the length in the 3D world space on which I must move the model.

Then I multiply my camera relative X and Y axis on those final values (X and Y) and add to the current position.

And it seems working for fps 300.

But when I set 60 fps, my gametime increases and object become moving much faster.

My goal is to make my dragging algorithm fps independent and move all objects with constant speed.

Does anyone know how to reach that?

Advertisement

Maybe the frametime is incorrect, Can you post your original code, and also tell us what frametime values you get from the debugger at both high and normal FPS?

My frame time is correct. I am sure. for 220 fps its - 0.004, for 60 fps - 0.016. Si, its logic that multiply the same value on different frametime will give me different results and in the second case result will be bigger.

Frame time shouldn't be used here at all?

Unless you want to push the object which would then be going on its way all by itself the object should simply be placed under the current location of the mouse.

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

Here is my calculations:


//Distance - distance to object (length of the vector (offset - absolute position))
               var distance = SelectedEntity.GetDistanceToCamera(cameraController.UserControlledCamera.Offset).Length();
               //angle of the triangle = (FOVx / width of the screen) * mouse offset for X axis
               var angleX = (cameraController.UserControlledCamera.Fov/cameraController.UserControlledCamera.Width)*
                           (totalDelta.X* (float)GameTime.FrameTime);
               //angle of the triangle = (FOVy / width of the screen) * mouse offset for Y axis
               var angleY = (cameraController.UserControlledCamera.Fov / cameraController.UserControlledCamera.Height) *
                           (totalDelta.Y * (float)GameTime.FrameTime);
               //find shift for X axis
               var x = Math.Tan(angleX)*distance;
               //find shift for Y axis
               var y = Math.Tan(angleY)*distance;
               
               SelectedEntity.MoveRelX(right, (decimal)x  );
               SelectedEntity.MoveRelY(up, (decimal)-y);

My question is how to keep object exactly under the cursor? Because In my case they have big shift.

Maybe my calculations incorrect?

Try this:

Calc the ray from under the mouse pointer towards the object at the old position.

Define a plane parallel to the screen surface at the exact distance from screen to object.

Calc the ray from under the mouse pointer at the new position.

Place the object at the intersection between new ray and the plane.

With that method the object is always moved parallel to the current camera angle. You may want to define the plane differently to confine the object to some level specific area.

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

But result of intersection is in the screen coordinates. How I will translate them to my 3d world coordinates?

The actual result should be in 3d coordinates already. The key word is unproject, e.g. take the mouse screen coordinates and get the ray that one pixel represents in 3d space.

For SharpDX use this method: http://sharpdx.org/documentation/api/m-sharpdx-vector3-unproject

Unproject the screen coordinates twice, with z set to 0 and 1 respectively. This nets you two points in 3d space, defining a line/ray.

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

Ok, seems I implement this, but I see a serious issue regarding intersection point.

I dont know why, but in some places (mostly near the edges of directX window) plane intersection check gives floating results for the same coordinates.

And this causing objects jump from one position to another.

Maybe My implementation is not correct. Could you just take a look on it?


var ray2 = CalculateRay(MouseManager.RelativeCoordinates, cameraController.UserControlledCamera,
                   SelectedEntity.GetActualMatrix());
               Plane p = new Plane(cameraController.UserControlledCamera.ViewMatrix.Backward, Vector3.UnitZ);
               Vector3 position;
               var res = ray2.Intersects(ref p, out position);
               RenderSystem.D2DText += "Distance to plane = " + SelectedEntity.GetRelativePosition() + "\n";
               RenderSystem.D2DText += "Intersection with plane = " +res+"\n";
               RenderSystem.D2DText += "Point = " + position + "\n";
               if (res)
               {
                  startPoint.X += (decimal)position.X;
                  startPoint.Y += (decimal)position.Y;
                  SelectedEntity.SetPosition(startPoint);

               }

I not set plane to the distance to the object bacuse in that case object not synced with the mouse cursor. And jump are much more bigger at that case.

When plane at the same distance as the object, it also give me diferent (in most cases opposite) results from frame to frame. For ex, X = 4000 and at the next frame it will be -4000. This leads to visual effect when seems that object is in 2 different places at the same time.

I suspect that I do something wrong with plane.

Shouldn't that be

startPoint.x = (decimal)position.X;
startPoint.y = (decimal)position.Y;

?

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

This topic is closed to new replies.

Advertisement