Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
2
Question by IanT · Nov 28, 2012 at 09:15 PM · cameramathdraggeometryprojection

Grab'n drag camera? (or, a little geometry problem)

Hi!

I might not use the proper search keywords, but I haven't found any answer to this question: how to make an actual grab-and-drag camera – a camera that moves parallel to a plane (seen in perspective) in such a way that the point of the plane that was projected on cursor's location when the player pressed the mouse button, remains under cursor's location while the player holds the button and moves the mouse, like if the cursor was pinned onto the plane.

I've just read a recent post on the forums: it seems to ask a similar question but it's got no proper answer.

My code does the following:

  1. retrieve the proper plane's point from cursor's position on screen (using Camera.ViewportPointToRay and line-plane intersection)

  2. get the delta vector between this plane's point and the previous plane's point retrieved (from cursor's position on previous frame)

  3. translate the cam to the opposite of this delta vector.

I thought that way I would always get the right distance to move the camera (since it's moving parallel to the plane), whatever the distance of the plane's point from the camera... But I guess I was wrong since the cursor is still not "pinned" onto the plane (the result is not really better than on my "basic" version, when I translated the cam at an arbitrary constant speed and relative only to the cursor's movement)

There might be an additional step to translate the cam, instead of just using the opposite of the delta vector; but I don't know what operations/transformations, I am not good enough in solid geometry. Yet my case is rather simple: the plane is normal to the z axis, thus the cam translates on x,y only.

Can anyone answer this little solid geometry problem?

EDIT - SOLUTION (principle – for code plz see the answer I posted below):

I've just come up with the solution and I think other people might be interested:

My mistake was on step 2, when getting the "previous position" that I will substract from the position of the plane's point I retrieve from the cursor's position on the current frame:

One should not use the plane's point that was retrieved on the previous frame (corresponding to the cursor's position on the previous frame).

Instead, because the cam moves every frame, one must retrieve – on the current frame thus with the current cam position – the plane's point corresponding to the cursor's position on the previous frame.

Comment
Add comment · Show 1
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Next Beat Games · Jan 02, 2013 at 03:34 PM 0
Share

Hi Ian. Thank you for this post. Can you please post your coded solution to this issue? I have the exact same question.

2 Replies

· Add your reply
  • Sort: 
avatar image
3
Best Answer

Answer by IanT · Jan 04, 2013 at 10:48 AM

Next Beat Games asked for my coded solution hence it's cleaner that I post it as an answer:

Notes: My code spans over a few functions and global variables, so there are a few parameters you have to figure out from their names (explicit enough I think), and I can just hope it's clear enough when taken out of context. Note as well that it's not optimized as I use Unity's built-in projection methods instead of custom instructions on matrices that would probably save a lot of math operations. But at least it works! ^^

First you need a method to retrieve the point on the plane (in 3D space) from a viewport's point:

     Vector3 getPosOnPlane(Vector2 posOnViewport)
     {
         Vector3 pt = new Vector3(posOnViewport.x, posOnViewport.y, 0);
         Ray d = camera.ViewportPointToRay(pt);
         float t = (planePos.z - d.origin.z) / d.direction.z;
         float x = d.direction.x * t + d.origin.x;
         float y = d.direction.y * t + d.origin.y;
         return new Vector3(x, y, planePos.z);
     }
 

Then the method that updates camera's position target point:

     void computeTgtPt(Vector2 currPosOnScreen)
     {
         Vector3 inputPosOnPlane = getPosOnPlane(currPosOnScreen);
         Vector3 posOnPlaneFromPrevTouchPos = getPosOnPlane(prevTouchPos);
         Vector3 move = posOnPlaneFromPrevTouchPos - inputPosOnPlane;
         targetPt.x += move.x; //Note: targetPt is a global variable because it's initialized at camera's position at the begining of a touch
         targetPt.y += move.y;
     }
 

In Update() you call computeTgtPt(...) with touch or cursor position as parameter whenever a touch is in effect and moves. (Note: as I'm using viewport positions instead of screen positions so that it works in the editor as well, you might have to transform Input.mousePosition from screen coordinates into viewport coordinates.)

What I do then in Update() is to move the camera toward targetPt at a steady speed (and smooth/limit the movement as it gets close to its target). Plus I have added contextual momentum that I spared you as well for simplicity (To add momentum you may call computeTgtPt(..) with a virtual target point that takes it into account).

But if you want the plane to just appear sticked to the finger/cursor, I guess you can just set camera's position to targetPt.

Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Next Beat Games · Jan 06, 2013 at 08:36 PM 0
Share

hey quick question. where are you doing the raycast? I have been doing:

 ray = camera.ViewportPointToRay(touchPos)
 hits = Physics.RaycastAll(ray, RAY_DISTANCE);
avatar image IanT · Jan 07, 2013 at 10:30 AM 0
Share

Since my plane is virtual (just defined by planePos.z, which is an easy case) I don't need a raycast, I just return the point mathematically.

avatar image SacWebDeveloper · Jul 19, 2018 at 06:18 PM 1
Share

Thanks! This was a good starting point for me. I am making a timer/builder game for mobile and it seems there are 5 different interpretations of what "touch and drag camera" means. Now for the task of sorting through various interpretations of "pinch zoom." Hint: it doesn't involve using field of view!

One note though, you can get the point on the plane by plane.Raycast(ray, enter).

 Vector3 getPositionOnPlane(Vector2 posOnViewport)
 {
     Vector3 hitPoint = Vector3.zero;
     Vector3 pt = new Vector3(posOnViewport.x, posOnViewport.y, 0);
     Ray ray = Camera.main.ViewportPointToRay(pt);
 
     //Initialise the enter variable
     float enter = 0.0f;
     if (m_Plane.Raycast(ray, out enter))
     {
        //Get the point that is clicked
         hitPoint = ray.GetPoint(enter);
     }
     return hitPoint;
 }

Also,

I dampened the camera movement in LateUpdate with a lerp.

 private void LateUpdate()
 {
     Camera.main.transform.position = Vector3.Lerp(Camera.main.transform.position, cameraTarget, Time.deltaTime * dragSpeed);
 }

avatar image
0

Answer by darthbator · Nov 29, 2012 at 01:43 AM

I normally use the following code to manually drag my camera in touch based games.

 public void manualPan (Vector3 panDirection) {
         Debug.Log("panning");
         cameraTarget = null;
         panDirection.z *= 1.5f;
         panDirection = new Vector3(Mathf.Clamp(panDirection.x, panClamp[0], panClamp[1]), 0, Mathf.Clamp(panDirection.z, panClamp[0], panClamp[1]));
         transform.position += panDirection;
     }

I generally feed in the touch delta from a single finger touch (I am multiplying the z value due to the aspect ratio of the screen). You could surely use the same code and feed in ray hit locations or mouse cursor positions.

I should mention that my camera here has a fixed rotation so I do not need to rotate the vector of the panning direction or anything. The cameras rotation is fixed and it's Y value is controlled via pinching/pulling. Sounds like you might have it rotating freely in 3d space?

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image IanT · Nov 29, 2012 at 08:56 AM 0
Share

Thanks darthbador for the addition and the advice.

If I'm right your code translates the cam at a constant speed whatever the distance of the plane from mouse cursor position.

I thought as well about the trick you propose: to multiply the z panning (actually it's y in my case) according to mouse vertical position or to the distance of the plane from mouse cursor position.

However this would have required empirical adjustments to achieve the exact feeling that mouse cursor gets pinned onto a certain plane' spot – and never slides away from this spot.

It would have been empirical at least for me who don't understand matrix transform and don't master the transformation principle from cam local space to plane or world space: the multiplying factor would have depended on plane's distance from the cursor, cam tilt AND cam FOV...

With the algorithm that actually compares projections I could now zoom the cam (and yes, even tilting it, although it's not my purpose) without worrying about arbitrarily updating a multiplying factor. :)

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

13 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

How to scale/calculate GameObject Z distance to the real physical world... 0 Answers

Inverse projection vertex shader 0 Answers

How to project a point on to a sphere? 1 Answer

How to calculate a following camera with a restrain angle 0 Answers

Apply Projector-Realsense calibration to Unity3d Camera 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges