private static void UpdatePointerRayOnHit(RayStep[] raySteps, RaycastHit physicsHit, int hitRayIndex, float rayStartDistance, PointerHitResult hitResult) { var origin = raySteps[hitRayIndex].Origin; var terminus = physicsHit.point; raySteps[hitRayIndex].UpdateRayStep(ref origin, ref terminus); hitResult.Set(physicsHit, raySteps[hitRayIndex], hitRayIndex, rayStartDistance + physicsHit.distance); }
/// <summary> /// Perform a Unity Graphics Raycast to determine which uGUI element is currently being gazed at, if any. /// </summary> /// <param name="pointer"></param> /// <param name="graphicEventData"></param> /// <param name="prioritizedLayerMasks"></param> /// <param name="hitResult"></param> private void RaycastGraphics(IMixedRealityPointer pointer, PointerEventData graphicEventData, LayerMask[] prioritizedLayerMasks, PointerHitResult hitResult) { if (UIRaycastCamera == null) { Debug.LogError("Missing UIRaycastCamera!"); return; } if (!uiRaycastCamera.nearClipPlane.Equals(0.01f)) { uiRaycastCamera.nearClipPlane = 0.01f; } if (pointer.Rays == null) { Debug.LogError($"No valid rays for {pointer.PointerName} pointer."); return; } if (pointer.Rays.Length <= 0) { Debug.LogError($"No valid rays for {pointer.PointerName} pointer"); return; } // Cast rays for every step until we score a hit float totalDistance = 0.0f; for (int i = 0; i < pointer.Rays.Length; i++) { if (RaycastGraphicsStep(graphicEventData, pointer.Rays[i], prioritizedLayerMasks, out var raycastResult) && raycastResult.isValid && raycastResult.distance < pointer.Rays[i].Length && raycastResult.module != null && raycastResult.module.eventCamera == UIRaycastCamera) { totalDistance += raycastResult.distance; newUiRaycastPosition.x = raycastResult.screenPosition.x; newUiRaycastPosition.y = raycastResult.screenPosition.y; newUiRaycastPosition.z = raycastResult.distance; var worldPos = uiRaycastCamera.ScreenToWorldPoint(newUiRaycastPosition); var normal = -raycastResult.gameObject.transform.forward; hitResult.Set(raycastResult, worldPos, normal, pointer.Rays[i], i, totalDistance); return; } totalDistance += pointer.Rays[i].Length; } }
/// <summary> /// Perform a Unity Graphics Raycast to determine which uGUI element is currently being pointed at, if any. /// </summary> private void RaycastGraphics(IMixedRealityPointer pointer, PointerEventData graphicEventData, LayerMask[] prioritizedLayerMasks, PointerHitResult hit) { Debug.Assert(UIRaycastCamera != null, "Missing UIRaycastCamera!"); Debug.Assert(UIRaycastCamera.nearClipPlane == 0, "Near plane must be zero for raycast distances to be correct"); RaycastResult raycastResult = default(RaycastResult); if (pointer.Rays == null) { Debug.LogError($"No valid rays for {pointer.PointerName} pointer."); return; } if (pointer.Rays.Length <= 0) { Debug.LogError($"No valid rays for {pointer.PointerName} pointer"); return; } // Cast rays for every step until we score a hit float totalDistance = 0.0f; for (int i = 0; i < pointer.Rays.Length; i++) { if (RaycastGraphicsStep(graphicEventData, pointer.Rays[i], prioritizedLayerMasks, out raycastResult)) { if (raycastResult.isValid && raycastResult.distance < pointer.Rays[i].Length && raycastResult.module != null && raycastResult.module.eventCamera == UIRaycastCamera) { totalDistance += raycastResult.distance; newUiRaycastPosition.x = raycastResult.screenPosition.x; newUiRaycastPosition.y = raycastResult.screenPosition.y; newUiRaycastPosition.z = raycastResult.distance; Vector3 worldPos = UIRaycastCamera.ScreenToWorldPoint(newUiRaycastPosition); Vector3 normal = -raycastResult.gameObject.transform.forward; hit.Set(raycastResult, worldPos, normal, pointer.Rays[i], i, totalDistance); return; } } totalDistance += pointer.Rays[i].Length; } }
/// <summary> /// Perform a scene query to determine which scene objects with a collider is currently being gazed at, if any. /// </summary> /// <param name="pointerData"></param> /// <param name="prioritizedLayerMasks"></param> private static void QueryScene(IMixedRealityPointer pointer, LayerMask[] prioritizedLayerMasks, PointerHitResult hit) { float rayStartDistance = 0; RaycastHit physicsHit; RayStep[] pointerRays = pointer.Rays; if (pointerRays == null) { Debug.LogError($"No valid rays for {pointer.PointerName} pointer."); return; } if (pointerRays.Length <= 0) { Debug.LogError($"No valid rays for {pointer.PointerName} pointer"); return; } // Perform query for each step in the pointing source for (int i = 0; i < pointerRays.Length; i++) { switch (pointer.SceneQueryType) { case SceneQueryType.SimpleRaycast: if (MixedRealityRaycaster.RaycastSimplePhysicsStep(pointerRays[i], prioritizedLayerMasks, out physicsHit)) { UpdatePointerRayOnHit(pointerRays, physicsHit, i, rayStartDistance, hit); return; } break; case SceneQueryType.BoxRaycast: Debug.LogWarning("Box Raycasting Mode not supported for pointers."); break; case SceneQueryType.SphereCast: if (MixedRealityRaycaster.RaycastSpherePhysicsStep(pointerRays[i], pointer.SphereCastRadius, prioritizedLayerMasks, out physicsHit)) { UpdatePointerRayOnHit(pointerRays, physicsHit, i, rayStartDistance, hit); return; } break; case SceneQueryType.SphereOverlap: Collider[] colliders = UnityEngine.Physics.OverlapSphere(pointer.Rays[i].Origin, pointer.SphereCastRadius, ~UnityEngine.Physics.IgnoreRaycastLayer); if (colliders.Length > 0) { Vector3 testPoint = pointer.Rays[i].Origin; GameObject closest = null; float closestDistance = Mathf.Infinity; Vector3 objectHitPoint = testPoint; foreach (Collider collider in colliders) { // Policy: in order for an collider to be near interactable it must have // a NearInteractionGrabbable component on it. // FIXME: This is assuming only the grab pointer is using SceneQueryType.SphereOverlap, // but there may be other pointers using the same query type which have different semantics. if (collider.GetComponent <NearInteractionGrabbable>() == null) { continue; } // From https://docs.unity3d.com/ScriptReference/Collider.ClosestPoint.html // If location is in the collider the closestPoint will be inside. Vector3 closestPointToCollider = collider.ClosestPoint(testPoint); float distance = (testPoint - closestPointToCollider).sqrMagnitude; if (distance < closestDistance) { closestDistance = distance; closest = collider.gameObject; objectHitPoint = closestPointToCollider; } } if (closest != null) { hit.Set(closest, objectHitPoint, Vector3.zero, pointer.Rays[i], 0, closestDistance); return; } } break; default: Debug.LogError($"Invalid raycast mode {pointer.SceneQueryType} for {pointer.PointerName} pointer."); break; } rayStartDistance += pointer.Rays[i].Length; } }