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 Bash Mills · Mar 17, 2014 at 07:20 PM · rotationquaternionrotate

Snapping Quaternion Rotations in Script

Hi. I have a bit of a problem concerning quaternions. In the game we're making, the player can position and rotate objects on all axes which is all done in script. But we want these positions and rotations to be snapped to certain increments (0.1 for movement and 5 for rotation). The movement is fine as can just do the good old:

 Vector3 position = SelectedObject.position;
 position.x = Mathf.Round(position.x / MovementIncrement) * MovementIncrement;
 position.y = Mathf.Round(position.y / MovementIncrement) * MovementIncrement;
 position.z = Mathf.Round(position.z / MovementIncrement) * MovementIncrement;
 SelectedObject.position = position;

But the rotations are being a bit more tricky to snap. I'm currently rotating the objects via:

 SelectedObject.Rotate(RotateIncrement * direction);

Where direction is a vector (Vector.up for example) that describes the axis to rotate around. This does kinda work but after running the game, playing with the rotations and then trying to put the object back to (0,0,0) the rotations are actually something like (1.567, 0.2345, -1.234) which are of course no longer multiples of five. I thought all I'd need to do is the same as the position snapping:

 Vector3 rotation = SelectedObject.eulerAngles;
 rotation.x = Mathf.Round(rotation.x / RotateIncrement) * RotateIncrement;
 rotation.y = Mathf.Round(rotation.y / RotateIncrement) * RotateIncrement;
 rotation.z = Mathf.Round(rotation.z / RotateIncrement) * RotateIncrement;
 SelectedObject.eulerAngles = rotation;

But this makes the rotations look very weird as they snap when they shouldn't due to the way Quaternions work and makes it look very jittery.

I tried using AngleAxis but this created the same problem as using just the Rotate function. I also tried storing and manipulating good old Eular vectors and then converting to quaternion after doing vector rotations but then this caused gimbal lock to happen.

Is there any way to snap quaternion rotations to multiples of 5 on all axes in script?

Comment
Add comment · Show 5
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 · Mar 17, 2014 at 07:46 PM 0
Share

I can you post the Input code you are using to do the rotation?

avatar image Bash Mills · Mar 17, 2014 at 07:55 PM 0
Share

There's nothing really special about the input code. There's literally just "Action" scripts on NGUI buttons that call a method passing through an enum. Then that function has a switch statement which calls a "DoRotation" method passing through the direction (Vecotr3.up, Vector3.right, etc) and the code in that function that is literally in the second bit of code I put up top.

avatar image Bash Mills · Mar 20, 2014 at 09:15 PM 0
Share

I've managed to get it somewhat working. I've resigned to the fact that I'm probably gonna have to use eular for storing and manipulating the rotation so that I can snap it as above. So now just trying to find a way to stop the gimbal lock happening. Using any of Unitys built in methods (Quaternion.Eular(), Rotate()) and passing in values all at once or individually seem to be failing. Any ideas?

avatar image Scribe · Mar 21, 2014 at 12:39 AM 0
Share

Check my answer! :)

avatar image Bash Mills · Mar 22, 2014 at 04:32 AM 0
Share

So after a lot of digging around it seems it really is impossible not to encounter gimbal lock when using Eular angles or when applying 3 separate quaternion rotations one after another. It literally has to be a single quaternion rotation to avoid gimbal lock. So it looks as if I do have to find a way to snap the quaternion (x,y,z,w) values while still keeping it normalized...

3 Replies

· Add your reply
  • Sort: 
avatar image
0

Answer by robertbu · Mar 17, 2014 at 08:07 PM

I'm not sure of what you need in terms of rotations, but try this script. Start with a new scene, add a cube, and add this script. While running, use the Arrow keys and the A/D keys for rotation.

 using UnityEngine;
 using System.Collections;
 
 public class Example : MonoBehaviour
 {
     private Vector3 vCurr = Vector3.zero;
 
     void Start() {
         transform.eulerAngles = vCurr;
     }
 
     void Update() {
         Vector3 vNext = vCurr;
 
         if (Input.GetKeyDown (KeyCode.UpArrow)) {
             vNext.x += 5.0f;
         }
 
         if (Input.GetKeyDown (KeyCode.DownArrow)) {
             vNext.x -= 5.0f;
         }
 
         if (Input.GetKeyDown (KeyCode.LeftArrow)) {
             vNext.y += 5.0f;
         }
         if (Input.GetKeyDown (KeyCode.RightArrow)) {
             vNext.y -= 5.0f;
         }
         if (Input.GetKeyDown (KeyCode.A)) {
             vNext.z += 5.0f;
         }
         if (Input.GetKeyDown (KeyCode.D)) {
             vNext.z -= 5.0f;
         }
 
         if (vNext != vCurr) {
             transform.eulerAngles = vNext;
             vCurr = vNext;
         }
     }
 }

Note that I never read Transform.eulerAngles. The rotation is always taken from my vCurr Vector3.

Comment
Add comment · Show 2 · 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 Bash Mills · Mar 17, 2014 at 08:17 PM 0
Share

But using vectors in this way causes gimbal lock no?

avatar image Bash Mills · Mar 17, 2014 at 08:35 PM 0
Share

Just tried it and it does indeed cause gimbal lock similar to what I'd tried before :(

avatar image
0

Answer by eightbitstev · Mar 17, 2014 at 10:30 PM

If I recall Quaternion math correctly, I believe multiplying them together is effectively what we would observe as adding them. Maybe try something like..

 transform.rotation *= Quaternion.Euler(new Vector3(RotateIncrement,0,0));

Since this way we're assigning the rotation as Quaternions instead of from Euler values, it might work better?

I could be totally off on this. It's been a while since I've dealt with rotations. I could also be completely misunderstanding your problem. I apologize in advance if either of these are the case! :)

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 Bash Mills · Mar 18, 2014 at 08:43 PM 0
Share

Unfortunately this methods creates the same problem as using the Rotate method (which I assume pretty much does this for you). It works fine for one axis rotation, but as soon as you start rotating all axes and then try to return to (0,0,0) the rotations are no longer multiple of five again. :(

avatar image
0

Answer by Scribe · Mar 21, 2014 at 12:38 AM

This should work hopefully, this is a slightly edited version of my answer here.

Just check the Update method on how to call my RotateAround function and then attach this to your object you want to rotate:

 private var targetAngle : Quaternion;
 private var startAngle : Quaternion;
  
 private var forward : Vector3;
 private var right : Vector3;
 private var up : Vector3;
 
 var increment : float = 5;
 var speed : float = 1.0;
  
 private var startTime : float;
  
 function RoundAngle(v : Quaternion) : Quaternion{
     var vE : Vector3 = v.eulerAngles;
     vE.x = Mathf.Round(vE.x/increment)*increment;
     vE.y = Mathf.Round(vE.y/increment)*increment;
     vE.z = Mathf.Round(vE.z/increment)*increment;
     v = Quaternion.Euler(vE);
     return v;
 }
 
 function RotateAround(vF : Vector3, vR : Vector3, vU : Vector3, axis: Vector3, angle: float) : Quaternion{
     var rot: Quaternion = Quaternion.AngleAxis(angle, axis); // get the desired rotation
     forward = (rot*vF);
     right = (rot*vR);
     up = (rot*vU);
 
     startTime = Time.time;
     startAngle = transform.rotation;
     targetAngle = RoundAngle(rot * targetAngle);
 }
 
 function Start(){
     startAngle = transform.rotation;
     targetAngle = startAngle;
     forward = (transform.forward);
     right = (transform.right);
     up = (transform.up);
 }
 
 function Update () {
     if(Input.GetKeyDown(KeyCode.RightArrow)){
         RotateAround(forward, right, up, Vector3.up, -increment);
     }else if(Input.GetKeyDown(KeyCode.LeftArrow)){
         RotateAround(forward, right, up, Vector3.up, increment);
     }
     if(Input.GetKeyDown(KeyCode.UpArrow)){
         RotateAround(forward, right, up, Vector3.right, increment);
     }else if(Input.GetKeyDown(KeyCode.DownArrow)){
         RotateAround(forward, right, up, Vector3.right, -increment);
     }
     transform.rotation = Quaternion.Slerp(startAngle, targetAngle, (Time.time-startTime)/speed);
 }

Hope that does what you want, it seems to work for me, you can change 'increment' to whatever angle (in degrees) you want to snap to, and you can change speed to snap to the angle faster (measured in seconds, currently it will take 1 second to snap).

Scribe

Comment
Add comment · Show 4 · 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 Bash Mills · Mar 21, 2014 at 07:02 PM 0
Share

Unfortunately this hasn't worked either :(

avatar image Scribe · Mar 21, 2014 at 09:40 PM 0
Share

Are you having the same problem as before? Ive tested this and it seems to work for me :/

avatar image Bash Mills · Mar 22, 2014 at 04:30 AM 0
Share

This gives similar results to what I originally did. Do quaternion rotations and then snap the Eular vectors to multiples of five but it creates very strange jittering when rotating. You may not have noticed it when doing it in multiples of 90 and the slerp definitely hides this somewhat but it's still noticeable. Especially when I took the slerp out.

Thanks for trying though :)

avatar image Bash Mills · Mar 22, 2014 at 04:30 AM 0
Share

Also I was doing it on all 3 axes which seems to be a factor in the phenomenon I'm experiencing.

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

22 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

Related Questions

Rotating wrong 0 Answers

Use Lerp to rotate object 2 Answers

Rotate object in the direction where it is going 1 Answer

How to instantiate on custom rotation? 1 Answer

w in Quaternion? 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