VcamExtraState GetExtraState(ICinemachineCamera vcam) { if (mExtraState == null) { mExtraState = new Dictionary <ICinemachineCamera, VcamExtraState>(); } VcamExtraState extra = null; if (!mExtraState.TryGetValue(vcam, out extra)) { extra = mExtraState[vcam] = new VcamExtraState(); } if (extra.filter == null || extra.filter.Sigma != m_PositionSmoothing) { extra.filter = new GaussianWindow1D_Vector3(m_PositionSmoothing); } if (!m_UseCurbFeelers) { extra.curbFeelers = null; } else if (extra.curbFeelers == null || extra.curbFeelers.Length != 9 || extra.curbResistance != m_CurbResistance || extra.feelerDistance != m_CurbFeelerDistance) { extra.RebuildCurbFeelers(m_CurbResistance, m_CurbFeelerDistance); } return(extra); }
/// <summary>Callback to to the camera confining</summary> protected override void PostPipelineStageCallback( CinemachineVirtualCameraBase vcam, CinemachineCore.Stage stage, ref CameraState state, float deltaTime) { if (IsValid) { // Move the body before the Aim is calculated if (stage == CinemachineCore.Stage.Body) { Vector3 displacement; if (m_ConfineScreenEdges && state.Lens.Orthographic) { displacement = ConfineScreenEdges(vcam, ref state); } else { displacement = ConfinePoint(state.CorrectedPosition); } VcamExtraState extra = GetExtraState <VcamExtraState>(vcam); if (m_Damping > 0 && deltaTime >= 0) { Vector3 delta = displacement - extra.m_previousDisplacement; delta = Damper.Damp(delta, m_Damping, deltaTime); displacement = extra.m_previousDisplacement + delta; } extra.m_previousDisplacement = displacement; state.PositionCorrection += displacement; extra.confinerDisplacement = displacement.magnitude; } } }
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 void PostPipelineStageCallback( CinemachineVirtualCameraBase vcam, CinemachineCore.Stage stage, ref CameraState state, float deltaTime) { if (enabled && m_BoundingVolume != null) { // Move the body before the Aim is calculated if (stage == CinemachineCore.Stage.Body) { Vector3 camPos = state.CorrectedPosition; Vector3 closest = m_BoundingVolume.ClosestPoint(camPos); Vector3 dir = closest - camPos; float distance = dir.magnitude; if (distance > Epsilon) { dir /= distance; } Vector3 displacement = distance * dir; VcamExtraState extra = GetExtraState(vcam); if (m_Damping > 0 && deltaTime > 0) { Vector3 delta = displacement - extra.m_previousDisplacement; if (Mathf.Abs(delta.magnitude) > Epsilon) { delta *= deltaTime / Mathf.Max(m_Damping * kDampingScale, deltaTime); } displacement = extra.m_previousDisplacement + delta; } extra.m_previousDisplacement = displacement; state.PositionCorrection += displacement; extra.confinerDisplacement = displacement.magnitude; } } }
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); }
VcamExtraState GetExtraState(ICinemachineCamera vcam) { if (mExtraState == null) { mExtraState = new Dictionary <ICinemachineCamera, VcamExtraState>(); } VcamExtraState extra = null; if (!mExtraState.TryGetValue(vcam, out extra)) { extra = mExtraState[vcam] = new VcamExtraState(); } return(extra); }
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); }
private bool PreserveLignOfSight(ref CameraState state, VcamExtraState extra) { bool displaced = false; if (state.HasLookAt) { Vector3 lookAtPos = state.ReferenceLookAt; Vector3 pos = state.CorrectedPosition; Vector3 dir = lookAtPos - pos; float targetDistance = dir.magnitude; float minDistanceFromTarget = Mathf.Max(m_MinimumDistanceFromTarget, UnityVectorExtensions.Epsilon); if (targetDistance > minDistanceFromTarget) { dir.Normalize(); float rayFar = targetDistance - minDistanceFromTarget; if (m_LineOfSightFeelerDistance > UnityVectorExtensions.Epsilon) { rayFar = Mathf.Min(m_LineOfSightFeelerDistance, rayFar); } // Make a ray that looks towards the camera, to get the most distant obstruction Ray ray = new Ray(pos + rayFar * dir, -dir); int raycastLayerMask = m_CollideAgainst.value; float rayLength = rayFar - Mathf.Max(0, m_MinimumDistanceFromCamera); if (rayLength > Mathf.Epsilon) { RaycastHit hitInfo; if (Physics.Raycast(ray, out hitInfo, rayLength, raycastLayerMask)) { float adjustment = hitInfo.distance; if (m_UseCurbFeelers) { adjustment -= MinCurbDistance; } pos = ray.GetPoint(adjustment); Vector3 displacement = pos - state.CorrectedPosition; state.PositionCorrection += displacement; extra.colliderDisplacement += displacement.magnitude; displaced = true; } } } } return(displaced); }
VcamExtraState GetExtraState(ICinemachineCamera vcam) { if (mExtraState == null) { mExtraState = new Dictionary <ICinemachineCamera, VcamExtraState>(); } VcamExtraState extra = null; if (!mExtraState.TryGetValue(vcam, out extra)) { extra = mExtraState[vcam] = new VcamExtraState(); } if (extra.filter == null || extra.filter.Sigma != m_Smoothing) { extra.filter = new GaussianWindow1D_Vector3(m_Smoothing); } return(extra); }
private bool ApplyCurbFeelers(ref CameraState state, VcamExtraState extra) { bool displaced = false; Vector3 pos = state.CorrectedPosition; Quaternion orientation = state.CorrectedOrientation; RaycastHit hitInfo; int raycastLayerMask = m_CollideAgainst.value; Ray feelerRay = new Ray(); int numHits = 0; Vector3 resultingPosition = Vector3.zero; for (int i = 0; i < extra.curbFeelers.Length; ++i) { CompiledCurbFeeler feeler = extra.curbFeelers[i]; feelerRay.origin = pos; feelerRay.direction = orientation * feeler.LocalVector; if (Physics.Raycast(feelerRay, out hitInfo, feeler.RayDistance, raycastLayerMask)) { float compressionPercent = Mathf.Clamp01((feeler.RayDistance - hitInfo.distance) / feeler.RayDistance); compressionPercent = 1f - Mathf.Pow(compressionPercent, feeler.DampingConstant); resultingPosition += hitInfo.point - feelerRay.direction * (compressionPercent * feeler.RayDistance); feeler.IsHit = true; feeler.HitDistance = hitInfo.distance; numHits++; } else { feeler.IsHit = false; feeler.HitDistance = float.MaxValue; } extra.curbFeelers[i] = feeler; } // Average the resulting positions if feelers hit anything if (numHits > 0) { Vector3 displacement = (resultingPosition / (float)numHits) - state.CorrectedPosition; extra.colliderDisplacement += displacement.magnitude; state.PositionCorrection += displacement; displaced = true; } return(displaced); }
protected override void PostPipelineStageCallback( CinemachineVirtualCameraBase vcam, CinemachineCore.Stage stage, ref CameraState state, float deltaTime) { if (enabled) { if (stage == CinemachineCore.Stage.Body) { VcamExtraState extra = GetExtraState <VcamExtraState>(vcam); if (m_PositionSmoothing > 0) { if (deltaTime < 0) { extra.mSmoothingFilter = null; // reset the filter } state.PositionCorrection += ApplySmoothing(vcam, state.CorrectedPosition, extra) - state.CorrectedPosition; } if (m_LookAtSmoothing > 0 && state.HasLookAt) { if (deltaTime < 0) { extra.mSmoothingFilterLookAt = null; // reset the filter } state.ReferenceLookAt = ApplySmoothingLookAt(vcam, state.ReferenceLookAt, extra); } } if (stage == CinemachineCore.Stage.Aim) { if (m_RotationSmoothing > 0) { VcamExtraState extra = GetExtraState <VcamExtraState>(vcam); if (deltaTime < 0) { extra.mSmoothingFilterRotation = null; // reset the filter } Quaternion q = Quaternion.Inverse(state.CorrectedOrientation) * ApplySmoothing(vcam, state.CorrectedOrientation, state.ReferenceUp, extra); state.OrientationCorrection = state.OrientationCorrection * q; } } } }
protected override void PostPipelineStageCallback( CinemachineVirtualCameraBase vcam, CinemachineCore.Stage stage, ref CameraState state, float deltaTime) { VcamExtraState extra = GetExtraState <VcamExtraState>(vcam); if (!enabled || deltaTime < 0) { extra.m_previousFrameZoom = state.Lens.FieldOfView; } if (enabled) { // Set the zoom after the body has been positioned, but before the aim, // so that composer can compose using the updated fov. if (stage == CinemachineCore.Stage.Body) { // Try to reproduce the target width float targetWidth = Mathf.Max(m_Width, 0); float fov = 179f; float d = Vector3.Distance(state.CorrectedPosition, state.ReferenceLookAt); if (d > UnityVectorExtensions.Epsilon) { // Clamp targetWidth to FOV min/max float minW = d * 2f * Mathf.Tan(m_MinFOV * Mathf.Deg2Rad / 2f); float maxW = d * 2f * Mathf.Tan(m_MaxFOV * Mathf.Deg2Rad / 2f); targetWidth = Mathf.Clamp(targetWidth, minW, maxW); // Apply damping if (deltaTime >= 0 && m_Damping > 0) { float currentWidth = d * 2f * Mathf.Tan(extra.m_previousFrameZoom * Mathf.Deg2Rad / 2f); float delta = targetWidth - currentWidth; delta = Damper.Damp(delta, m_Damping, deltaTime); targetWidth = currentWidth + delta; } fov = 2f * Mathf.Atan(targetWidth / (2 * d)) * Mathf.Rad2Deg; } LensSettings lens = state.Lens; lens.FieldOfView = extra.m_previousFrameZoom = Mathf.Clamp(fov, m_MinFOV, m_MaxFOV); state.Lens = lens; } } }
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 void PostPipelineStageCallback( CinemachineVirtualCameraBase vcam, CinemachineCore.Stage stage, ref CameraState state, float deltaTime) { VcamExtraState extra = null; if (stage == CinemachineCore.Stage.Body) { extra = GetExtraState(vcam); extra.targetObscured = false; extra.colliderDisplacement = 0; } if (enabled) { // Move the body before the Aim is calculated if (stage == CinemachineCore.Stage.Body) { if (m_PreserveLineOfSight) { Vector3 displacement = PreserveLignOfSight(ref state); if (m_Smoothing > 0) { if (deltaTime > 0) { displacement = extra.filter.Filter(displacement); } else { extra.filter.Reset(); } } state.PositionCorrection += displacement; extra.colliderDisplacement += displacement.magnitude; } } // Rate the shot after the aim was set if (stage == CinemachineCore.Stage.Aim) { extra = GetExtraState(vcam); extra.targetObscured = CheckForTargetObstructions(state); // GML these values are an initial arbitrary attempt at rating quality if (extra.targetObscured) { state.ShotQuality *= 0.2f; } if (extra.colliderDisplacement > 0) { state.ShotQuality *= 0.8f; } float nearnessBoost = 0; const float kMaxNearBoost = 0.2f; if (m_OptimalTargetDistance > 0 && state.HasLookAt) { float distance = Vector3.Magnitude(state.ReferenceLookAt - state.FinalPosition); if (distance <= m_OptimalTargetDistance) { float threshold = m_OptimalTargetDistance / 2; if (distance >= threshold) { nearnessBoost = kMaxNearBoost * (distance - threshold) / (m_OptimalTargetDistance - threshold); } } else { distance -= m_OptimalTargetDistance; float threshold = m_OptimalTargetDistance * 3; if (distance < threshold) { nearnessBoost = kMaxNearBoost * (1f - (distance / threshold)); } } state.ShotQuality *= (1f + nearnessBoost); } } } }
/// <summary>Callback to do the collision resolution and shot evaluation</summary> protected override void PostPipelineStageCallback( CinemachineVirtualCameraBase vcam, CinemachineCore.Stage stage, ref CameraState state, float deltaTime) { VcamExtraState extra = null; if (stage == CinemachineCore.Stage.Body) { extra = GetExtraState <VcamExtraState>(vcam); extra.targetObscured = false; extra.colliderDisplacement = 0; if (extra.debugResolutionPath != null) { extra.debugResolutionPath.RemoveRange(0, extra.debugResolutionPath.Count); } } // Move the body before the Aim is calculated if (stage == CinemachineCore.Stage.Body) { if (m_AvoidObstacles) { Vector3 displacement = Vector3.zero; displacement = PreserveLignOfSight(ref state, ref extra); if (m_MinimumOcclusionTime > Epsilon) { float now = Time.timeSinceLevelLoad; if (displacement.sqrMagnitude < Epsilon) { extra.occlusionStartTime = 0; } else { if (extra.occlusionStartTime <= 0) { extra.occlusionStartTime = now; } if (now - extra.occlusionStartTime < m_MinimumOcclusionTime) { displacement = extra.m_previousDisplacement; } } } float damping = m_Damping; if (displacement.AlmostZero()) { extra.ResetDistanceSmoothing(m_SmoothingTime); } else { damping = m_DampingWhenOccluded; } if (damping > 0 && deltaTime >= 0) { Vector3 delta = displacement - extra.m_previousDisplacement; delta = Damper.Damp(delta, damping, deltaTime); displacement = extra.m_previousDisplacement + delta; } extra.m_previousDisplacement = displacement; Vector3 correction = RespectCameraRadius(state.CorrectedPosition + displacement, ref state); if (damping > 0 && deltaTime >= 0) { Vector3 delta = correction - extra.m_previousDisplacementCorrection; delta = Damper.Damp(delta, damping, deltaTime); correction = extra.m_previousDisplacementCorrection + delta; } displacement += correction; extra.m_previousDisplacementCorrection = correction; state.PositionCorrection += displacement; extra.colliderDisplacement += displacement.magnitude; } } // Rate the shot after the aim was set if (stage == CinemachineCore.Stage.Aim) { extra = GetExtraState <VcamExtraState>(vcam); extra.targetObscured = IsTargetOffscreen(state) || CheckForTargetObstructions(state); // GML these values are an initial arbitrary attempt at rating quality if (extra.targetObscured) { state.ShotQuality *= 0.2f; } if (extra.colliderDisplacement > 0) { state.ShotQuality *= 0.8f; } float nearnessBoost = 0; const float kMaxNearBoost = 0.2f; if (m_OptimalTargetDistance > 0 && state.HasLookAt) { float distance = Vector3.Magnitude(state.ReferenceLookAt - state.FinalPosition); if (distance <= m_OptimalTargetDistance) { float threshold = m_OptimalTargetDistance / 2; if (distance >= threshold) { nearnessBoost = kMaxNearBoost * (distance - threshold) / (m_OptimalTargetDistance - threshold); } } else { distance -= m_OptimalTargetDistance; float threshold = m_OptimalTargetDistance * 3; if (distance < threshold) { nearnessBoost = kMaxNearBoost * (1f - (distance / threshold)); } } state.ShotQuality *= (1f + nearnessBoost); } } }
private void PostPipelineStageCallback( CinemachineVirtualCameraBase vcam, CinemachineCore.Stage stage, ref CameraState state, CameraState previousState, float deltaTime) { VcamExtraState extra = null; if (stage == CinemachineCore.Stage.Body) { extra = GetExtraState(vcam); extra.targetObscured = false; extra.colliderDisplacement = 0; if (extra.colliderDisplacementDecay > 0) { --extra.colliderDisplacementDecay; // decay the displacement to accommodate the filter } } if (enabled) { // Move the body before the Aim is calculated if (stage == CinemachineCore.Stage.Body) { if (m_PreserveLineOfSight) { PreserveLignOfSight(ref state, extra); } if (m_UseCurbFeelers && m_CurbFeelerDistance > UnityVectorExtensions.Epsilon) { ApplyCurbFeelers(ref state, extra); } if (extra.colliderDisplacement > 0.1f) { extra.colliderDisplacementDecay = extra.filter.KernelSize + 1; } // Apply the smoothing filter Vector3 pos = state.CorrectedPosition; if (m_PositionSmoothing > 0) { state.PositionCorrection += extra.filter.Filter(pos) - pos; } } // Rate the shot after the aim was set if (stage == CinemachineCore.Stage.Aim) { extra = GetExtraState(vcam); extra.targetObscured = CheckForTargetObstructions(state); // GML these values are an initial arbitrary attempt at rating quality if (extra.targetObscured) { state.ShotQuality *= 0.2f; } if (extra.colliderDisplacementDecay > 0) { state.ShotQuality *= 0.8f; } float nearnessBoost = 0; const float kMaxNearBoost = 0.2f; if (m_OptimalTargetDistance > 0 && state.HasLookAt) { float distance = Vector3.Magnitude(state.ReferenceLookAt - state.FinalPosition); if (distance <= m_OptimalTargetDistance) { float threshold = m_OptimalTargetDistance / 2; if (distance >= threshold) { nearnessBoost = kMaxNearBoost * (distance - threshold) / (m_OptimalTargetDistance - threshold); } } else { distance -= m_OptimalTargetDistance; float threshold = m_OptimalTargetDistance * 3; if (distance < threshold) { nearnessBoost = kMaxNearBoost * (1f - (distance / threshold)); } } state.ShotQuality *= (1f + nearnessBoost); } } } }
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); }
/// <summary>Callcack to to the collision resolution and shot evaluation</summary> protected override void PostPipelineStageCallback( CinemachineVirtualCameraBase vcam, CinemachineCore.Stage stage, ref CameraState state, float deltaTime) { VcamExtraState extra = null; if (stage == CinemachineCore.Stage.Body) { extra = GetExtraState <VcamExtraState>(vcam); extra.targetObscured = false; extra.colliderDisplacement = 0; extra.debugResolutionPath = null; } // Move the body before the Aim is calculated if (stage == CinemachineCore.Stage.Body) { if (m_AvoidObstacles) { var displacement = PreserveLignOfSight(ref state, ref extra); if (m_Damping > 0 && deltaTime >= 0) { var delta = displacement - extra.m_previousDisplacement; delta = Damper.Damp(delta, m_Damping, deltaTime); displacement = extra.m_previousDisplacement + delta; } extra.m_previousDisplacement = displacement; state.PositionCorrection += displacement; extra.colliderDisplacement += displacement.magnitude; } } // Rate the shot after the aim was set if (stage == CinemachineCore.Stage.Aim) { extra = GetExtraState <VcamExtraState>(vcam); extra.targetObscured = CheckForTargetObstructions(state); // GML these values are an initial arbitrary attempt at rating quality if (extra.targetObscured) { state.ShotQuality *= 0.2f; } if (extra.colliderDisplacement > 0) { state.ShotQuality *= 0.8f; } float nearnessBoost = 0; const float kMaxNearBoost = 0.2f; if (m_OptimalTargetDistance > 0 && state.HasLookAt) { var distance = Vector3.Magnitude(state.ReferenceLookAt - state.FinalPosition); if (distance <= m_OptimalTargetDistance) { var threshold = m_OptimalTargetDistance / 2; if (distance >= threshold) { nearnessBoost = kMaxNearBoost * (distance - threshold) / (m_OptimalTargetDistance - threshold); } } else { distance -= m_OptimalTargetDistance; var threshold = m_OptimalTargetDistance * 3; if (distance < threshold) { nearnessBoost = kMaxNearBoost * (1f - distance / threshold); } } state.ShotQuality *= 1f + nearnessBoost; } } }
private Vector3 ApplySmoothingLookAt(CinemachineVirtualCameraBase vcam, Vector3 pos, VcamExtraState extra) { if (extra.mSmoothingFilterLookAt == null || extra.mSmoothingFilterLookAt.Sigma != m_LookAtSmoothing) { extra.mSmoothingFilterLookAt = new GaussianWindow1D_Vector3(m_LookAtSmoothing); } return(extra.mSmoothingFilterLookAt.Filter(pos)); }
private Quaternion ApplySmoothing(CinemachineVirtualCameraBase vcam, Quaternion rot, Vector3 up, VcamExtraState extra) { if (extra.mSmoothingFilterRotation == null || extra.mSmoothingFilterRotation.Sigma != m_RotationSmoothing) { extra.mSmoothingFilterRotation = new GaussianWindow1D_CameraRotation(m_RotationSmoothing); } Vector3 camRot = Quaternion.identity.GetCameraRotationToTarget(rot * Vector3.forward, up); return(Quaternion.identity.ApplyCameraRotation(extra.mSmoothingFilterRotation.Filter(camRot), up)); }
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); }