public static bool GetAimTarget(out RaycastHit hit, Vector2 minMax, Vector3 source, Transform aim, LayerMask layerMask, string m_IgnoreTag) { var aimPos = aim.position; var aimForward = aim.forward; //var pos = source.position; var posDist = Vector3.Distance(aimPos, source); aimPos += aimForward * posDist; Debug.DrawLine(aim.position, aimPos, Color.red); //hit.point = aimPos + (aimForward * minMax.y); Ray ray = new Ray(aimPos, aimForward); if (RuntimeUtility.RaycastIgnoreTag(ray, out hit, minMax.y, layerMask, m_IgnoreTag)) { //target = hit.point; Debug.DrawLine(aimPos, hit.point, Color.green); } else if (Physics.Raycast(aimPos + (aimForward * minMax.y), Vector3.down, out hit, minMax.y, layerMask, QueryTriggerInteraction.Ignore)) { Debug.DrawLine(aimPos, hit.point, Color.yellow); //target = hit.point; } else { hit.point = aimPos + (aimForward * minMax.y); return(false); } var dist = Vector3.Distance(source, hit.point); return(dist > minMax.x); }
public bool GetTarget(out Vector3 target, float min, float max, Transform source, Transform aim, out Transform lockon) { lockon = null; var aimPos = aim.transform.position; var aimForward = aim.transform.forward; var pos = source.position; var posDist = Vector3.Distance(aimPos, pos); aimPos += aimForward * posDist; RaycastHit hit; target = aimPos + (aimForward * max); if (RuntimeUtility.SphereCastIgnoreTag(aimPos, targetRadius, cam.forward, out hit, max, targetLayerMask, m_IgnoreTag)) { var heading = hit.point - aimPos; Ray headinRay = new Ray(aimPos, heading.normalized); if (RuntimeUtility.RaycastIgnoreTag(headinRay, out hit, max, layerMask, m_IgnoreTag)) { target = hit.point; if ((targetLayerMask & 1 << hit.collider.gameObject.layer) == 1 << hit.collider.gameObject.layer) { if (hit.collider.TryGetComponent(out Animator animator) && animator.isHuman) { lockon = animator.GetBoneTransform(HumanBodyBones.Head); target = lockon.position; } } } } if (!lockon) { Ray ray = new Ray(aimPos, cam.forward); if (RuntimeUtility.RaycastIgnoreTag(ray, out hit, max, layerMask, m_IgnoreTag)) { target = hit.point; if ((targetLayerMask & 1 << hit.collider.gameObject.layer) == 1 << hit.collider.gameObject.layer) { if (hit.collider.TryGetComponent(out Animator animator) && animator.isHuman) { lockon = animator.GetBoneTransform(HumanBodyBones.Head); target = lockon.position; } } } else if (Physics.Raycast(aimPos + (cam.forward * max), Vector3.down, out hit, max, layerMask, QueryTriggerInteraction.Ignore)) { target = hit.point; } } var dist = Vector3.Distance(aimPos, target); return(dist > min); }
private Vector3 PullCameraInFrontOfNearestObstacle( Vector3 cameraPos, Vector3 lookAtPos, int layerMask, ref RaycastHit hitInfo) { Vector3 displacement = Vector3.zero; Vector3 dir = cameraPos - lookAtPos; float targetDistance = dir.magnitude; if (_cinemachineCameraOffset) { targetDistance -= _cinemachineCameraOffset.m_Offset.z; } 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 += 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 - PrecisionSlush); displacement = ray.GetPoint(adjustment) - cameraPos; } } } } return(displacement); }
private 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); RaycastHit hitInfo; if (RuntimeUtility.RaycastIgnoreTag(ray, out hitInfo, distance - m_MinimumDistanceFromTarget, m_CollideAgainst & ~m_TransparentLayers, m_IgnoreTag)) { return(true); } } return(false); }
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); }
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 (RuntimeUtility.RaycastIgnoreTag(ray, out hitInfo, distance, m_CollideAgainst & ~m_TransparentLayers, m_IgnoreTag)) { // 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; RaycastHit hitInfo2; if (d < Epsilon || RuntimeUtility.RaycastIgnoreTag( new Ray(lookAtPos, dir), out hitInfo2, d - 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 - 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); }