Skip to main content
Clarifying
Source Link
DMGregory
  • 140.8k
  • 23
  • 257
  • 401

I often like to give myself a little convenience method:

Vector3 CameraRelativeFlatten(Vector3 input, Vector3 localUp) { // If this script is on your camera object, you can use this.transform instead. Transform cam = Camera.main.transform; // The first part creates a rotation looking into the ground, with // with "up" matching the inputcamera's look direction as closely as it can. // The second part rotates this 90 degrees, so "forward" input matches  // the inputcamera's look direction as closely as it can while sitting in the correcthorizontal plane. Quaternion flatten = Quaternion.LookRotation( -localUp, cam.forward ) * Quaternion.Euler(Vector3.right * -90f); // Now we rotate our input vector into this plane.frame of reference return flatten * input; } 

When I have an input in controller space, I can use this convert it to a direction in the world horizontal plane, relative to the camera:

Vector3 input = new Vector3(Input.GetAxis("Horizontal"), 0f, -Input.GetAxis("Vertical")); Vector3 worldSpaceInput = CameraRelativeFlatten(input, Vector3.up); 

If we wanted, we could also use a local surface normal instead of Vector3.up to get our input parallel to an arbitrary tilted surface, instead of always in the XZ plane.

Since we're rotating the input vector, the length is preserved, so we won't just chop off the portion of a vector that was digging into the surface, slowing our forward-back movement relative to left-right.

I often like to give myself a little convenience method:

Vector3 CameraRelativeFlatten(Vector3 input, Vector3 localUp) { // If this script is on your camera object, you can use this.transform instead. Transform cam = Camera.main.transform; // The first part creates a rotation looking into the ground, // with "up" matching the input direction as closely as it can. // The second part rotates this 90 degrees, so "forward" matches // the input as closely as it can while sitting in the correct plane. Quaternion flatten = Quaternion.LookRotation( -localUp, cam.forward ) * Quaternion.Euler(Vector3.right * 90f); // Now we rotate our input vector into this plane. return flatten * input; } 

When I have an input in controller space, I can use this convert it to a direction in the world horizontal plane, relative to the camera:

Vector3 input = new Vector3(Input.GetAxis("Horizontal"), 0f, -Input.GetAxis("Vertical")); Vector3 worldSpaceInput = CameraRelativeFlatten(input, Vector3.up); 

If we wanted, we could also use a local surface normal instead of Vector3.up to get our input parallel to an arbitrary tilted surface, instead of always in the XZ plane.

Since we're rotating the input vector, the length is preserved, so we won't just chop off the portion of a vector that was digging into the surface, slowing our forward-back movement relative to left-right.

I often like to give myself a little convenience method:

Vector3 CameraRelativeFlatten(Vector3 input, Vector3 localUp) { // If this script is on your camera object, you can use this.transform instead. Transform cam = Camera.main.transform; // The first part creates a rotation looking into the ground, with // "up" matching the camera's look direction as closely as it can. // The second part rotates this 90 degrees, so "forward" input matches  // the camera's look direction as closely as it can in the horizontal plane. Quaternion flatten = Quaternion.LookRotation( -localUp, cam.forward ) * Quaternion.Euler(Vector3.right * -90f); // Now we rotate our input vector into this frame of reference return flatten * input; } 

When I have an input in controller space, I can use this convert it to a direction in the world horizontal plane, relative to the camera:

Vector3 input = new Vector3(Input.GetAxis("Horizontal"), 0f, Input.GetAxis("Vertical")); Vector3 worldSpaceInput = CameraRelativeFlatten(input, Vector3.up); 

If we wanted, we could also use a local surface normal instead of Vector3.up to get our input parallel to an arbitrary tilted surface, instead of always in the XZ plane.

Since we're rotating the input vector, the length is preserved, so we won't just chop off the portion of a vector that was digging into the surface, slowing our forward-back movement relative to left-right.

Source Link
DMGregory
  • 140.8k
  • 23
  • 257
  • 401

I often like to give myself a little convenience method:

Vector3 CameraRelativeFlatten(Vector3 input, Vector3 localUp) { // If this script is on your camera object, you can use this.transform instead. Transform cam = Camera.main.transform; // The first part creates a rotation looking into the ground, // with "up" matching the input direction as closely as it can. // The second part rotates this 90 degrees, so "forward" matches // the input as closely as it can while sitting in the correct plane. Quaternion flatten = Quaternion.LookRotation( -localUp, cam.forward ) * Quaternion.Euler(Vector3.right * 90f); // Now we rotate our input vector into this plane. return flatten * input; } 

When I have an input in controller space, I can use this convert it to a direction in the world horizontal plane, relative to the camera:

Vector3 input = new Vector3(Input.GetAxis("Horizontal"), 0f, -Input.GetAxis("Vertical")); Vector3 worldSpaceInput = CameraRelativeFlatten(input, Vector3.up); 

If we wanted, we could also use a local surface normal instead of Vector3.up to get our input parallel to an arbitrary tilted surface, instead of always in the XZ plane.

Since we're rotating the input vector, the length is preserved, so we won't just chop off the portion of a vector that was digging into the surface, slowing our forward-back movement relative to left-right.