Vector3 GetLookAtPoint(ref CameraState state)
        {
            var fwd         = state.CorrectedOrientation * Vector3.forward;
            var camPos      = state.CorrectedPosition;
            var aimDistance = AimDistance;

            // We don't want to hit targets behind the player
            var player = VirtualCamera.Follow;

            if (player != null)
            {
                var playerPos = Quaternion.Inverse(state.CorrectedOrientation) * (player.position - camPos);
                if (playerPos.z > 0)
                {
                    camPos      += fwd * playerPos.z;
                    aimDistance -= playerPos.z;
                }
            }

            aimDistance = Mathf.Max(1, aimDistance);
            bool hasHit = RuntimeUtility.RaycastIgnoreTag(
                new Ray(camPos, fwd),
                out RaycastHit hitInfo, aimDistance, AimCollisionFilter, IgnoreTag);

            return(hasHit ? hitInfo.point : camPos + fwd * aimDistance);
        }
示例#2
0
        Vector3 GetLookAtPoint(ref CameraState state)
        {
            var  fwd    = state.CorrectedOrientation * Vector3.forward;
            var  camPos = state.CorrectedPosition;
            bool hasHit = RuntimeUtility.RaycastIgnoreTag(
                new Ray(camPos, fwd),
                out RaycastHit hitInfo, AimDistance, AimCollisionFilter, IgnoreTag);

            return(hasHit ? hitInfo.point : camPos + fwd * AimDistance);
        }
        Vector3 ComputeAimTarget(Vector3 cameraLookAt, Transform player)
        {
            // Adjust for actual player aim target (may be different due to offset)
            var playerPos = player.position;
            var dir       = cameraLookAt - playerPos;

            if (RuntimeUtility.RaycastIgnoreTag(new Ray(playerPos, dir),
                                                out RaycastHit hitInfo, dir.magnitude, AimCollisionFilter, IgnoreTag))
            {
                return(hitInfo.point);
            }
            return(cameraLookAt);
        }
        Vector3 ComputeLookAtPoint(Vector3 camPos, Transform player)
        {
            // We don't want to hit targets behind the player
            var aimDistance       = AimDistance;
            var playerOrientation = player.rotation;
            var fwd       = playerOrientation * Vector3.forward;
            var playerPos = Quaternion.Inverse(playerOrientation) * (player.position - camPos);

            if (playerPos.z > 0)
            {
                camPos      += fwd * playerPos.z;
                aimDistance -= playerPos.z;
            }

            aimDistance = Mathf.Max(1, aimDistance);
            bool hasHit = RuntimeUtility.RaycastIgnoreTag(new Ray(camPos, fwd),
                                                          out RaycastHit hitInfo, aimDistance, AimCollisionFilter, IgnoreTag);

            return(hasHit ? hitInfo.point : camPos + fwd * aimDistance);
        }
        Vector3 PullCameraInFrontOfNearestObstacle(
            Vector3 cameraPos, Vector3 lookAtPos, int layerMask, ref RaycastHit hitInfo)
        {
            Vector3 displacement   = Vector3.zero;
            Vector3 dir            = cameraPos - lookAtPos;
            float   targetDistance = dir.magnitude;

            if (targetDistance > Epsilon)
            {
                dir /= targetDistance;
                float minDistanceFromTarget = Mathf.Max(m_MinimumDistanceFromTarget, Epsilon);
                if (targetDistance < minDistanceFromTarget + Epsilon)
                {
                    displacement = dir * (minDistanceFromTarget - targetDistance);
                }
                else
                {
                    float rayLength = targetDistance - minDistanceFromTarget;
                    if (m_DistanceLimit > Epsilon)
                    {
                        rayLength = Mathf.Min(m_DistanceLimit, rayLength);
                    }

                    // Make a ray that looks towards the camera, to get the obstacle closest to target
                    Ray ray = new Ray(cameraPos - rayLength * dir, dir);
                    rayLength += k_PrecisionSlush;
                    if (rayLength > Epsilon)
                    {
                        if (RuntimeUtility.RaycastIgnoreTag(
                                ray, out hitInfo, rayLength, layerMask, m_IgnoreTag))
                        {
                            // Pull camera forward in front of obstacle
                            float adjustment = Mathf.Max(0, hitInfo.distance - k_PrecisionSlush);
                            displacement = ray.GetPoint(adjustment) - cameraPos;
                        }
                    }
                }
            }
            return(displacement);
        }
 bool CheckForTargetObstructions(CameraState state)
 {
     if (state.HasLookAt)
     {
         Vector3 lookAtPos = state.ReferenceLookAt;
         Vector3 pos       = state.CorrectedPosition;
         Vector3 dir       = lookAtPos - pos;
         float   distance  = dir.magnitude;
         if (distance < Mathf.Max(m_MinimumDistanceFromTarget, Epsilon))
         {
             return(true);
         }
         Ray ray = new Ray(pos, dir.normalized);
         if (RuntimeUtility.RaycastIgnoreTag(ray, out _,
                                             distance - m_MinimumDistanceFromTarget,
                                             m_CollideAgainst & ~m_TransparentLayers, m_IgnoreTag))
         {
             return(true);
         }
     }
     return(false);
 }
示例#7
0
 void DrawReticle(CinemachineBrain brain)
 {
     if (!brain.IsLive(VirtualCamera) || brain.OutputCamera == null)
     {
         CinemachineCore.CameraUpdatedEvent.RemoveListener(DrawReticle);
     }
     else
     {
         var player = VirtualCamera.Follow;
         if (AimTargetReticle != null && player != null)
         {
             // Adjust for actual player aim target (may be different due to offset)
             var playerPos = player.position;
             var aimTarget = VirtualCamera.State.ReferenceLookAt;
             var dir       = aimTarget - playerPos;
             if (RuntimeUtility.RaycastIgnoreTag(new Ray(playerPos, dir),
                                                 out RaycastHit hitInfo, dir.magnitude, AimCollisionFilter, IgnoreTag))
             {
                 aimTarget = hitInfo.point;
             }
             AimTargetReticle.position = brain.OutputCamera.WorldToScreenPoint(aimTarget);
         }
     }
 }
        Vector3 RespectCameraRadius(Vector3 cameraPos, Vector3 lookAtPos)
        {
            Vector3 result = Vector3.zero;

            if (m_CameraRadius < Epsilon || m_CollideAgainst == 0)
            {
                return(result);
            }

            Vector3 dir      = cameraPos - lookAtPos;
            float   distance = dir.magnitude;

            if (distance > Epsilon)
            {
                dir /= distance;
            }

            // Pull it out of any intersecting obstacles
            RaycastHit hitInfo;
            int        numObstacles = Physics.OverlapSphereNonAlloc(
                cameraPos, m_CameraRadius, s_ColliderBuffer,
                m_CollideAgainst, QueryTriggerInteraction.Ignore);

            if (numObstacles == 0 && m_TransparentLayers != 0 &&
                distance > m_MinimumDistanceFromTarget + Epsilon)
            {
                // Make sure the camera position isn't completely inside an obstacle.
                // OverlapSphereNonAlloc won't catch those.
                float   d         = distance - m_MinimumDistanceFromTarget;
                Vector3 targetPos = lookAtPos + dir * m_MinimumDistanceFromTarget;
                if (RuntimeUtility.RaycastIgnoreTag(new Ray(targetPos, dir),
                                                    out hitInfo, d, m_CollideAgainst, m_IgnoreTag))
                {
                    // Only count it if there's an incoming collision but not an outgoing one
                    Collider c = hitInfo.collider;
                    if (!c.Raycast(new Ray(cameraPos, -dir), out hitInfo, d))
                    {
                        s_ColliderBuffer[numObstacles++] = c;
                    }
                }
            }
            if (numObstacles > 0 && distance == 0 || distance > m_MinimumDistanceFromTarget)
            {
                var scratchCollider = RuntimeUtility.GetScratchCollider();
                scratchCollider.radius = m_CameraRadius;

                Vector3 newCamPos = cameraPos;
                for (int i = 0; i < numObstacles; ++i)
                {
                    Collider c = s_ColliderBuffer[i];
                    if (m_IgnoreTag.Length > 0 && c.CompareTag(m_IgnoreTag))
                    {
                        continue;
                    }

                    // If we have a lookAt target, move the camera to the nearest edge of obstacle
                    if (distance > m_MinimumDistanceFromTarget)
                    {
                        dir = newCamPos - lookAtPos;
                        float d = dir.magnitude;
                        if (d > Epsilon)
                        {
                            dir /= d;
                            var ray = new Ray(lookAtPos, dir);
                            if (c.Raycast(ray, out hitInfo, d + m_CameraRadius))
                            {
                                newCamPos = ray.GetPoint(hitInfo.distance) - (dir * k_PrecisionSlush);
                            }
                        }
                    }
                    if (Physics.ComputePenetration(
                            scratchCollider, newCamPos, Quaternion.identity,
                            c, c.transform.position, c.transform.rotation,
                            out var offsetDir, out var offsetDistance))
                    {
                        newCamPos += offsetDir * offsetDistance;
                    }
                }
                result = newCamPos - cameraPos;
            }

            // Respect the minimum distance from target - push camera back if we have to
            if (distance > Epsilon && m_MinimumDistanceFromTarget > Epsilon)
            {
                float   minDistance = Mathf.Max(m_MinimumDistanceFromTarget, m_CameraRadius) + k_PrecisionSlush;
                Vector3 newOffset   = cameraPos + result - lookAtPos;
                if (newOffset.magnitude < minDistance)
                {
                    result = lookAtPos - cameraPos + dir * minDistance;
                }
            }

            return(result);
        }
        Vector3 PushCameraBack(
            Vector3 currentPos, Vector3 pushDir, RaycastHit obstacle,
            Vector3 lookAtPos, Plane startPlane, float targetDistance, int iterations,
            ref VcamExtraState extra)
        {
            // Take a step along the wall.
            Vector3 pos = currentPos;
            Vector3 dir = Vector3.zero;

            if (!GetWalkingDirection(pos, pushDir, obstacle, ref dir))
            {
                return(pos);
            }

            Ray   ray      = new Ray(pos, dir);
            float distance = GetPushBackDistance(ray, startPlane, targetDistance, lookAtPos);

            if (distance <= Epsilon)
            {
                return(pos);
            }

            // Check only as far as the obstacle bounds
            float clampedDistance = ClampRayToBounds(ray, distance, obstacle.collider.bounds);

            distance = Mathf.Min(distance, clampedDistance + k_PrecisionSlush);

            if (RuntimeUtility.RaycastIgnoreTag(ray, out var hitInfo, distance,
                                                m_CollideAgainst & ~m_TransparentLayers, m_IgnoreTag))
            {
                // We hit something.  Stop there and take a step along that wall.
                float adjustment = hitInfo.distance - k_PrecisionSlush;
                pos = ray.GetPoint(adjustment);
                extra.AddPointToDebugPath(pos);
                if (iterations > 1)
                {
                    pos = PushCameraBack(
                        pos, dir, hitInfo,
                        lookAtPos, startPlane,
                        targetDistance, iterations - 1, ref extra);
                }

                return(pos);
            }

            // Didn't hit anything.  Can we push back all the way now?
            pos = ray.GetPoint(distance);

            // First check if we can still see the target.  If not, abort
            dir = pos - lookAtPos;
            float d = dir.magnitude;

            if (d < Epsilon || RuntimeUtility.RaycastIgnoreTag(
                    new Ray(lookAtPos, dir), out _, d - k_PrecisionSlush,
                    m_CollideAgainst & ~m_TransparentLayers, m_IgnoreTag))
            {
                return(currentPos);
            }

            // All clear
            ray = new Ray(pos, dir);
            extra.AddPointToDebugPath(pos);
            distance = GetPushBackDistance(ray, startPlane, targetDistance, lookAtPos);
            if (distance > Epsilon)
            {
                if (!RuntimeUtility.RaycastIgnoreTag(ray, out hitInfo, distance,
                                                     m_CollideAgainst & ~m_TransparentLayers, m_IgnoreTag))
                {
                    pos = ray.GetPoint(distance); // no obstacles - all good
                    extra.AddPointToDebugPath(pos);
                }
                else
                {
                    // We hit something.  Stop there and maybe take a step along that wall
                    float adjustment = hitInfo.distance - k_PrecisionSlush;
                    pos = ray.GetPoint(adjustment);
                    extra.AddPointToDebugPath(pos);
                    if (iterations > 1)
                    {
                        pos = PushCameraBack(
                            pos, dir, hitInfo, lookAtPos, startPlane,
                            targetDistance, iterations - 1, ref extra);
                    }
                }
            }
            return(pos);
        }
示例#10
0
        private Vector3 RespectCameraRadius(Vector3 cameraPos, ref CameraState state)
        {
            Vector3 result = Vector3.zero;

            if (m_CameraRadius < Epsilon || m_CollideAgainst == 0)
            {
                return(result);
            }

            Vector3 dir      = state.HasLookAt ? (cameraPos - state.ReferenceLookAt) : Vector3.zero;
            Ray     ray      = new Ray();
            float   distance = dir.magnitude;

            if (distance > Epsilon)
            {
                dir /= distance;
                ray  = new Ray(state.ReferenceLookAt, dir);
            }
            // Pull it out of any intersecting obstacles
            RaycastHit hitInfo;
            int        numObstacles = Physics.OverlapSphereNonAlloc(
                cameraPos, m_CameraRadius, mColliderBuffer,
                m_CollideAgainst, QueryTriggerInteraction.Ignore);

            if (numObstacles == 0 && m_TransparentLayers != 0 &&
                distance > m_MinimumDistanceFromTarget + Epsilon)
            {
                // Make sure the camera position isn't completely inside an obstacle.
                // OverlapSphereNonAlloc won't catch those.
                float   d         = distance - m_MinimumDistanceFromTarget;
                Vector3 targetPos = state.ReferenceLookAt + dir * m_MinimumDistanceFromTarget;
                if (RuntimeUtility.RaycastIgnoreTag(new Ray(targetPos, dir),
                                                    out hitInfo, d, m_CollideAgainst, m_IgnoreTag))
                {
                    // Only count it if there's an incoming collision but not an outgoing one
                    Collider c = hitInfo.collider;
                    if (!c.Raycast(new Ray(cameraPos, -dir), out hitInfo, d))
                    {
                        mColliderBuffer[numObstacles++] = c;
                    }
                }
            }
            if (numObstacles > 0 && distance == 0 || distance > m_MinimumDistanceFromTarget)
            {
                if (mCameraColliderGameObject == null)
                {
                    mCameraColliderGameObject                    = new GameObject("CinemachineCollider Collider");
                    mCameraColliderGameObject.hideFlags          = HideFlags.HideAndDontSave;
                    mCameraColliderGameObject.transform.position = Vector3.zero;
                    mCameraColliderGameObject.SetActive(true);
                    mCameraCollider           = mCameraColliderGameObject.AddComponent <SphereCollider>();
                    mCameraCollider.isTrigger = true;
                    var rb = mCameraColliderGameObject.AddComponent <Rigidbody>();
                    rb.detectCollisions = false;
                    rb.isKinematic      = true;
                }
                mCameraCollider.radius = m_CameraRadius;
                Vector3 offsetDir;
                float   offsetDistance;
                Vector3 newCamPos = cameraPos;
                for (int i = 0; i < numObstacles; ++i)
                {
                    Collider c = mColliderBuffer[i];
                    if (m_IgnoreTag.Length > 0 && c.CompareTag(m_IgnoreTag))
                    {
                        continue;
                    }

                    // If we have a lookAt target, move the camera to the nearest edge of obstacle
                    if (distance > m_MinimumDistanceFromTarget)
                    {
                        dir = newCamPos - state.ReferenceLookAt;
                        float d = dir.magnitude;
                        if (d > Epsilon)
                        {
                            dir /= d;
                            ray  = new Ray(state.ReferenceLookAt, dir);
                            if (c.Raycast(ray, out hitInfo, d + m_CameraRadius))
                            {
                                newCamPos = ray.GetPoint(hitInfo.distance) - (dir * PrecisionSlush);
                            }
                        }
                    }
                    if (Physics.ComputePenetration(
                            mCameraCollider, newCamPos, Quaternion.identity,
                            c, c.transform.position, c.transform.rotation,
                            out offsetDir, out offsetDistance))
                    {
                        newCamPos += offsetDir * offsetDistance;
                    }
                }
                result = newCamPos - cameraPos;
            }

            // Respect the minimum distance from target - push camera back if we have to
            if (distance > Epsilon)
            {
                float   minDistance = Mathf.Max(m_MinimumDistanceFromTarget, m_CameraRadius) + PrecisionSlush;
                Vector3 newOffset   = cameraPos + result - state.ReferenceLookAt;
                if (newOffset.magnitude < minDistance)
                {
                    result = state.ReferenceLookAt - cameraPos + dir * minDistance;
                }
            }

            return(result);
        }