void LateUpdate()
        {
            if (target == null)
            {
                return;
            }

            if (!initDone)
            {
                return;
            }

            if (distance < 0)
            {
                distance = 0;
            }

            // disable player character when too close
            if (!hideSkinnedMeshRenderers && smrs != null)
            {
                if (playerCollision || distance <= collisionDistance)
                {
                    for (int i = 0; i < smrs.Length; i++)
                    {
                        smrs[i].enabled = false;
                    }
                }
                else
                {
                    for (int i = 0; i < smrs.Length; i++)
                    {
                        smrs[i].enabled = true;
                    }
                }
            }

            Vector3 offsetVectorTransformed       = target.rotation * offsetVector;
            Vector3 cameraOffsetVectorTransformed = transform.rotation * cameraOffsetVector;

            if (smoothTargetMode)
            {
                smoothedTargetPosition = Vector3.Lerp(
                    smoothedTargetPosition,
                    target.position,
                    smoothTargetValue * Time.deltaTime);

                targetPosition = smoothedTargetPosition;
            }
            else
            {
                targetPosition = target.position;
            }

            targetPosWithOffset = (targetPosition + offsetVectorTransformed);
            Vector3 targetPosWithCameraOffset = targetPosition + offsetVectorTransformed + cameraOffsetVectorTransformed;

            Vector3 testDir = targetPosWithCameraOffset - targetPosWithOffset;

            if (Physics.SphereCast(targetPosWithOffset, collisionDistance, testDir, out offsetTest, testDir.magnitude, collisionLayer))
            {
                // offset clips into geometry, move the offset
                targetPosWithCameraOffset = offsetTest.point + offsetTest.normal * collisionDistance * 2;
            }

            dirToTarget = (transform.rotation * (new Vector3(0, 0, -distance) + cameraOffsetVector) + offsetVectorTransformed + targetPosition) - targetPosWithCameraOffset;
            float cameraToPlayerDistance = Mathf.Min(dirToTarget.magnitude, desiredDistance);

            dirToTarget = dirToTarget.normalized;

            RaycastHit[] hits = Physics.SphereCastAll(targetPosWithCameraOffset, collisionDistance, dirToTarget, desiredDistance, collisionLayer);

            //Debug.DrawRay(targetPosWithCameraOffset, dirToTarget * desiredDistance, Color.blue);

            if (hits.Length > 0)
            {
                rcms = new List <RayCastWithMags>(hits.Length);

                for (int i = 0; i < hits.Length; i++)
                {
                    RayCastWithMags rcm = new RayCastWithMags();

                    rcm.hit = hits[i];
                    rcm.distanceFromCamera = (prevPosition - hits[i].point).magnitude;
                    rcm.distanceFromTarget = (targetPosWithOffset - hits[i].point).magnitude;

                    rcms.Add(rcm);
                }

                List <RayCastWithMags> sortList = new List <RayCastWithMags>(rcms);

                sortList.Sort(sortMethodTarget);

                float lowestMagn = sortList[0].distanceFromTarget;

                for (int i = sortList.Count - 1; i >= 0; i--)
                {
                    if (sortList[i].distanceFromTarget > lowestMagn + collisionDistance * 2)
                    {
                        sortList.RemoveAt(i);
                    }
                }

                if (sortList[0].hit.distance > 0)
                {
                    occlusionHit = sortList[0].hit;
                }
            }
            else
            {
                occlusionHit = null;
            }

            // get current thickness between target and camera
            if (thicknessCheck && occlusionHit != null)
            {
                thickness = GetThickness();
            }
            else
            {
                thickness = float.MaxValue;
            }

            if ((cameraNormalMode || !smartPivot))
            {
                if (distance < desiredDistance)
                {
                    // safe guard for zooming out
                    Vector3 dirToTargetDistanced = ((transform.rotation * (new Vector3(0, 0, -distance - zoomOutStepValuePerFrame) + cameraOffsetVector) + offsetVectorTransformed + targetPosition) - (targetPosWithCameraOffset));

                    RaycastHit zoomOutHit;
                    if ((thicknessCheck && thickness > maxThickness) && Physics.SphereCast(targetPosWithCameraOffset, collisionDistance, dirToTargetDistanced.normalized, out zoomOutHit, dirToTargetDistanced.magnitude, collisionLayer))
                    {
                        distance = (zoomOutHit.point - targetPosWithCameraOffset).magnitude - collisionDistance;
                    }
                    else
                    {
                        distance += zoomOutStepValuePerFrame;
                    }
                }
                if (distance > desiredDistance)
                {
                    distance -= zoomOutStepValuePerFrame;
                }
            }

            // Cast ground target to activate smartPivot
            if ((smartPivot && occlusionHit != null) || bGroundHit) // needs a small distance offset
            {
                if (Physics.Raycast(prevPosition, Vector3.down, out groundHit, collisionDistance + 0.1f) && !playerLayer.IsInLayerMask(groundHit.transform.gameObject))
                {
                    bGroundHit = true;
                }
                else
                {
                    bGroundHit = false;
                }
            }
            else if (occlusionHit == null && cameraNormalMode)
            {
                bGroundHit = false;
            }

            // Avoid that the character is not visible
            if (occlusionCheck && occlusionHit != null)
            {
                if (cameraNormalMode)
                {
                    if (thickness > maxThickness)
                    {
                        //Debug.DrawLine(targetPosWithOffset, occlusionHit.Value.point, Color.green);
                        //Debug.DrawLine(targetPosWithOffset, occlusionHit.Value.point + occlusionHit.Value.normal.normalized * (collisionDistance), Color.red);

                        transform.position = occlusionHit.Value.point + occlusionHit.Value.normal.normalized * (collisionDistance);
                    }
                    else
                    {
                        transform.position = (transform.rotation * (new Vector3(0, 0, -distance) + cameraOffsetVector)) + offsetVectorTransformed + targetPosition;;
                    }
                }
            }
            else if (cameraNormalMode)
            {
                thickness          = float.MaxValue;
                transform.position = transform.rotation * (new Vector3(0, 0, -distance) + cameraOffsetVector) + offsetVectorTransformed + targetPosition;;
            }

            // smart pivot mode collision check
            if (smartPivot && (!cameraNormalMode))
            {
                Vector3 tmpEuler = transform.rotation.eulerAngles;
                tmpEuler.x = startingY;

                dirToTargetSmartPivot = (Quaternion.Euler(tmpEuler) * (new Vector3(0, 0, -distance) + cameraOffsetVector) + offsetVectorTransformed + targetPosition) - targetPosWithOffset;

                if (Physics.SphereCast(targetPosWithOffset, collisionDistance, dirToTargetSmartPivot.normalized, out hitSmartPivot, dirToTargetSmartPivot.magnitude + collisionDistance, collisionLayer))
                {
                    Vector3 v1  = hitSmartPivot.point - targetPosWithOffset;
                    float   dot = Vector3.Dot(v1, dirToTargetSmartPivot) / dirToTargetSmartPivot.magnitude;

                    Vector3 v2 = (dirToTargetSmartPivot.normalized * dot) - (dirToTargetSmartPivot.normalized * collisionDistance);

                    Vector3 newAlignVector = Vector3.zero;
                    if (v2.magnitude < dirToTargetSmartPivot.magnitude)
                    {
                        newAlignVector = v2;
                    }
                    else
                    {
                        newAlignVector = dirToTargetSmartPivot;
                    }

                    if (dot > 0.1f)
                    {
                        if ((transform.position - targetPosWithOffset).magnitude + zoomOutStepValuePerFrame < newAlignVector.magnitude)
                        {
                            transform.position += newAlignVector.normalized * zoomOutStepValuePerFrame;
                            transform.position += targetPosition - prevTargetPos;
                        }
                        else
                        {
                            transform.position = targetPosWithOffset + newAlignVector;
                        }
                    }
                }
                else
                {
                    // no clipping, transition to max distance
                    if ((transform.position - targetPosWithOffset).magnitude + zoomOutStepValuePerFrame < dirToTargetSmartPivot.magnitude)
                    {
                        transform.position += dirToTargetSmartPivot.normalized * zoomOutStepValuePerFrame;
                    }

                    transform.position += targetPosition - prevTargetPos;
                }
            }

            prevTargetPos = targetPosition;
            prevPosition  = transform.position;
        }
Beispiel #2
0
        void Update()
        {
            if (!initDone)
                return;

            if (distance < 0)
                distance = 0;

            // disable player character when too close
            if (smrs != null)
            {
                if (playerCollision || distance <= collisionDistance)
                {
                    for (int i = 0; i < smrs.Length; i++)
                    {
                        smrs[i].enabled = false;
                    }
                }
                else
                {
                    for (int i = 0; i < smrs.Length; i++)
                    {
                        smrs[i].enabled = true;
                    }
                }
            }

            if ((cameraNormalMode || !smartPivot))
            {
                if (distance <= desiredDistance)
                {
                    distance += zoomOutStepValuePerFrame;
                }
                if (distance >= desiredDistance)
                {
                    distance -= zoomOutStepValuePerFrame;
                }
            }

            Vector3 offsetVectorTransformed = target.transform.rotation * offsetVector;
            transform.position += (target.position - prevTargetPos);
            targetPosWithOffset = (target.position + offsetVectorTransformed);

            Vector3 dirToTargetOffset = targetPosWithOffset - target.position;

            if (Physics.SphereCast(target.position, collisionDistance, dirToTargetOffset, out offsetTest, dirToTargetOffset.magnitude + collisionDistance, collisionLayer))
            {
                // offset clips into geometry, move the offset
                float newDistance = offsetTest.distance - collisionDistance - 0.1f;
                targetPosWithOffset = (target.position + offsetVectorTransformed.normalized * newDistance);
            }

            dirToTarget = (transform.rotation * new Vector3(0, 0, -distance) + offsetVectorTransformed + target.position) - targetPosWithOffset;
            float cameraToPlayerDistance = Mathf.Min(dirToTarget.magnitude, desiredDistance);
            dirToTarget = dirToTarget.normalized;

            RaycastHit[] hits = Physics.SphereCastAll(targetPosWithOffset, collisionDistance, dirToTarget, cameraToPlayerDistance, collisionLayer);

            if (hits.Length > 0)
            {
                rcms = new List<RayCastWithMags>(hits.Length);

                for (int i = 0; i < hits.Length; i++)
                {
                    RayCastWithMags rcm = new RayCastWithMags();

                    rcm.hit = hits[i];
                    rcm.distanceFromCamera = (prevPosition - hits[i].point).magnitude;
                    rcm.distanceFromTarget = (targetPosWithOffset - hits[i].point).magnitude;

                    rcms.Add(rcm);
                }

                rcms = rcms.OrderBy(m => m.distanceFromTarget).ToList();
                float lowestMagn = rcms[0].distanceFromTarget;

                for (int i = rcms.Count - 1; i >= 0; i--)
                {
                    if (rcms[i].distanceFromTarget > lowestMagn + collisionDistance * 2)
                        rcms.RemoveAt(i);
                }

                rcms = rcms.OrderBy(m => m.distanceFromCamera).ToList();

                if (rcms[0].hit.distance > 0)
                    occlusionHit = rcms[0].hit;
            }
            else
                occlusionHit = null;

            // Cast ground target to activate smartPivot
            if ((smartPivot && occlusionHit != null) || bGroundHit) // needs a small distance offset
            {
                if (Physics.Raycast(prevPosition, Vector3.down, out groundHit, collisionDistance + 0.1f) && groundHit.transform.gameObject.layer != playerLayer)
                {
                    bGroundHit = true;
                }
                else
                    bGroundHit = false;
            }
            else if (occlusionHit == null && cameraNormalMode)
            {
                bGroundHit = false;
            }

            // Avoid that the character is not visible
            if (occlusionCheck && occlusionHit != null)
            {
                thickness = float.MaxValue;

                if (thicknessCheck && cameraNormalMode)
                {
                    currentIterations = 0;
                    thicknessStarts.Clear();
                    thicknessEnds.Clear();

                    Vector3 dirToHit = (transform.position - targetPosWithOffset).normalized;

                    Vector3 hitVector = (targetPosWithOffset - occlusionHit.Value.point);
                    Vector3 targetVector = targetPosWithOffset - transform.position;

                    float dotProd = Vector3.Dot(hitVector, targetVector) / targetVector.magnitude;
                    Vector3 unknownPoint = occlusionHit.Value.point + targetVector.normalized * dotProd;

                    thicknessStartPoint = unknownPoint + dirToHit * (cameraToPlayerDistance + collisionDistance);
                    thicknessEndPoint = unknownPoint;

                    float length = cameraToPlayerDistance;

                    while (Physics.SphereCast(thicknessEndPoint, collisionDistance, dirToHit, out thicknessHit, length, collisionLayer) && currentIterations < maxThicknessIterations)
                    {
                        length -= (thicknessEndPoint - thicknessHit.point).magnitude - 0.00001f;
                        thicknessEndPoint = thicknessHit.point + dirToTarget * 0.00001f;
                        if (!thicknessEnds.ContainsKey(thicknessHit.collider.name))
                            thicknessEnds.Add(thicknessHit.collider.name, thicknessHit); //TODO: fix multiple keys issue

                        currentIterations++;
                    }

                    currentIterations = 0;
                    length = cameraToPlayerDistance;

                    while (Physics.SphereCast(thicknessStartPoint, collisionDistance, -dirToHit, out thicknessHit, length, collisionLayer) && currentIterations < maxThicknessIterations)
                    {
                        length -= (thicknessStartPoint - thicknessHit.point).magnitude - 0.00001f;
                        thicknessStartPoint = thicknessHit.point - dirToTarget * 0.00001f;

                        if (!thicknessStarts.ContainsKey(thicknessHit.collider.name))
                            thicknessStarts.Add(thicknessHit.collider.name, thicknessHit);

                        currentIterations++;
                    }

                    if (thicknessEnds.Count > 0 && thicknessStarts.Count > 0)
                    {
                        bool thicknessFound = false;
                        string currentColliderName = "";
                        for (int i = 0; i < thicknessEnds.Count; i++)
                        {
                            currentColliderName = thicknessEnds.ElementAt(i).Value.collider.name;

                            if (thicknessStarts.ContainsKey(currentColliderName))
                            {
                                if (!thicknessFound)
                                {
                                    thickness = 0;
                                    thicknessFound = true;
                                }
                                thickness += (thicknessStarts[currentColliderName].point - thicknessEnds[currentColliderName].point).magnitude;
                            }
                            else
                            {
                                thickness = float.MaxValue;
                            }
                        }
                    }
                }

                if (cameraNormalMode)
                {
                    if (thickness > maxThickness)
                    {
                        distance = Mathf.Clamp(occlusionHit.Value.distance, 0, desiredDistance);
                        transform.position = occlusionHit.Value.point + occlusionHit.Value.normal.normalized * collisionDistance;
                    }
                    else
                        transform.position = transform.rotation * new Vector3(0, 0, -distance) + offsetVectorTransformed + target.position;
                }
            }
            else if (cameraNormalMode)
            {
                transform.position = transform.rotation * new Vector3(0, 0, -distance) + offsetVectorTransformed + target.position;
            }

            // smart pivot mode collision check
            if (smartPivot && (!cameraNormalMode))
            {
                Vector3 tmpEuler = transform.rotation.eulerAngles;
                tmpEuler.x = startingY;

                dirToTargetSmartPivot = (Quaternion.Euler(tmpEuler) * new Vector3(0, 0, -distance) + offsetVectorTransformed + target.position) - targetPosWithOffset;

                if (Physics.SphereCast(targetPosWithOffset, collisionDistance, dirToTargetSmartPivot.normalized, out hitSmartPivot, dirToTargetSmartPivot.magnitude + collisionDistance, collisionLayer))
                {
                    Vector3 v1 = hitSmartPivot.point - targetPosWithOffset;
                    float dot = Vector3.Dot(v1, dirToTargetSmartPivot) / dirToTargetSmartPivot.magnitude;

                    Vector3 v2 = (dirToTargetSmartPivot.normalized * dot) - (dirToTargetSmartPivot.normalized * collisionDistance);

                    Vector3 newAlignVector = Vector3.zero;
                    if (v2.magnitude < dirToTargetSmartPivot.magnitude)
                        newAlignVector = v2;
                    else
                        newAlignVector = dirToTargetSmartPivot;

                    if (dot > 0.1f)
                    {
                        if ((transform.position - targetPosWithOffset).magnitude + zoomOutStepValuePerFrame < newAlignVector.magnitude)
                        {
                            transform.position += newAlignVector.normalized * zoomOutStepValuePerFrame;
                        }
                        else
                        {
                            transform.position = targetPosWithOffset + newAlignVector;
                        }
                    }
                }
                else
                {
                    // no clipping, transition to max distance
                    if ((transform.position - targetPosWithOffset).magnitude + zoomOutStepValuePerFrame < dirToTargetSmartPivot.magnitude)
                    {
                        transform.position += dirToTargetSmartPivot.normalized * zoomOutStepValuePerFrame;
                    }
                }
            }

            prevTargetPos = target.position;
            prevPosition = transform.position;
        }
        void Update()
        {
            if (!initDone)
            {
                return;
            }

            if (distance < 0)
            {
                distance = 0;
            }

            // disable player character when too close
            if (smrs != null)
            {
                if (playerCollision || distance <= collisionDistance)
                {
                    for (int i = 0; i < smrs.Length; i++)
                    {
                        smrs[i].enabled = false;
                    }
                }
                else
                {
                    for (int i = 0; i < smrs.Length; i++)
                    {
                        smrs[i].enabled = true;
                    }
                }
            }

            if ((cameraNormalMode || !smartPivot))
            {
                if (distance <= desiredDistance)
                {
                    distance += zoomOutStepValuePerFrame;
                }
                if (distance >= desiredDistance)
                {
                    distance -= zoomOutStepValuePerFrame;
                }
            }

            Vector3 offsetVectorTransformed = target.transform.rotation * offsetVector;

            transform.position += (target.position - prevTargetPos);
            targetPosWithOffset = (target.position + offsetVectorTransformed);

            Vector3 dirToTargetOffset = targetPosWithOffset - target.position;

            if (Physics.SphereCast(target.position, collisionDistance, dirToTargetOffset, out offsetTest, dirToTargetOffset.magnitude + collisionDistance, collisionLayer))
            {
                // offset clips into geometry, move the offset
                float newDistance = offsetTest.distance - collisionDistance - 0.1f;
                targetPosWithOffset = (target.position + offsetVectorTransformed.normalized * newDistance);
            }

            dirToTarget = (transform.rotation * new Vector3(0, 0, -distance) + offsetVectorTransformed + target.position) - targetPosWithOffset;
            float cameraToPlayerDistance = Mathf.Min(dirToTarget.magnitude, desiredDistance);

            dirToTarget = dirToTarget.normalized;

            RaycastHit[] hits = Physics.SphereCastAll(targetPosWithOffset, collisionDistance, dirToTarget, cameraToPlayerDistance, collisionLayer);

            if (hits.Length > 0)
            {
                rcms = new List <RayCastWithMags>(hits.Length);

                for (int i = 0; i < hits.Length; i++)
                {
                    RayCastWithMags rcm = new RayCastWithMags();

                    rcm.hit = hits[i];
                    rcm.distanceFromCamera = (prevPosition - hits[i].point).magnitude;
                    rcm.distanceFromTarget = (targetPosWithOffset - hits[i].point).magnitude;

                    rcms.Add(rcm);
                }

                rcms = rcms.OrderBy(m => m.distanceFromTarget).ToList();
                float lowestMagn = rcms[0].distanceFromTarget;

                for (int i = rcms.Count - 1; i >= 0; i--)
                {
                    if (rcms[i].distanceFromTarget > lowestMagn + collisionDistance * 2)
                    {
                        rcms.RemoveAt(i);
                    }
                }

                rcms = rcms.OrderBy(m => m.distanceFromCamera).ToList();

                if (rcms[0].hit.distance > 0)
                {
                    occlusionHit = rcms[0].hit;
                }
            }
            else
            {
                occlusionHit = null;
            }

            // Cast ground target to activate smartPivot
            if ((smartPivot && occlusionHit != null) || bGroundHit) // needs a small distance offset
            {
                if (Physics.Raycast(prevPosition, Vector3.down, out groundHit, collisionDistance + 0.1f) && groundHit.transform.gameObject.layer != playerLayer)
                {
                    bGroundHit = true;
                }
                else
                {
                    bGroundHit = false;
                }
            }
            else if (occlusionHit == null && cameraNormalMode)
            {
                bGroundHit = false;
            }

            // Avoid that the character is not visible
            if (occlusionCheck && occlusionHit != null)
            {
                thickness = float.MaxValue;

                if (thicknessCheck && cameraNormalMode)
                {
                    currentIterations = 0;
                    thicknessStarts.Clear();
                    thicknessEnds.Clear();

                    Vector3 dirToHit = (transform.position - targetPosWithOffset).normalized;

                    Vector3 hitVector    = (targetPosWithOffset - occlusionHit.Value.point);
                    Vector3 targetVector = targetPosWithOffset - transform.position;

                    float   dotProd      = Vector3.Dot(hitVector, targetVector) / targetVector.magnitude;
                    Vector3 unknownPoint = occlusionHit.Value.point + targetVector.normalized * dotProd;

                    thicknessStartPoint = unknownPoint + dirToHit * (cameraToPlayerDistance + collisionDistance);
                    thicknessEndPoint   = unknownPoint;

                    float length = cameraToPlayerDistance;

                    while (Physics.SphereCast(thicknessEndPoint, collisionDistance, dirToHit, out thicknessHit, length, collisionLayer) && currentIterations < maxThicknessIterations)
                    {
                        length           -= (thicknessEndPoint - thicknessHit.point).magnitude - 0.00001f;
                        thicknessEndPoint = thicknessHit.point + dirToTarget * 0.00001f;
                        if (!thicknessEnds.ContainsKey(thicknessHit.collider.name))
                        {
                            thicknessEnds.Add(thicknessHit.collider.name, thicknessHit); //TODO: fix multiple keys issue
                        }
                        currentIterations++;
                    }

                    currentIterations = 0;
                    length            = cameraToPlayerDistance;

                    while (Physics.SphereCast(thicknessStartPoint, collisionDistance, -dirToHit, out thicknessHit, length, collisionLayer) && currentIterations < maxThicknessIterations)
                    {
                        length -= (thicknessStartPoint - thicknessHit.point).magnitude - 0.00001f;
                        thicknessStartPoint = thicknessHit.point - dirToTarget * 0.00001f;

                        if (!thicknessStarts.ContainsKey(thicknessHit.collider.name))
                        {
                            thicknessStarts.Add(thicknessHit.collider.name, thicknessHit);
                        }

                        currentIterations++;
                    }

                    if (thicknessEnds.Count > 0 && thicknessStarts.Count > 0)
                    {
                        bool   thicknessFound      = false;
                        string currentColliderName = "";
                        for (int i = 0; i < thicknessEnds.Count; i++)
                        {
                            currentColliderName = thicknessEnds.ElementAt(i).Value.collider.name;

                            if (thicknessStarts.ContainsKey(currentColliderName))
                            {
                                if (!thicknessFound)
                                {
                                    thickness      = 0;
                                    thicknessFound = true;
                                }
                                thickness += (thicknessStarts[currentColliderName].point - thicknessEnds[currentColliderName].point).magnitude;
                            }
                            else
                            {
                                thickness = float.MaxValue;
                            }
                        }
                    }
                }

                if (cameraNormalMode)
                {
                    if (thickness > maxThickness)
                    {
                        distance           = Mathf.Clamp(occlusionHit.Value.distance, 0, desiredDistance);
                        transform.position = occlusionHit.Value.point + occlusionHit.Value.normal.normalized * collisionDistance;
                    }
                    else
                    {
                        transform.position = transform.rotation * new Vector3(0, 0, -distance) + offsetVectorTransformed + target.position;
                    }
                }
            }
            else if (cameraNormalMode)
            {
                transform.position = transform.rotation * new Vector3(0, 0, -distance) + offsetVectorTransformed + target.position;
            }



            // smart pivot mode collision check
            if (smartPivot && (!cameraNormalMode))
            {
                Vector3 tmpEuler = transform.rotation.eulerAngles;
                tmpEuler.x = startingY;

                dirToTargetSmartPivot = (Quaternion.Euler(tmpEuler) * new Vector3(0, 0, -distance) + offsetVectorTransformed + target.position) - targetPosWithOffset;

                if (Physics.SphereCast(targetPosWithOffset, collisionDistance, dirToTargetSmartPivot.normalized, out hitSmartPivot, dirToTargetSmartPivot.magnitude + collisionDistance, collisionLayer))
                {
                    Vector3 v1  = hitSmartPivot.point - targetPosWithOffset;
                    float   dot = Vector3.Dot(v1, dirToTargetSmartPivot) / dirToTargetSmartPivot.magnitude;

                    Vector3 v2 = (dirToTargetSmartPivot.normalized * dot) - (dirToTargetSmartPivot.normalized * collisionDistance);

                    Vector3 newAlignVector = Vector3.zero;
                    if (v2.magnitude < dirToTargetSmartPivot.magnitude)
                    {
                        newAlignVector = v2;
                    }
                    else
                    {
                        newAlignVector = dirToTargetSmartPivot;
                    }

                    if (dot > 0.1f)
                    {
                        if ((transform.position - targetPosWithOffset).magnitude + zoomOutStepValuePerFrame < newAlignVector.magnitude)
                        {
                            transform.position += newAlignVector.normalized * zoomOutStepValuePerFrame;
                        }
                        else
                        {
                            transform.position = targetPosWithOffset + newAlignVector;
                        }
                    }
                }
                else
                {
                    // no clipping, transition to max distance
                    if ((transform.position - targetPosWithOffset).magnitude + zoomOutStepValuePerFrame < dirToTargetSmartPivot.magnitude)
                    {
                        transform.position += dirToTargetSmartPivot.normalized * zoomOutStepValuePerFrame;
                    }
                }
            }

            prevTargetPos = target.position;
            prevPosition  = transform.position;
        }