Having trouble with resolving collisions with Physics.ComputePenetration()

I am trying to create my own character controller by following couple of tutorials but i am having trouble with player being able to squeeze through gaps that are just a bit thinner than the players collider when moving towards it:

or when moving towards sharp corners where player will clip small amount into objects:

After stopping player is pushed outside of the objects correctly.

In PlayerController script I first get input, rotate and move the player with the following fuctions in the update method:

private void GetInput()
    {
        input = Vector2.ClampMagnitude(new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical")), 1);
        inputDirection = input.normalized;
    }

    private void Rotate()
    {
        if (inputDirection != Vector2.zero)
        {
            float targetRotation = Mathf.Atan2(inputDirection.x, inputDirection.y) * Mathf.Rad2Deg +  cameraTransform.eulerAngles.y;
            transform.eulerAngles = Vector3.up * Mathf.SmoothDampAngle(transform.eulerAngles.y, targetRotation, ref turnSmoothVelocity, TurnSpeed);
        }
    }

    private void Move()
    {
        Vector3 accelaration = transform.forward * MovementSpeed  * input.magnitude;
        velocity += accelaration * Time.deltaTime;
        transform.position += velocity;
        velocity = Vector3.zero;
    }

After which I check for collisions with the following function in the update method:

public void CheckCollision()
    {
        Collider[] overlaps = new Collider[4];
        int numOfCollisons = Physics.OverlapCapsuleNonAlloc(transform.TransformPoint(new Vector3(0f, transform.position.y + capsuleCollider.radius, 0f)), transform.TransformPoint(new Vector3(0f, capsuleCollider.height - capsuleCollider.radius, 0f)), capsuleCollider.radius, overlaps, playerMask, QueryTriggerInteraction.UseGlobal);
        for (int i = 0; i < numOfCollisons; i++)
        {
            Transform overlapTransform = overlaps[i].transform;
            Vector3 fixPositionVector;
            float fixPositionDistance;
            if (Physics.ComputePenetration(capsuleCollider, transform.position, transform.rotation, overlaps[i], overlapTransform.position, overlapTransform.rotation, out fixPositionVector, out fixPositionDistance))
            {
                Vector3 updatedPostion = fixPositionVector * fixPositionDistance;
                transform.position += new Vector3(updatedPostion.x, 0.0f, updatedPostion.z);
                velocity -= Vector3.Project(velocity, -fixPositionVector);
            }
        }
    }

I have tried to fix this with adding adding negative accelaration when pushing player out of the objects:

if (Physics.ComputePenetration(capsuleCollider, transform.position, transform.rotation, overlaps[i], overlapTransform.position, overlapTransform.rotation, out fixPositionVector, out fixPositionDistance))
            {
                Vector3 updatedPostion = fixPositionVector * fixPositionDistance;
                transform.position += new Vector3(updatedPostion.x, 0.0f, updatedPostion.z) + (-accelaration * Time.deltaTime);
                velocity -= Vector3.Project(velocity, -fixPositionVector);
            }

this helped with visible clipping but it also causes stuttering motion when player collides with objects. Any ideas how to fix this?

One way to handle this is to have a proxy object that is invisible with the physics collider on it. That object would be subject to sharp stops and jitters but nobody would notice it.

The player in turn would try to move to match that object’s position/rotation, but only if it was more than X distance different from where the player is now. The player itself would have no physics at all but just blindly follow this proxy object in LateUpdate(). When it got near a collider and the proxy started jittering, if you had your X big enough, your player would just stand there not moving as you try to wiggle the collider through.

Yeah this seems to be better way handling the movement, but I am having the same problems as before. The distance that player needs to move needs to be so big that general movement becomes choppy. There is probably something wrong with the OverlapCapsuleNonAlloc(), ComputePenetration() or how I apply it to the player. Thanks for the advice.

You can as well “predict” if player is clipping, and only then apply any translation at all or even negate some inputs.
This will also prevent any clipping done.

Also, make sure you’re performing checks and movement in FixedUpdate, as this does matter.