|
1 | 1 | # Euler Angles |
2 | 2 |
|
| 3 | +Euler angles describe rotations with three ordered rotations (typically yaw, pitch, roll) expressed in degrees. Unity exposes them heavily in the Inspector, but under the hood it converts every change to quaternions. Treat Euler angles as a user-friendly façade: lean on them for authoring and quick edits, then hand off to quaternions for math-heavy work. |
| 4 | + |
| 5 | +## Where Euler Angles Shine |
| 6 | + |
| 7 | +- Editing rotations in the Inspector or scripting quick adjustments in degrees. |
| 8 | +- Presenting player-facing data such as compass bearings or camera pitch. |
| 9 | +- Constraining motion to specific axes (e.g., yaw-only turrets, clamped camera pitch). |
| 10 | +- Debug logging of orientation values without converting radians to degrees. |
| 11 | + |
| 12 | +## Reading and Setting Euler Values |
| 13 | + |
3 | 14 | ```csharp |
4 | | -// Euler angles are "degree angles" like 90, 180, 45, 30 degrees. |
5 | | -// Quaternions differ from Euler angles in that they represent a point on a Unit Sphere (the radius is 1 unit). |
| 15 | +// Grab the world rotation in degrees |
| 16 | +Vector3 worldEuler = transform.eulerAngles; // e.g., (0, 180, 0) |
| 17 | +
|
| 18 | +// Override the yaw while keeping existing pitch/roll |
| 19 | +Vector3 newEuler = worldEuler; |
| 20 | +newEuler.y = desiredHeadingDegrees; |
| 21 | +transform.eulerAngles = newEuler; |
6 | 22 |
|
7 | | -// Create a quaternion that represents 30 degrees about X, 10 degrees about Y |
8 | | -Quaternion rotation = Quaternion.Euler(30, 10, 0); |
| 23 | +// Local rotation in degrees, relative to the parent |
| 24 | +Vector3 localEuler = transform.localEulerAngles; |
| 25 | +transform.localEulerAngles = new Vector3(0f, 45f, 0f); |
| 26 | +``` |
| 27 | + |
| 28 | +Euler angles wrap to the range `[0, 360)` when read from Unity. If you need values centered around zero, normalize them manually with helpers like `Mathf.DeltaAngle`. |
| 29 | + |
| 30 | +## Creating Quaternions From Euler Data |
| 31 | + |
| 32 | +```csharp |
| 33 | +// Construct from components (XYZ order, degrees) |
| 34 | +Quaternion facing = Quaternion.Euler(0f, 30f, 0f); |
| 35 | + |
| 36 | +// Construct from a vector |
| 37 | +Vector3 turretAngles = new Vector3(0f, 90f, 0f); |
| 38 | +Quaternion turretRotation = Quaternion.Euler(turretAngles); |
| 39 | + |
| 40 | +// Mix: set pitch in Euler, keep yaw from a quaternion |
| 41 | +Quaternion baseRotation = transform.rotation; |
| 42 | +Vector3 mixedEuler = baseRotation.eulerAngles; |
| 43 | +mixedEuler.x = pitchDegrees; |
| 44 | +transform.rotation = Quaternion.Euler(mixedEuler); |
| 45 | +``` |
| 46 | + |
| 47 | +Under the hood Unity uses Z-X-Y (roll, pitch, yaw) order when converting Euler angles to quaternions. You usually do not need to care, but remember that reordering axes changes the final orientation. |
| 48 | + |
| 49 | +## Avoiding the Common Pitfalls |
| 50 | + |
| 51 | +- **Gimbal lock** – When two axes align, you lose a degree of freedom. This happens when composing Euler rotations directly; generate a quaternion via `Quaternion.Euler` and combine in quaternion space instead. |
| 52 | +- **Interpolation artefacts** – `Vector3.Lerp` on Euler angles causes axis flipping near 180/360°. Prefer `Quaternion.Slerp` or `Quaternion.Lerp` for smooth motion. |
| 53 | +- **Angle wrapping** – Values jump between `0` and `360` instead of smoothly crossing through zero. Use `Mathf.DeltaAngle`, or track your own unbounded angle accumulator. |
| 54 | +- **Inspector edit order** – Rotations apply in Z-X-Y order. Animating multiple axes simultaneously can produce unintuitive curves; preview in the animation window to verify. |
| 55 | + |
| 56 | +## Debugging & Utilities |
| 57 | + |
| 58 | +```csharp |
| 59 | +// Convert quaternion to Euler for logging |
| 60 | +Vector3 display = transform.rotation.eulerAngles; |
| 61 | +Debug.Log($"Heading: {display.y:0}° Pitch: {display.x:0}°"); |
9 | 62 |
|
10 | | -// Using a Vector |
11 | | -Vector3 EulerRotation = new Vector3(30, 10, 0); |
12 | | -Quaternion rotation = Quaternion.Euler(EulerRotation); |
| 63 | +// Clamp pitch while keeping yaw free |
| 64 | +Vector3 clamped = transform.localEulerAngles; |
| 65 | +clamped.x = Mathf.Clamp(Mathf.DeltaAngle(0f, clamped.x), -45f, 45f); |
| 66 | +clamped.x = (clamped.x + 360f) % 360f; // convert back to 0-360 range |
| 67 | +transform.localEulerAngles = clamped; |
13 | 68 |
|
14 | | -// Convert a transform's Quaternion angles to Euler angles |
15 | | -Quaternion quaternionAngles = transform.rotation; |
16 | | -Vector3 eulerAngles = quaternionAngles.eulerAngles; |
| 69 | +// Build a quaternion after editing Euler values |
| 70 | +Vector3 offsetEuler = new Vector3(0f, 45f, 0f); |
| 71 | +Quaternion offsetRotation = Quaternion.Euler(offsetEuler) * transform.rotation; |
17 | 72 | ``` |
18 | 73 |
|
| 74 | +Use Euler angles where readability and simple axis locks matter, but switch to quaternions for compound rotations, interpolation, and physics-facing logic. Combining both viewpoints lets you keep authoring intuitive while the runtime math stays robust. |
0 commit comments