I've been trying to get the vector that represents the local rigid body's true forward pointing (z axis, or blue colored) vector. I've been using Debug.DrawLine(...) to try and find out which position vector to use.

Debug.DrawLine(_rb.position, new Vector3(_rb.position.x, _rb.position.y, _rb.position.z + 10), Color.red, .01f, true);
Debug.DrawLine(_tf.position, new Vector3(_tf.position.x, _tf.position.y, _tf.position.z + 10), Color.green, .01f, true);

Debug.DrawLine(transform.forward, new Vector3(transform.forward.x, transform.forward.y, transform.forward.z + 10), Color.blue, .01f, true);
Debug.DrawLine(transform.forward, new Vector3(transform.forward.x, transform.forward.y, transform.forward.z + 10), Color.yellow, .01f, true);

rb.position and tf.position appear to be equivalent, while transform.forward and Vector3.forward are equivalent but are in the world's (x,y,z) 0 position. All four have the same orientation when I change the orientation of the Rigidbody via it's angular velocity property.

Why do you need the local z axis orientation?

I'm implementing a Vehicle in unity without using Wheel Colliers because they don't have the level of control that I want, and their physics are extremely wonky. Being able to obtain a vector representing the z axis orientation makes it very easy to turn the car, since I only have to modify the Rigidbody.angularVelocity function to get it to turn.

Code for reference

For reference, my driving controller code consists of three steps within the FixedUpdate() method.

First is the simple Turning algorithm, which creates a triangle relationship with the front and back wheel of the car and the requested steering angle and then factors this relationship into a rate of change of angular velocity:

if (Input.GetButton("Right")) {
  _steerAngle = 45;
  var l = Mathf.Abs(Vector2.Distance(new Vector2(BL.position.x, BL.position.z), new Vector2(FL.position.x, FL.position.z)));
  turningCircleRadius = l / Mathf.Sin(_steerAngle);
  _rb.angularVelocity = new Vector3(_rb.angularVelocity.x, new Vector2(_rb.velocity.x, _rb.velocity.z).magnitude / _turningCircleRadius, _rb.angularVelocity.z);
} else if (Input.GetButton("Left")) {
  steerAngle = -45;
  var l = Mathf.Abs(Vector2.Distance(new Vector2(BR.position.x, BR.position.z), new Vector2(FR.position.x, FR.position.z)));
  _turningCircleRadius = l / Mathf.Sin(_steerAngle);
  _rb.angularVelocity = new Vector3(_rb.angularVelocity.x, new Vector2(_rb.velocity.x, _rb.velocity.z).magnitude / _turningCircleRadius, _rb.angularVelocity.z);
} else {
  _steerAngle = 0;
  _rb.angularVelocity = new Vector3(0, 0, 0);
  _turningCircleRadius = 1 / 0f;

Then the force exerted by the engine is calculated and then converted into change in velocity:

var latSpeed = new Vector2(_rb.velocity.x, _rb.velocity.z).magnitude;
  if (Input.GetButton("Accelerate")) {
    var force = _rb.mass * 10;
    latSpeed += force / _rb.mass * Time.fixedDeltaTime;
  } else if (Input.GetButton("Brake")) {
    var force = -1 * 1000 * _rb.mass;
    latSpeed += force / _rb.mass * Time.fixedDeltaTime;
    if(latSpeed <= 0) latSpeed = 0;

Finally, the velocity is modified:

_rb.velocity = new Vector3(transform.forward.x * latSpeed, _rb.velocity.y, transform.forward.z * latSpeed);

As you can see this driving algorithm would work fine on a completely flat surface, but would start to have wonky interactions with hills if the vehicle's pitch were to change.


1 Answer 1


transform.forward already gives you exactly this.

It looks like you might just be confused about how to visualize the vectors. You're repeatedly visualizing the vector (0, 0, 10) with different start points, not visualizing the facing direction of transform.forward.

Try this:

// Start our drawn line at the object's position in world space.
Vector3 lineStart = transform.position;

// From here, extend 3 units in worldspace along the object's local forward direction.
Vector3 lineEnd = lineStart + 3.0f * transform.forward;

// Draw the resuting line.
Debug.DrawLine(lineStart, lineEnd, Color.blue, Time.deltaTime);

You can verify that the blue line drawn exactly tracks the blue z+ axis of the local transform gizmo for the GameObject to which this script is attached.

There are similar bits of odd-looking math in the rest of your code. A couple of examples:

  • You wrap a Vector2.Distance call inside an absolute value function, which is a no-op since the returned distance is already non-negative by definition.

  • You both multiply and divide the force value by rb_mass, which neutralizes its effect, so your code ends up ignoring the object's mass.

With this in mind, you might want to consider re-evaluating Unity's built-in wheel collider. It's possible that the issues you had with it were a result of misinterpreting the vectors & math you were using. Physics libraries are strange and it's easy to make them behave badly, but the vast majority of troubles I've seen with them (including the majority of the problems I've had myself) turn out to be a result of using these tools incorrectly, and not an intrinsic flaw in the provided physics classes. They're just very easy to misconfigure.


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .