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
0
Question by IsaiahKelly · Jan 01, 2014 at 06:27 PM · quaterniondirectionangleoffsetrelative

Relative rotation offset?

This script rotates a rigidbody's transform.up to look at the mouse position on click, but the problem is I want it to only rotate relative to the current rotation when dragging the mouse, instead of rotating the transform.up to aim directly at it. How can I do this?

 using UnityEngine;
 using System.Collections;
 
 public class RotateTowards : MonoBehaviour 
 {
     public float smoothing = 0.3f;
     
     private Camera mainCamera;
     private Vector3 targetDir;
     
     void Awake () 
     {
         targetDir = Vector3.zero;
         mainCamera = Camera.main;
     }
     
     void Update () 
     {
         Ray ray = mainCamera.ScreenPointToRay (Input.mousePosition);
         Vector3 mousePosition = ray.origin + (ray.direction * 10);
         targetDir = (mousePosition - transform.position);        
     }
     
     void FixedUpdate () 
     {
         if (Input.GetMouseButton(0))
         {
             if (targetDir == Vector3.zero) 
             {
                 rigidbody.angularVelocity = Vector3.zero;
             }
             else
             {
                 float angularSpeed = AngleAroundAxis (transform.up, targetDir, Vector3.forward);
                 rigidbody.angularVelocity = (Vector3.forward * angularSpeed * smoothing);
             }
         }
     }
     
     static float AngleAroundAxis (Vector3 dirA, Vector3 dirB, Vector3 axis) 
     {
         dirA = dirA - Vector3.Project (dirA, axis);
         dirB = dirB - Vector3.Project (dirB, axis);
         float angle = Vector3.Angle (dirA, dirB);
         return angle * (Vector3.Dot (axis, Vector3.Cross (dirA, dirB)) < 0 ? -1 : 1);
     }
 
 }
 
Comment
Add comment · Show 2
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 robertbu · Jan 01, 2014 at 07:07 PM 1
Share

I'm unclear about your question. Right now this code uses 'Input.Get$$anonymous$$ouseButton(0)' which is true for every frame the mouse button held down. Are you saying you want it to delay rotation until the mouse is moved...to not move if the button is just clicked?

avatar image IsaiahKelly · Jan 01, 2014 at 10:07 PM 0
Share

Sorry for not explaining it properly.

I don't want the transform.up to snap to the target direction when clicking. I only want to add to the current rotation while dragging the mouse. Hope that makes sense.

2 Replies

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

Answer by IsaiahKelly · Jan 02, 2014 at 10:12 PM

Here's how I solved my problem thanks to Robertbu's example code.

I could only get it to work correctly by placing most of the code in Update() and just using FixedUpdate() to apply the velocity changes. This seems to work perfectly, but please let me know if you think there's a better way.

 using UnityEngine;
 using System.Collections;
 
 public class RotateTowards : MonoBehaviour
 {
     public float smoothing = 0.3f;
     
     private Camera mainCamera;
     private Vector3 targetDir;
     private Quaternion offset;
     private float angularSpeed;
 
     void Awake ()
     {
         mainCamera = Camera.main;
     }
 
     void Update ()
     {
         if (Input.GetMouseButtonDown(0)) 
         {
             rigidbody.angularVelocity = Vector3.zero;
             targetDir = MouseDirection();
             offset = Quaternion.FromToRotation (transform.up, targetDir);
         }
 
         if (Input.GetMouseButton(0))
         {
             targetDir = MouseDirection();
             angularSpeed = AngleAroundAxis (offset * transform.up, targetDir, Vector3.forward);
         }
     }
 
     void FixedUpdate ()
     {
         if (Input.GetMouseButton(0))
             rigidbody.angularVelocity = (Vector3.forward * angularSpeed * smoothing);
     }
     
     static float AngleAroundAxis (Vector3 dirA, Vector3 dirB, Vector3 axis)
     {
         dirA = dirA - Vector3.Project (dirA, axis);
         dirB = dirB - Vector3.Project (dirB, axis);
         float angle = Vector3.Angle (dirA, dirB);
         return angle * (Vector3.Dot (axis, Vector3.Cross (dirA, dirB)) < 0 ? -1 : 1);
     }
 
     Vector3 MouseDirection ()
     {
         Vector3 mousePos = new Vector3 (Input.mousePosition.x, Input.mousePosition.y, 10.0f);
         Vector3 mouseWorldPos = mainCamera.ScreenToWorldPoint (mousePos);
         Vector3 dir = mouseWorldPos - transform.position;
         return dir;
     }
 }


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 robertbu · Jan 03, 2014 at 12:09 AM 1
Share

If your changes work for you, I see nothing wrong with them. I played for awhile and could not reproduce the problems you outlined in the original code, but in theory it is possible that a fixed update misses the frame when the mouse button goes down so that the rotation does not get set. If this is the problem, then your rewrite should solve it. Note I reiterate the restrictions on how this code is currently written:

  • The camera must have rotation of (0,0,0).

  • The distance 'z' distance between the camera and the subject must be exactly 10 units.

The are alternate solutions if your app cannot live within these restrictions.

avatar image
0

Answer by robertbu · Jan 01, 2014 at 11:34 PM

I think this is what you want. At the top of the file:

 private Vector3 downPos;

Add to FixedUpdate():

 if (Input.GetMouseButtonDown(0)) {
     downPos = Input.mousePosition;
 }

Then modify line 26:

   if (Input.GetMouseButton(0) && Vector3.Distance(downPos, Input.mousePosition) > threshold) {

'threshold' is some small value like 3. And if you are targeting multiple platforms, then you may want to calculate 'threshold' based on Screen.dpi.

The idea here is that the mouse has to be some small distance from where it was first clicked before it starts tracking. There is one hole in this logic that I don't think matters in practice. If the user drags away form 'downPos' and then drags back to 'downPos', it will stop trying to rotate the object while the position is very near 'downPos'. If this becomes a problem, it is easy to fix.

Comment
Add comment · Show 6 · 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 IsaiahKelly · Jan 02, 2014 at 03:20 AM 0
Share

I really appreciate your help, but I guess I'm still not explaining it right. Very sorry about that.

$$anonymous$$y problem is not with mouse input, but what happens after. Essentially, I'm trying to use the mouse to grab/spin the rigidbody relative to it's current rotation. The problem is with this part:

 float angularSpeed = AngleAroundAxis (transform.up, targetDir, Vector3.forward);

This rotates the transform.up to the targetDir and means that if the transform.up is ai$$anonymous$$g to the right and I click to the left, it will rotate 180 degrees. I don't want that. I want it to keep it's current rotation when I click and only add to it as the targetDir (mouse position) changes when holding the mouse down.

I think I need to apply some kind of angle offset to accomplish this. I can get the angle differences with something like:

     if (Input.Get$$anonymous$$ouseButtonDown(0))
     {
         angleOffset = Vector3.Angle (transform.up, targetDir);
     }

But I have no idea how to apply this as an offset. :(

avatar image robertbu · Jan 02, 2014 at 07:00 AM 1
Share

Your calculation of an angle offset the way you indicate won't work, mostly because Vector3.Angle() returns an unsigned value. Below is a script that I think is what you want. Note this script assumes that the camera is 1) axes aligned, 2) facing positive 'z', and 3) the camera's 'z' coordinate is 10 units away from the objects 'z' coordinate.

 using UnityEngine;
 using System.Collections;
 
 public class RotateTowards : $$anonymous$$onoBehaviour 
 {
     public float smoothing = 0.3f;
     
     private Camera mainCamera;
     private Vector3 targetDir;
     private Quaternion q;
 
     void Awake () 
     {
         targetDir = Vector3.zero;
         mainCamera = Camera.main;
     }
 
     void FixedUpdate () 
     {    if (Input.Get$$anonymous$$ouseButtonDown (0)) {
 
             Vector3 pos = new Vector3(Input.mousePosition.x, Input.mousePosition.y, 10.0f);
             pos = mainCamera.ScreenToWorldPoint(pos);
             targetDir = pos - transform.position;
 
             q = Quaternion.FromToRotation (transform.up, targetDir);
         }
         if (Input.Get$$anonymous$$ouseButton(0))
         {
             Vector3 pos = new Vector3(Input.mousePosition.x, Input.mousePosition.y, 10.0f);
             pos = mainCamera.ScreenToWorldPoint(pos);
             targetDir = pos - transform.position;
 
             if (targetDir == Vector3.zero) 
             {
                 rigidbody.angularVelocity = Vector3.zero;
             }
             else
             {
                 float angularSpeed = AngleAroundAxis (q * transform.up, targetDir, Vector3.forward);
                 rigidbody.angularVelocity = (Vector3.forward * angularSpeed * smoothing);
             }
         }
     }
     
     static float AngleAroundAxis (Vector3 dirA, Vector3 dirB, Vector3 axis) 
     {
         dirA = dirA - Vector3.Project (dirA, axis);
         dirB = dirB - Vector3.Project (dirB, axis);
         float angle = Vector3.Angle (dirA, dirB);
         return angle * (Vector3.Dot (axis, Vector3.Cross (dirA, dirB)) < 0 ? -1 : 1);
     }
 }


I also redid how the mouse position is converted from screen to world coordinates. Note when you create a ray with Camera.ScreenPointToRay(), the origin starts at the near clip plane, not the camera origin. Plus I don't like that the calculation was done 1) every frame even when the mouse was held down, and 2) was done in Update() (which has a different frame rate than FixedUpdate()).

avatar image IsaiahKelly · Jan 02, 2014 at 07:33 PM 0
Share

Thanks! This is almost exactly what I want, but there's something wrong with the offset calculation. Sometimes it follows the mouse from the current offset correctly, other times it rotates to the mouse on click etc.

avatar image IsaiahKelly · Jan 02, 2014 at 08:50 PM 0
Share

Okay. I think the problem might be with the applied angular velocity and not the offset calculation. The AngleAroundAxis function seems to be adding force when it shouldn't. I tried setting angular velocity to zero on mouse down, but that didn't help.

avatar image IsaiahKelly · Jan 02, 2014 at 09:12 PM 0
Share

Hmm.. Changing FixedUpdate to Update solves the problem, but I know this is the wrong place to update physics objects.

Show more comments

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

18 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 avatar image avatar image avatar image avatar image avatar image

Related Questions

How to do relativte offset rotation 0 Answers

Need to know euler angles of Vector3 direction relative to other Vector3 direction 1 Answer

Location in relation to other objects rotation 1 Answer

Raycast across angle? 3 Answers

reproducing hingejoint.angle 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