Skip to main content
C
Source Link
DMGregory
  • 140.8k
  • 23
  • 257
  • 401
transform// Construct a new orientation quaternion or matrix from Euler/Tait-Bryan angles.rotation var newRotation = Quaternion.Euler(totalPitch, totalYaw, 0f); // Apply it to our object. transform.rotation = newRotation; 
// Form a view vector using total pitch & yaw as spherical coordinates. Vector3 forward = new Vector3( Mathf.cos(totalPitch) * Mathf.sin(totalYaw), Mathf.sin(totalPitch), Mathf.cos(totalPitch) * Mathf.cos(totalYaw)); // Construct an orientation or view matrix pointing in that direction. transform.rotationvar newRotation = Quaternion.LookRotation(forward, new Vector3(0, 1, 0)); // Apply it to our object. transform.rotation = newRotation; 
transform.rotation = Quaternion.Euler(totalPitch, totalYaw, 0f); 
// Form a view vector using total pitch & yaw as spherical coordinates. Vector3 forward = new Vector3( Mathf.cos(totalPitch) * Mathf.sin(totalYaw), Mathf.sin(totalPitch), Mathf.cos(totalPitch) * Mathf.cos(totalYaw)); // Construct an orientation or view matrix pointing in that direction. transform.rotation = Quaternion.LookRotation(forward, new Vector3(0, 1, 0)); 
// Construct a new orientation quaternion or matrix from Euler/Tait-Bryan angles. var newRotation = Quaternion.Euler(totalPitch, totalYaw, 0f); // Apply it to our object. transform.rotation = newRotation; 
// Form a view vector using total pitch & yaw as spherical coordinates. Vector3 forward = new Vector3( Mathf.cos(totalPitch) * Mathf.sin(totalYaw), Mathf.sin(totalPitch), Mathf.cos(totalPitch) * Mathf.cos(totalYaw)); // Construct an orientation or view matrix pointing in that direction. var newRotation = Quaternion.LookRotation(forward, new Vector3(0, 1, 0)); // Apply it to our object. transform.rotation = newRotation; 
Clarifying example
Source Link
DMGregory
  • 140.8k
  • 23
  • 257
  • 401

This is equivalent to storing up the net total yaw and total pitch you want as float variables, then always applying the net result all at once, constructing a single new orientation quaternion or matrix from scratchthese angles alone (provided you keep totalPitch clamped):

transform.rotation.eulerAngles = new Vector3Quaternion.Euler(totalPitch, totalYaw, 0f); 

This is equivalent to storing up the net total yaw and total pitch you want, then always applying the net result all at once, from scratch (provided you keep totalPitch clamped):

transform.rotation.eulerAngles = new Vector3(totalPitch, totalYaw, 0f); 

This is equivalent to storing up the net total yaw and total pitch you want as float variables, then always applying the net result all at once, constructing a single new orientation quaternion or matrix from these angles alone (provided you keep totalPitch clamped):

transform.rotation = Quaternion.Euler(totalPitch, totalYaw, 0f); 
Clarifying
Source Link
DMGregory
  • 140.8k
  • 23
  • 257
  • 401

(The specific order will depend on the multiplication conventions in your environment, but left = more global / right = more local is a common choice)

This is equivalent to storing up the net total yaw and total pitch you want, then always applying the net result all at once, from scratch (provided you keep totalPitch clamped):

// Form a view vector using total pitch & yaw as spherical coordinates. Vector3 forward = new Vector3( Mathf.cos(pitchtotalPitch) * Mathf.sin(yawtotalYaw), Mathf.sin(pitchtotalPitch), Mathf.cos(pitchtotalPitch) * Mathf.cos(yawtotalYaw)); // Construct an orientation or view matrix pointing in that direction. transform.rotation = Quaternion.LoockRotationLookRotation(forward, new Vector3(0, 1, 0)); 

This global/local hybrid strategy isn't always the right fix. For example, in a game with 3D flight/swimming, you might want to be able to point straight up / straight down and still have full control. But with this setup you'll hit gimbal lock - your yaw axis (global up) becomes parallel to your roll axis (local forward), and you have no way to look left or right without twisting.

What you can do instead in cases like this is to use pure local rotations like we started with in the question above (so your controls feel the same no matter where you're looking), which will initially let some roll creep in - but then we correct for it.

For example, we can use local rotations to update our forward"forward" vector, then use that forward vector together with a reference up"up" vector to construct our final orientation. (Using, for example, Unity's Quaternion.LookRotation method, or manually constructing an orthonormal matrix from these vectors) By controlling the up vector, we control the roll or twist.

This is equivalent to storing up the net total yaw and total pitch you want, then always applying the net result all at once, from scratch (provided you keep totalPitch clamped):

// Form a view vector using total pitch & yaw as spherical coordinates. Vector3 forward = new Vector3( Mathf.cos(pitch) * Mathf.sin(yaw), Mathf.sin(pitch), Mathf.cos(pitch) * Mathf.cos(yaw)); // Construct an orientation or view matrix pointing in that direction. transform.rotation = Quaternion.LoockRotation(forward, new Vector3(0, 1, 0)); 

This global/local hybrid strategy isn't always the right fix. For example, in a game with 3D flight/swimming, you might want to be able to point straight up / straight down and still have full control. But with this setup you'll hit gimbal lock - your yaw axis (global up) becomes parallel to your roll axis (local forward), and you have no way to look left or right.

What you can do instead in cases like this is to use pure local rotations (so your controls feel the same no matter where you're looking), which will initially let some roll creep in - but then we correct for it.

For example, we can use local rotations to update our forward vector, then use that forward vector together with a reference up vector to construct our final orientation. (Using, for example, Unity's Quaternion.LookRotation method, or manually constructing an orthonormal matrix from these vectors) By controlling the up vector, we control the roll or twist.

(The specific order will depend on the multiplication conventions in your environment, but left = more global / right = more local is a common choice)

This is equivalent to storing up the net total yaw and total pitch you want, then always applying the net result all at once, from scratch (provided you keep totalPitch clamped):

// Form a view vector using total pitch & yaw as spherical coordinates. Vector3 forward = new Vector3( Mathf.cos(totalPitch) * Mathf.sin(totalYaw), Mathf.sin(totalPitch), Mathf.cos(totalPitch) * Mathf.cos(totalYaw)); // Construct an orientation or view matrix pointing in that direction. transform.rotation = Quaternion.LookRotation(forward, new Vector3(0, 1, 0)); 

This global/local hybrid strategy isn't always the right fix. For example, in a game with 3D flight/swimming, you might want to be able to point straight up / straight down and still have full control. But with this setup you'll hit gimbal lock - your yaw axis (global up) becomes parallel to your roll axis (local forward), and you have no way to look left or right without twisting.

What you can do instead in cases like this is to use pure local rotations like we started with in the question above (so your controls feel the same no matter where you're looking), which will initially let some roll creep in - but then we correct for it.

For example, we can use local rotations to update our "forward" vector, then use that forward vector together with a reference "up" vector to construct our final orientation. (Using, for example, Unity's Quaternion.LookRotation method, or manually constructing an orthonormal matrix from these vectors) By controlling the up vector, we control the roll or twist.

Adding a polar coordinate example.
Source Link
DMGregory
  • 140.8k
  • 23
  • 257
  • 401
Loading
Adding multiplication order example
Source Link
DMGregory
  • 140.8k
  • 23
  • 257
  • 401
Loading
Clarifying world case
Source Link
DMGregory
  • 140.8k
  • 23
  • 257
  • 401
Loading
added 1 character in body
Source Link
DMGregory
  • 140.8k
  • 23
  • 257
  • 401
Loading
Source Link
DMGregory
  • 140.8k
  • 23
  • 257
  • 401
Loading