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); }
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); }
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); }