3D Rigidbody Turning Inconsistencies while moving on a surface

Good morning,

I am observing a scenario where a 3D rigidbody cube behaves inconsistently between turning left & turning right. I am attempting to move the cube like a vehicle and stay compliant with the physics system (I’m using addforce/addtorque instead of adjusting some rigidbody values directly). Across several sessions, I have tweaked numerous values hoping to discover what causes this behavior. So far, I have had no luck isolating the issue.


I have ran low on ideas, but this behavior is really bothering me. I have circumvented the issue in the past by upping the torque value, but I was intending to improve finer control when this behavior reared its ugly head again. I wanted to post the question and see if the community had any experience or feedback regarding the issue.


I have attached a video displaying the behavior: rigidbodyTurning - YouTube


Additionally, here’s a code sample of the most relevant area. I believe I am applying the torque forces in the same manner both positively and negatively, but I could certainly have overlooked something.

        forwardInput = Input.GetAxis("Vertical");
        lateralInput = Input.GetAxis("Q/E");
        pivotInput = Input.GetAxis("Horizontal");

        if (Math.Abs(pivotInput) > 0f)
        {
            pivotCurrent = 0.16f * Math.Sign(pivotInput); ;
        }
        else if (Math.Abs(pivotInput) == 0f)
        {
            float subtractAmount = 1f;
            if (Math.Abs(pivotCurrent) <= 1f)
            {
                subtractAmount = Math.Abs(pivotCurrent);
            }
            pivotCurrent = (Math.Abs(pivotCurrent) - subtractAmount) * Math.Sign(pivotCurrent);
        }
        float maxPivot = 60f;
        pivotCurrent = Mathf.Clamp(pivotCurrent, -maxPivot, maxPivot);

        pivotProduct = Vector3.up * pivotCurrent;

        if (BoxCaseGroundCheck())
        {
            myRigidbody.AddRelativeTorque(pivotProduct, ForceMode.Impulse);
            myRigidbody.AddRelativeForce(Vector3.forward * forwardInput * forwardMultiplier, ForceMode.Force);
            myRigidbody.AddRelativeForce(Vector3.right * lateralInput * lateralMultiplier, ForceMode.Force);
            if (myRigidbody.velocity.sqrMagnitude > squareMaxVelocity)
            {
                RegulateVelocity();
            }
        }

Thanks for your time and attention regarding this behavior. Editted: Cleaned up some wording for clarity.

After investigating this issue further, it appears to be related to the friction component of the Player’s physic material. Setting dynamic friction/static friction to 0.0 seems to remove irregularities.


However, I have established a workable solution that seems to minimize the magnitude of the issue.

        // Ang Vel of .4-.5 feels good for turning
        // with Vel Change forcemode

        // Forcemode.VelocityChange directly adjusts the angular velocity. Give or take some
        // However, physic material Friction also seems to impact this. Add an additional offset for this

        // Left and right turning is not precisely the same, but it's withing spitting distance. 
        // seems to be something related to friction physics-- setting to zero will ignore it
        // Will be investigating "friction 2" functionality I discovered

        forwardInput = Input.GetAxis("Vertical");
        steeringInput = Input.GetAxis("Horizontal");

        float deltaTargetAngularVelocity = 0f;
        float localVelocityZ = transform.InverseTransformVector(myRigidbody.velocity).z;
        float baseTarget = .75f;
        // Checking it against zero didn't seem to function. checking it against a small value (.025 arbitrarily)
        // seems to achieve the behavior
        if (Math.Abs(localVelocityZ) >= 0.025f)
        {
            deltaTargetAngularVelocity = Steering2(baseTarget);
        }
        else
        {
            deltaTargetAngularVelocity = Steering2(baseTarget * 2.25f);
        }

        pivotProduct = Vector3.up * deltaTargetAngularVelocity;

        if (BoxCaseGroundCheck())
        {
            myRigidbody.AddRelativeTorque(pivotProduct, ForceMode.VelocityChange);
            myRigidbody.AddRelativeForce(Vector3.forward * forwardInput * forwardMultiplier, ForceMode.Force);

            RegulateVelocity();
            RegulateLateralVelocity();
        }

    float Steering2(float targetValue)
    {
        /*
         * For some reason, I'm still seeing a variance on left/right turns. It seems to be something
         * concerning friction values. Removing friction removes the variances.
         * Until I can isolate it further, I've customized the steering function to degrade negative/
         * left turn by 15%-- this seems to get the values in range at the setting angVel goal of .75 
         */
        Debug.Log(targetValue);
        float deltaTargetAngularVelocity = 0f;
        if (steeringInput != 0f)
        {
            float frictionValue = GetComponent<BoxCollider>().material.dynamicFriction;
            float localAngularVelocityY = transform.InverseTransformVector(myRigidbody.angularVelocity).y;
            float targetedAngularVelocity = targetValue * Math.Sign(steeringInput);
            deltaTargetAngularVelocity = targetedAngularVelocity - localAngularVelocityY;
            if(steeringInput > 0)
            {
                deltaTargetAngularVelocity += frictionValue * Math.Sign(steeringInput);
            }else if (steeringInput < 0 ) 
            {
                deltaTargetAngularVelocity += frictionValue * Math.Sign(steeringInput) * .85f;
            }
        }

        return deltaTargetAngularVelocity;
    }

Beyond refactoring the code, the major changes were:

  1. Changed Forcemode to Velocity Change. This takes some of the guesswork out of a torque to angular velocity conversion. It’s not precisely there, but it’s close enough to work with.
  2. In the same vein, it seems like dynamic/static friction component impacts velocity change nearly 1 to 1. adding the friction value to addTorque’s force seems to do a respectable job.
  3. Within the Steering2() functon, I wrote out a bit of code to scale back Left-turning by about 15%. This puts it roughly in line with RIght-turning with my specific setup. Additionally, even ignoring the 15% offset, this bit of code seemed to perform respectably, and probably wouldn’t have noticed the differences between left and right turning were it not for tracking the value onscreen.

Ultimately, I am pleased with the solution, and wanted to share it here in case anyone else experiences this issue.


The root of the question still remains though:
Why is there a ~15% turning variance between a left turn and a right turn?

This issue may be closed.