Vector3 PreserveLineOfSight(ref CameraState state, ref VcamExtraState extra)
        {
            Vector3 displacement = Vector3.zero;

            if (state.HasLookAt && m_CollideAgainst != 0 &&
                m_CollideAgainst != m_TransparentLayers)
            {
                Vector3    cameraPos = state.CorrectedPosition;
                Vector3    lookAtPos = state.ReferenceLookAt;
                RaycastHit hitInfo   = new RaycastHit();
                displacement = PullCameraInFrontOfNearestObstacle(
                    cameraPos, lookAtPos, m_CollideAgainst & ~m_TransparentLayers, ref hitInfo);
                Vector3 pos = cameraPos + displacement;
                if (hitInfo.collider != null)
                {
                    extra.AddPointToDebugPath(pos);
                    if (m_Strategy != ResolutionStrategy.PullCameraForward)
                    {
                        Vector3 targetToCamera = cameraPos - lookAtPos;
                        pos = PushCameraBack(
                            pos, targetToCamera, hitInfo, lookAtPos,
                            new Plane(state.ReferenceUp, cameraPos),
                            targetToCamera.magnitude, m_MaximumEffort, ref extra);
                    }
                }
                displacement = pos - cameraPos;
            }
            return(displacement);
        }
        private Vector3 PreserveLignOfSight(ref CameraState state, ref VcamExtraState extra)
        {
            var displacement = Vector3.zero;

            if (state.HasLookAt)
            {
                var cameraPos             = state.CorrectedPosition;
                var lookAtPos             = state.ReferenceLookAt;
                var pos                   = cameraPos;
                var dir                   = pos - lookAtPos;
                var targetDistance        = dir.magnitude;
                var minDistanceFromTarget = Mathf.Max(m_MinimumDistanceFromTarget, Epsilon);
                if (targetDistance > minDistanceFromTarget)
                {
                    dir.Normalize();
                    var rayLength = targetDistance - minDistanceFromTarget;
                    if (m_DistanceLimit > Epsilon)
                    {
                        rayLength = Mathf.Min(m_DistanceLimit, rayLength);
                    }

                    // Make a ray that looks towards the camera, to get the most distant obstruction
                    var ray = new Ray(pos - rayLength * dir, dir);
                    rayLength += PrecisionSlush;
                    if (rayLength > Epsilon)
                    {
                        RaycastHit hitInfo;
                        if (RaycastIgnoreTag(ray, out hitInfo, rayLength))
                        {
                            // Pull camera forward in front of obstacle
                            var adjustment = Mathf.Max(0, hitInfo.distance - PrecisionSlush);
                            pos = ray.GetPoint(adjustment);
                            extra.AddPointToDebugPath(pos);
                            if (m_Strategy != ResolutionStrategy.PullCameraForward)
                            {
                                pos = PushCameraBack(
                                    pos, dir, hitInfo, lookAtPos,
                                    new Plane(state.ReferenceUp, cameraPos),
                                    targetDistance, m_MaximumEffort, ref extra);
                            }
                        }
                    }
                }

                if (m_CameraRadius > Epsilon)
                {
                    pos += RespectCameraRadius(pos, state.ReferenceLookAt);
                }
                else if (mCameraColliderGameObject != null)
                {
                    CleanupCameraCollider();
                }
                displacement = pos - cameraPos;
            }

            return(displacement);
        }
예제 #3
0
        private Vector3 PreserveLignOfSight(ref CameraState state, ref VcamExtraState extra)
        {
            Vector3 displacement = Vector3.zero;

            if (state.HasLookAt && m_CollideAgainst != 0 &&
                m_CollideAgainst != m_TransparentLayers)
            {
                Vector3    cameraPos = state.CorrectedPosition;
                Vector3    lookAtPos = state.ReferenceLookAt;
                RaycastHit hitInfo   = new RaycastHit();
                displacement = PullCameraInFrontOfNearestObstacle(
                    cameraPos, lookAtPos, m_CollideAgainst & ~m_TransparentLayers, ref hitInfo);
                Vector3 pos = cameraPos + displacement;
                if (hitInfo.collider != null)
                {
                    extra.AddPointToDebugPath(pos);
                    if (m_Strategy != ResolutionStrategy.PullCameraForward)
                    {
                        Vector3 targetToCamera = cameraPos - lookAtPos;
                        pos = PushCameraBack(
                            pos, targetToCamera, hitInfo, lookAtPos,
                            new Plane(state.ReferenceUp, cameraPos),
                            targetToCamera.magnitude, m_MaximumEffort, ref extra);
                    }
                }
                displacement = pos - cameraPos;

                // Apply distance smoothing
                if (m_SmoothingTime > Epsilon)
                {
                    Vector3 dir      = pos - lookAtPos;
                    float   distance = dir.magnitude;
                    if (distance > Epsilon)
                    {
                        dir /= distance;
                        if (!displacement.AlmostZero())
                        {
                            extra.UpdateDistanceSmoothing(distance, m_SmoothingTime);
                        }
                        distance      = extra.ApplyDistanceSmoothing(distance, m_SmoothingTime);
                        displacement += (state.ReferenceLookAt + dir * distance) - pos;
                    }
                }
            }
            return(displacement);
        }
        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);
        }
        private 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 + PrecisionSlush);

            RaycastHit hitInfo;

            if (Physics.Raycast(ray, out hitInfo, distance, m_CollideAgainst.value))
            {
                // We hit something.  Stop there and take a step along that wall.
                float adjustment = hitInfo.distance - 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 = lookAtPos - pos;
            float      d = dir.magnitude - m_MinimumDistanceFromTarget;
            RaycastHit hitInfo2;

            if (d < Epsilon || Physics.Raycast(
                    new Ray(pos, dir), out hitInfo2, d, m_CollideAgainst.value,
                    QueryTriggerInteraction.Ignore))
            {
                return(currentPos);
            }

            // All clear
            extra.AddPointToDebugPath(pos);
            dir      = pos - lookAtPos;
            ray      = new Ray(pos, dir);
            distance = GetPushBackDistance(ray, startPlane, targetDistance, lookAtPos);
            if (distance > Epsilon)
            {
                if (!Physics.Raycast(
                        ray, out hitInfo, distance, m_CollideAgainst.value,
                        QueryTriggerInteraction.Ignore))
                {
                    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 - 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);
        }
예제 #6
0
        private 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 + PrecisionSlush);

            RaycastHit hitInfo;

            if (RaycastIgnoreTag(ray, out hitInfo, distance,
                                 m_CollideAgainst & ~m_TransparentLayers))
            {
                // We hit something.  Stop there and take a step along that wall.
                float adjustment = hitInfo.distance - 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 (m_MinDistanceNearTarget != 0  && distance != 0 && d < m_MinDistanceNearTarget)
            //{
            //    Vector3 hitToTarget = lookAtPos - currentPos;
            //    float hd = hitToTarget.magnitude;
            //    Vector3 planeDir = Vector3.ProjectOnPlane(hitToTarget, obstacle.normal);
            //    float pd = planeDir.magnitude;
            //    distance = Mathf.Sqrt(m_MinimumDistanceFromTarget * m_MinimumDistanceFromTarget - (hd * hd - pd * pd)) - pd;
            //    pos = ray.GetPoint(distance);
            //    dir = pos - lookAtPos;
            //    d = dir.magnitude;
            //}

            RaycastHit hitInfo2;

            if (d < Epsilon || RaycastIgnoreTag(
                    new Ray(lookAtPos, dir), out hitInfo2, d - PrecisionSlush,
                    m_CollideAgainst & ~m_TransparentLayers))
            {
                return(currentPos);
            }

            // All clear
            ray = new Ray(pos, dir);
            extra.AddPointToDebugPath(pos);
            distance = GetPushBackDistance(ray, startPlane, targetDistance, lookAtPos);
            if (distance > Epsilon)
            {
                if (!RaycastIgnoreTag(ray, out hitInfo, distance,
                                      m_CollideAgainst & ~m_TransparentLayers))
                {
                    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 - 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);
        }