private PokeInteractable ComputeBestHoverInteractable() { PokeInteractable closestInteractable = null; float closestSqrDist = float.MaxValue; IEnumerable <PokeInteractable> interactables = PokeInteractable.Registry.List(this); // We check that we're above the surface first as we don't // care about hovers that originate below the surface foreach (PokeInteractable interactable in interactables) { if (!PassesEnterHoverDistanceCheck(interactable)) { continue; } Vector3 closestSurfacePoint = interactable.ClosestSurfacePoint(Origin); Vector3 closestSurfaceNormal = interactable.ClosestSurfaceNormal(Origin); Vector3 surfaceToPoint = Origin - closestSurfacePoint; float magnitude = surfaceToPoint.magnitude; if (magnitude != 0f) { // Check if our position is above the surface if (Vector3.Dot(surfaceToPoint, closestSurfaceNormal) > 0f) { // Check if our position lies outside of the optional volume mask if (interactable.VolumeMask != null && !Collisions.IsPointWithinCollider(Origin, interactable.VolumeMask)) { continue; } // We're above the surface so now we must rank this // interactable versus others that also pass this test this frame // but may be at a closer proximity. Vector3 closestPoint = interactable.ComputeClosestPoint(Origin); float sqrDistanceFromPoint = (closestPoint - Origin).sqrMagnitude; if (sqrDistanceFromPoint > interactable.MaxDistance * interactable.MaxDistance) { continue; } if (sqrDistanceFromPoint < closestSqrDist) { closestSqrDist = sqrDistanceFromPoint; closestInteractable = interactable; ClosestPoint = closestPoint; TouchPoint = ClosestPoint; } } } } return(closestInteractable); }
public Pose GetGrabSourceForTarget(Pose target) { if (_grabSource == null && !_useClosestPointAsGrabSource) { return(target); } if (_useClosestPointAsGrabSource) { return(new Pose( Collisions.ClosestPointToColliders(target.position, _colliders), target.rotation)); } return(_grabSource.GetPose()); }
protected override GrabInteractable ComputeCandidate() { GrabInteractable closestInteractable = null; float bestScore = float.NegativeInfinity; float score = bestScore; IEnumerable <GrabInteractable> interactables = GrabInteractable.Registry.List(this); foreach (GrabInteractable interactable in interactables) { Collider[] colliders = interactable.Colliders; foreach (Collider collider in colliders) { if (Collisions.IsPointWithinCollider(Rigidbody.transform.position, collider)) { // Points within a collider are always weighted better than those outside float sqrDistanceFromCenter = (Rigidbody.transform.position - collider.bounds.center).magnitude; score = float.MaxValue - sqrDistanceFromCenter; } else { var position = Rigidbody.transform.position; Vector3 closestPointOnInteractable = collider.ClosestPoint(position); score = -1f * (position - closestPointOnInteractable).magnitude; } if (score > bestScore) { bestScore = score; closestInteractable = interactable; } } } BestInteractableWeight = bestScore; return(closestInteractable); }
public static Vector3 ClosestPointToColliders(Vector3 point, Collider[] colliders) { Vector3 closestPoint = point; float closestDistance = float.MaxValue; foreach (Collider collider in colliders) { if (Collisions.IsPointWithinCollider(point, collider)) { return(point); } Vector3 closest = collider.ClosestPoint(point); float distance = (closest - point).magnitude; if (distance < closestDistance) { closestDistance = distance; closestPoint = closest; } } return(closestPoint); }
private PokeInteractable ComputeSelectCandidate() { PokeInteractable closestInteractable = null; float closestSqrDist = float.MaxValue; IEnumerable <PokeInteractable> interactables = PokeInteractable.Registry.List(this); Vector3 moveDirection = Origin - _previousOrigin; float magnitude = moveDirection.magnitude; if (magnitude == 0f) { return(null); } moveDirection /= magnitude; Ray ray = new Ray(_previousOrigin, moveDirection); // Check the surface first as a movement through this will // automatically put us in a "active" state. We expect the raycast // to happen only in one direction foreach (PokeInteractable interactable in interactables) { if (!PassesEnterHoverDistanceCheck(interactable)) { continue; } Vector3 closestSurfaceNormal = interactable.ClosestSurfaceNormal(Origin); // First check that we are moving towards the surface by checking // the direction of our position delta with the forward direction of the surface normal. // This is to not allow presses from "behind" the surface. // Check if we are moving toward the surface if (Vector3.Dot(moveDirection, closestSurfaceNormal) < 0f) { // Then do a raycast against the surface bool hit = interactable.Surface.Raycast(ray, out SurfaceHit surfaceHit); if (hit && surfaceHit.Distance <= magnitude) { // We collided against the surface and now we must rank this // interactable versus others that also pass this test this frame // but may be at a closer proximity. For this we use the closest // point compute against the surface intersection point // Check if our collision lies outside of the optional volume mask if (interactable.VolumeMask != null && !Collisions.IsPointWithinCollider(surfaceHit.Point, interactable.VolumeMask)) { continue; } Vector3 closestPointToHitPoint = interactable.ComputeClosestPoint(surfaceHit.Point); float sqrDistanceFromPoint = (closestPointToHitPoint - surfaceHit.Point).sqrMagnitude; if (sqrDistanceFromPoint > interactable.MaxDistance * interactable.MaxDistance) { continue; } if (sqrDistanceFromPoint < closestSqrDist) { closestSqrDist = sqrDistanceFromPoint; closestInteractable = interactable; ClosestPoint = closestPointToHitPoint; TouchPoint = ClosestPoint; } } } } return(closestInteractable); }