Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
2 captures
12 Jun 22 - 14 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
1
Question by oliver344 · Jul 10, 2011 at 09:07 PM · rotationangleeulerangleslocallimit

Limit local rotation

Hi,

i have an issue i am not able to resolve myself. I have looked around topics here, but i couldnt find exactly what i am looking for.

I have an object, which is rotating around its axis, i.e. its orbiting on place. But i need to limit the rotation when it stops. So it means the object can have local y rotation anything between 0 and 360. Lets say its current y rotation is 100. I need to limit in +/- 40 interval. I.e. 60 - 140. Thats not problem, i am clamping it using eulerAngle.y. But when the current rotation is for example 20, then the issue comes up as it the interval is -20 to 60. Which causes issues as the rotation is only 0 - 360. So when the current rotation gets to this break point, whole limit code brakes and it does some funky stuff. Is there anyway how to prevent it from going in 0-360 interval and have negative values for rotation ? Or any other solution ?

Thanks a lot for any reply.

Luke

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 Waz · Jul 10, 2011 at 09:16 PM 0
Share

This is really just a coding question, so you should post your code.

avatar image mikii123 · Jun 15, 2016 at 06:31 PM 0
Share

Hi! Good news everyone! I'm using Unity 5.3.4 and there's no need for any angle conversion or special clamping. Quaternion.Euler() takes care of it. And it understands negative angles. So you just say $$anonymous$$athf.Clamp(angle, $$anonymous$$, max) and you're done. Have a nice day!

6 Replies

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

Answer by aldonaletto · Jul 11, 2011 at 04:50 AM

This is really a big problem: the limits below 0 and above 360 can't become negative or higher than 360; to further complicate matters, if you rotate the object past 359, it returns to 0; if you rotate the object below 0, it returns to 359. But I created a function similar to Mathf.Clamp which I think may solve your problem:

 function ClampAngle(angle: float, min: float, max: float): float {
 
     if (angle<90 || angle>270){       // if angle in the critic region...
         if (angle>180) angle -= 360;  // convert all angles to -180..+180
         if (max>180) max -= 360;
         if (min>180) min -= 360;
     }    
     angle = Mathf.Clamp(angle, min, max);
     if (angle<0) angle += 360;  // if angle negative, convert to 0..360
     return angle;
 }

This function has some limitations: it uses Mathf.Clamp if angle is in the range 90 to 270, and convert everything to the -180..+180 when angle is outside this range. In any case, the result is converted to 0..360 (the range eulerAngles accepts).
You can use it this way:

   transform.eulerAngles = Vector3(0, ClampAngle(angle, ang0-40, ang0+40), 0);
Comment
Add comment · Show 11 · 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 oliver344 · Jul 11, 2011 at 08:43 AM 0
Share

Amazing, works like charm. Thanks a lot.

avatar image aldonaletto · Jul 11, 2011 at 12:15 PM 0
Share

Please notice that this function has a "capture" range: if the parameter angle is between -90 and +90 degrees around the center of the range, it will be clamped correctly; if its out of this range, the function may "think" it is at the "other side" of the circle, and clamp to the wrong limit - for example: if the range is centered at 120 degrees, an angle lower than 270 will be clamped to 160 degrees, but above 270 it will be clamped to 80 degrees. This will not be a problem if you're clamping the angle returned by eulerAngles after a small rotation (what seems to be your case), since it will not be too away from the range. If you want to clamp an arbitrary angle to the limits, however, this problem may arise.

avatar image oliver344 · Jul 11, 2011 at 02:56 PM 0
Share

Iam having small rotation, so its not problem. I have tested it very intensly and it works very smoothly withouth any issue so far. So thanks a lot again :).

avatar image unitynewbie1 · Mar 21, 2012 at 05:38 PM 0
Share

I was trying to do something similar, but for clamping an arbitrary angle to the limits, so the problem that aldonaletto mentioned in his comment occurred. I started a new question thread about it here: http://answers.unity3d.com/questions/226639/limit-local-rotation-around-x-y-and-z-axes-when-ro.html

avatar image quainchris · Sep 09, 2017 at 03:07 PM 1
Share

I saw this been looking for ages for something good. This is absolutely brilliant work thanks very much

Show more comments
avatar image
1

Answer by mkgame · Apr 19, 2016 at 11:22 PM

The following code is stable for all angles. Both methods can be static. NormalizeAngle method fix the angles above 360 and under -360 degree and the ClampAngle method normalize the angles from -180 to 180 to make the angles clamp-able. You can call this method with e.g. ClampAngle(angle, 3450, -70), ClampAngle(angle, -70, 70), ClampAngle(angle, -470, 5604). Its stable! I used this code to limit the angles of my hover vehicle, to avoid turning around it.

    /** Normalize angles to a range from -180 to 180 an then clamp the angle
      * with min and max.
      */
     protected float ClampAngle(float angle, float min, float max) {
 
         angle = NormalizeAngle(angle);
         if (angle > 180) {
             angle -= 360;
         } else if (angle < -180) {
             angle += 360;
         }
 
         min = NormalizeAngle(min);
         if (min > 180) {
             min -= 360;
         } else if (min < -180) {
             min += 360;
         }
 
         max = NormalizeAngle(max);
         if (max > 180) {
             max -= 360;
         } else if (max < -180) {
             max += 360;
         }
 
         // Aim is, convert angles to -180 until 180.
         return Mathf.Clamp(angle, min, max);
     }
 
     /** If angles over 360 or under 360 degree, then normalize them.
      */
     protected float NormalizeAngle(float angle) {
         while (angle > 360)
             angle -= 360;
         while (angle < 0)
             angle += 360;
         return angle;
     }

Use it in your code to limit the angles:

 transform.eulerAngles = new Vector3(0, ClampAngle(angle, -40, 40), 0);

Or like this for fake tilt to terrain normal:

 // Raycat down to terrain, in my case the GameManager.TERRAIN_MASK is
 // the terrain mask.
 Vector3 linecastTo = new Vector3(transform.position.x, transform.position.y - 100, transform.position.z);
         Vector3 linecastFrom = new Vector3(transform.position.x, transform.position.y + 20, transform.position.z);
         bool hitSomewhat = Physics.Linecast(linecastFrom, linecastTo, out hitInfo, GameManager.TERRAIN_MASK);
 
  float SwingSpeed = 1;
  // Difference between our up vector and the terrain normal vector.
  Quaternion tilt = Quaternion.FromToRotation(transform.up, hitInfo.normal);
  Vector3 rot = transform.eulerAngles;
 // Rotation for the next frame until this value ClampAngle(tilt.eulerAngles.x, -30, 30) 
 // has been achieved. Max tilt is 30, even on a 45 degree terrain mesh normal!
 Quaternion qRot = Quaternion.Euler(
             Mathf.LerpAngle(rot.x,  ClampAngle(tilt.eulerAngles.x, -30, 30), 
                                           Time.deltaTime * SwingSpeed), 
             rot.y,
             Mathf.LerpAngle(rot.z, ClampAngle(tilt.eulerAngles.z, -30, 30), 
                                           Time.deltaTime * SwingSpeed));
         
     // RB is the rigidbody, smooth physical change because of the LerpAngle before.
     RB.MoveRotation(qRot);
 
 

Happy coding!

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 elhispano · Sep 05, 2016 at 06:31 PM 0
Share

mkgame. Seeing your code, i think you don't need to check for negative values after calling NormalizeAngle.

avatar image
0

Answer by immerhart · Oct 19, 2012 at 07:07 PM

its a little late, but here my approach:

   m_startRotation = transform.rotation.eulerAngles.y;
   m_minRot = m_startRotation - 90.0f;
   m_maxRot = m_startRotation + 90.0f;
   m_isTranslationNessecary = false;
 
   // check if rotation happens between 0/360
   if(m_minRot <= 0.0f)
    m_minRot += 360.0f;
 
   if(m_maxRot >= 360.0f)
    m_maxRot -= 360.0f;
 
   if(m_minRot > m_maxRot)
    m_isTranslationNessecary = true;

and this function checks if the obj can be rotated:

     private float ClampAngle(float angle, float min, float max, bool isTranslationNecessary)
     {
         if(!isTranslationNecessary)
         {
             if(angle < min )
                 return min;
 
             if(angle > max)
                 return max;
         }
         else
         {
             if(angle > max && angle < min)
             {
                 if(min - angle > angle - max)
                     return max;
                 else
                     return min;
             }
         }
 
         return angle;
     }
Comment
Add comment · 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
0

Answer by VictorPinto90 · Jun 13, 2015 at 04:13 PM

Here is my solution. I have a camera thar rotates around a target in X and Y axis. I'm only limiting the angle in X-Axis

 public void OnDrag (PointerEventData eventData){
         float deltaX = Mathf.Clamp(eventData.delta.x,-maxPointerDelta,maxPointerDelta)*Time.smoothDeltaTime*speed;
         float deltaY = Mathf.Clamp(eventData.delta.y,-maxPointerDelta,maxPointerDelta)*Time.smoothDeltaTime*speed;
         Vector3 relativePos = cameraTransform.position - handler.position;
         Vector3 v1 = new Vector3(relativePos.x,0,relativePos.z);
         float angleX = Vector3.Angle(v1,relativePos);
         float futureangle = angleX + -deltaY;
         if(futureangle<maxAngle && futureangle>minAngle){
             cameraTransform.RotateAround(target.position,cameraTransform.right,-deltaY);
         }
         cameraTransform.RotateAround(targer.position,Vector3.up,deltaX);
     }
Comment
Add comment · 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
0

Answer by rblkwa · Nov 22, 2016 at 02:38 PM

 public void SetRotation(float amount) {
     float clampedAngle = Mathf.Clamp(CheckAngle(transform.eulerAngles.x - amount), -15, 15);
     transform.eulerAngles = new Vector3(clampedAngle, transform.eulerAngles.y, transform.eulerAngles.z);
 }   
 
  public float CheckAngle(float value)
  {
         float angle = value - 180;
 
         if (angle > 0)
             return angle - 180;
 
         return angle + 180;
     }
Comment
Add comment · 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
  • 1
  • 2
  • ›

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

Limit local Rotations on one axis 3 Answers

Rotating Object on its Local World Axis 4 Answers

Limit Object Angle 2 Answers

How to use Euler angles to rotate an object ? 5 Answers

Problems caused by non-unique Euler angle solutions 1 Answer


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