1
\$\begingroup\$

I'm using a slider to rotate an object on the z axis. The slider has a value of 1-360 (Whole Numbers); when the slider is moved, I use that value for the eulerAngles z axis value. (NOTE: The object is part of a child/parent 'string' of instantiated objects and it should only ever rotate on the local z axis). This method is working for some objects in the 'string', but not others. When it's not working, the object I'm trying to rotate spins wildly on the z axis because the objects z value is not a reflection of the slider value (I tested this in the inspector). I can't figure where these 'random' slider values are coming from.

Here is the rotation function I'm using for the sliders On Value Change event:

 public void SliderRotate () {
     Target.transform.eulerAngles = new Vector3(
         Target.transform.eulerAngles.x,
         Target.transform.eulerAngles.y,
         mySlider.GetComponent<Slider> ().value);
 }

BTW - If I change the x and y values to zero, the problem goes away. However, the objects then loose their correct orientation to their parent (I need the x and y to stay where they are).

Thanks in advance for any insight you can offer into this issue.

Windows - Unity 5.3.5f1

Here is an image that might help clarify:

Pipe Run

\$\endgroup\$
  • \$\begingroup\$ Are you attempting to have the slider object's z axis be absolute to the world, or relative? As in, if the child is a globe or planet, do you want the child rotating around its equator or in the direction of the solar orbit? \$\endgroup\$ – ketura Aug 26 '16 at 20:59
  • \$\begingroup\$ The object needs to rotate relative to its parent. It's a series of pipes and fittings all connected to each other. So, each part needs to rotate as if it was attached and just pivoting around it's parent. I'll try to attach an image that might help clarify. \$\endgroup\$ – Alex Aug 29 '16 at 13:16
  • 1
    \$\begingroup\$ Do you mean to use Transform.localEulerAngles? \$\endgroup\$ – DMGregory Aug 29 '16 at 13:22
1
\$\begingroup\$

The wild rotation happens because you don't get the same number for Target.transform.eulerAngles.x every frame.

Internally, Euler angles that you give are converted to quaternions and when you read it back they are converted back to Euler angles. This conversion is not one-to-one because Euler angles are an ambiguous representation of 3D rotation (meaning the same rotation can be represented by more than one set of Euler angle numbers). Therefore it makes sense that it goes wild, what you give is not always what you get back.

(Btw, like @DMGregory said, you should be using localEulerAngles, but that's only part of the story.)

Here are your options:

Simplest option: Have two gameobjects per an object that you want to turn like this. They should be a parent and a child. The parent contains the rotation that's not going to change, such as parent.transform.localEulerAngles = new Vector3(x, y, 0); or any other rotation that makes sense. The child will have the rotation that changes, such as child.transform.localEulerAngles = new Vector3(0, 0, mySlider.GetComponent<Slider> ().value);. This would be the cleanest option. If you don't want to use two game objects, the two other options below may help.

Option #2: Keep x and y fixed. Get the x and y of the rotation in the beginning, perhaps in Start() as such:

float x, y;
Start() {
    x = Target.transform.localEulerAngles.x;
    y = Target.transform.localEulerAngles.y;
}

and then later change your function to use them, rather than reading it from transform everytime:

public void SliderRotate () {
    Target.transform.localEulerAngles = new Vector3(
        x,
        y,
        mySlider.GetComponent<Slider> ().value);
}

This will ensure that you don't keep getting different values for x and y because of Euler angles being ambiguous. Again, we use localEulerAngles because you want to use local z axis.

Option #3: Like the previous step but keep quaternions instead.

Quaternion initialRotation;
Start() {
    initialRotation = Target.transform.localRotation;
}

public void SliderRotate () {
    // you can also use any other axis other than Vector3.forward
    Target.localRotation = initialRotation * Quaternion.AngleAxis(mySlider.GetComponent<Slider> ().value, Vector3.forward); 
}
\$\endgroup\$
  • \$\begingroup\$ "localEulerAngles" works perfectly. Thank you for the detailed explanation! :) \$\endgroup\$ – Alex Aug 30 '16 at 18:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.