Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 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 bmc85uk · Mar 02, 2020 at 03:53 PM · rotationsrotation detection

Rotation snapping overshooting on certain rotations.

Hi, I've been trying to get a function working to snap rotation of a block on each axis to increments of 90 degrees. The problem I've been having is that, no matter how I seem to approach applying rotation, I get slight miscalculations at certain rotations.

The code:

     void RotateBlock()
     {
         if (buildMode == BuildMode.Active)
             if (!IsACube())
             {
                 float xAngle = 0;
                 float yAngle = 0;
                 float zAngle = 0;
 
                 if (Input.GetKeyDown(KeyCode.G))
                     xAngle = 90f;
 
                 if (Input.GetKeyDown(KeyCode.R))
                     yAngle = 90f;
 
                 if (Input.GetKeyDown(KeyCode.F))
                     zAngle = 90f;
 
                 if (mirrorMode == MirrorMode.Inactive)
                 {
                     tempBlock1.transform.Rotate(
                         Mathf.RoundToInt(xAngle),
                         Mathf.RoundToInt(yAngle),
                         Mathf.RoundToInt(zAngle),
                         Space.World);
                 }
 
                 else
                 {
                     tempBlock1.transform.Rotate(
                         Mathf.RoundToInt(xAngle),
                         Mathf.RoundToInt(yAngle),
                         Mathf.RoundToInt(zAngle), 
                         Space.World);
 
                     tempBlock2.transform.Rotate(
                         Mathf.RoundToInt(xAngle),
                         Mathf.RoundToInt(-yAngle),
                         Mathf.RoundToInt(-zAngle), 
                         Space.World);
                 }
             }
         else return;
     }

On -90 and +90 rotations for each axis, I'm getting a deviation of -/+ 0.00001 which is causing me problems elsewhere because I need to be able to check an object's rotation against a vector. I'm also getting a weird assignment (-1.525879e-05) to the Y and Z axes every other time the X rotation snaps to -180.

I'm sure I'm just doing something stupid, but I'm at a loss as to what. Any help would be hugely appreciated. For the record, I've tried each of the angles being an int, rounding the rotational assignment with Mathf.Round, Mathf.RoundToInt, or without any rounding at all.

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 bmc85uk · Mar 02, 2020 at 03:57 PM 0
Share

Another odd thing I noticed, when these blocks are reinstantiated from the save file and the rotation is assigned from an explicitly declared Quaternion.Euler, the same behaviours seem to be happening.

1 Reply

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

Answer by unity_ek98vnTRplGj8Q · Mar 02, 2020 at 04:40 PM

Ah yes floating point approximation strikes yet again... TLDR: positions and rotations in Unity cannot be reliably set and read due to the fact that floating point numbers cannot exactly express many fractions. In reality you are just going to have to deal with it, but usually there is a pretty simply workaround depending on your application. If you give me more information on why you need to check the rotation angles or why you need to check them against a vector I can help out with that, but generally doing things like if (rotation.eulerAngles.y == 90) is bad practice.


The reason these errors happen is because floating point numbers use base 2, and not all simple base 10 numbers can be expressed simply in base 2. Just like how 1/3 cannot be expressed in a finite number of decimal places in base 10, similar things happen in base 2 when trying to express some simple fractions. The solution is just to go out to as many decimal places as will fit into a float and dropping anything after that. This results in values that are extremely close to the desired value but not exact. This is often only really an issue with fractions, as generally you don't get large enough integers to break down floating point precision. But even when rotating by small integers, like 90 degrees, you will still get issues as Unity converts these angles into a Quaternion, and the internal values in a quaternion are usually small fractions resulting in some floating point error. There are two common solutions to this kind of issue:
1. You can keep track of the "desired" rotation yourself, instead of reading it from the objects rotation directly. That way you know your "desired" rotation is exactly 90 degrees, while you actual rotation is very very very close to 90 degrees.
2. You can allow for a small degree of error. Instead of checking if the rotation is exactly 90 degrees, you can check if the rotation is 90 degrees +- 0.001 degrees

Comment
Add comment · Show 7 · 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 bmc85uk · Mar 02, 2020 at 05:03 PM 0
Share

Thinking about it, I actually have the rotations stored as an enum for use in the array, I really should have just been checking against that the whole time.

avatar image bmc85uk · Mar 02, 2020 at 05:11 PM 0
Share

For some reason my previous reply was deleted, which is frustrating.

I'll try to be more brief this time. I have turrets that can be placed in various orientations that snap to said 90° increments. The turrets track a ray hit point and rotate their bodies around the local Y axis and their barrels on the barrels local X axis.

I was trying to get the orientation of the turret so I could restrict rotation on the relevant axes.

I essentially did exactly what you said was bad practice.

Thanks for the explanation, you've been a huge help :)

avatar image bmc85uk · Mar 03, 2020 at 12:08 AM 0
Share

Ah, this makes a lot of sense. Thanks for the explanation.

What I have are turrets that can be placed by the user (in any 90° snapped orientation) that will track a ray from the camera. The turrets rotate a main body around their local Y axis and pitch the main part of the weapon around the local X axis (I'm actually still trying to get the main rotation working before I even touch the pitch on the X axis).

I was trying to find a quick and dirty way (I'm very new to this, I accept a lot of my code is probably doing things in the wrong way) to check the orientation of the turret so that I know which axis to ignore when rotating towards the ray point.

I hope I haven't missed anything relevant here. Let me know if so.

This is the code, apologies in advance, I can see I've done exactly what you said was bad practice!

     private void RotateBase(int index)
     {
         Vector3 aimPoint = hitInfo.point;
 
         Vector3 targetDirection = aimPoint - weaponPlatform[index].transform.position;
         if (weaponPlatform[index].transform.up == Vector3.up || weaponPlatform[index].transform.up == Vector3.down) targetDirection.y = 0.0f;
         else if (weaponPlatform[index].transform.up == Vector3.left || weaponPlatform[index].transform.up == Vector3.right) targetDirection.x = 0.0f;
         else if (weaponPlatform[index].transform.up == Vector3.forward || weaponPlatform[index].transform.up == Vector3.back) targetDirection.z = 0.0f;
 
         Quaternion rotationGoal = Quaternion.LookRotation(targetDirection);
 
         Vector3 temp = weaponPlatform[index].transform.rotation.eulerAngles;
         temp.y = rotationGoal.eulerAngles.y;
         rotationGoal.eulerAngles = temp;
 
         weaponInfo.text = $"Target position: {aimPoint} \n" +
                           $"Weapon position {weaponPlatform[index].transform.position} \n" +
                           $"Target direction: {targetDirection} \n" +
                           $"Current rotation: {weaponPlatform[index].transform.rotation.eulerAngles} \n" +
                           $"Desired rotation: {rotationGoal.eulerAngles}";
 
         Quaternion newRotation = Quaternion.RotateTowards(weaponPlatform[index].transform.rotation, rotationGoal, turnRate);
 
         weaponPlatform[index].transform.rotation = newRotation;
     }

avatar image unity_ek98vnTRplGj8Q bmc85uk · Mar 03, 2020 at 04:16 PM 0
Share

Ok this actually isn't too bad of a way to do this, but yea you will run into problems with the vector comparisons. I think the cleanest way to do this is storing the orientation as an enum, especially if you already have this enum available like you mentioned. If you don't want to do this, then using dot product will clean up those if statements a little bit

 if($$anonymous$$athf.Abs(Vector3.Dot(weaponPlatform[index].transform.up, Vector3.up)) > 0.99f) targetDirection.y = 0;
 else if($$anonymous$$athf.Abs(Vector3.Dot(weaponPlatform[index].transform.up, Vector3.right)) > 0.99f) targetDirection.x = 0;
 else targetDirection.z = 0;

Also if you are getting weird rotations then I think change Quaternion.LookRotation(targetDirection) to Quaternion.LookRotation(targetDirection, weaponPlatform[index].transform.up)

avatar image unity_ek98vnTRplGj8Q unity_ek98vnTRplGj8Q · Mar 03, 2020 at 04:20 PM 0
Share

Oh and the 3 lines where you are messing with the eulerAngles seem like they could cause some issues, I'm not exactly sure what you are trying to do there but I can almost guarantee that this is not the correct way to do it.

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

121 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 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 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 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 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 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 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 Rotate 3D Object using Accelerometer? 1 Answer

rotation on instantiating 1 Answer

Bending an Armature with Programming 1 Answer

How can I rotate an object without moving it up or down? 0 Answers

Make a cube rotate exactly 90 degrees rather than keeping it rotating 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