private void SphereRaycastStepUpdate(RayStep rayStep) { bool isHit; float scaleOverride = ScaleOverride; // Do the cast! float size = scaleOverride > 0 ? scaleOverride : transform.lossyScale.x * sphereSize; isHit = MixedRealityRaycaster.RaycastSpherePhysicsStep(rayStep, size, maxDistance, magneticSurfaces, out RaycastHit result); OnSurface = isHit; // Enforce CloseDistance Vector3 hitDelta = result.point - rayStep.Origin; float length = hitDelta.magnitude; if (length < closeDistance) { result.point = rayStep.Origin + rayStep.Direction * closeDistance; } // Apply results if (isHit) { GoalPosition = result.point + surfaceNormalOffset * result.normal + surfaceRayOffset * rayStep.Direction; GoalRotation = CalculateMagnetismOrientation(rayStep.Direction, result.normal); } }
private void BoxRaycastStepUpdate(RayStep rayStep) { Vector3 scale = transform.lossyScale; float scaleOverride = ScaleOverride; if (scaleOverride > 0) { scale = scale.normalized * scaleOverride; } Quaternion orientation = orientationMode == OrientModeEnum.None ? Quaternion.LookRotation(rayStep.Direction, Vector3.up) : CalculateMagnetismOrientation(rayStep.Direction, Vector3.up); Matrix4x4 targetMatrix = Matrix4x4.TRS(Vector3.zero, orientation, scale); if (boxCollider == null) { boxCollider = GetComponent <BoxCollider>(); } Debug.Assert(boxCollider != null, $"Missing a box collider for Surface Magnetism on {gameObject}"); Vector3 extents = boxCollider.size; if (MixedRealityRaycaster.RaycastBoxPhysicsStep(rayStep, extents, transform.position, targetMatrix, maxDistance, magneticSurfaces, boxRaysPerEdge, orthographicBoxCast, out Vector3[] positions, out Vector3[] normals, out bool[] hits))
/// <inheritdoc /> public bool Raycast(RayStep step, LayerMask[] prioritizedLayerMasks, bool focusIndividualCompoundCollider, out MixedRealityRaycastHit hitInfo) { bool result = MixedRealityRaycaster.RaycastSimplePhysicsStep(step, step.Length, prioritizedLayerMasks, focusIndividualCompoundCollider, out RaycastHit physicsHit); hitInfo = new MixedRealityRaycastHit(result, physicsHit); return(result); }
/// <inheritdoc /> public bool SphereCast(RayStep step, float radius, LayerMask[] prioritizedLayerMasks, bool focusIndividualCompoundCollider, out MixedRealityRaycastHit hitInfo) { var result = MixedRealityRaycaster.RaycastSpherePhysicsStep(step, radius, step.Length, prioritizedLayerMasks, focusIndividualCompoundCollider, out RaycastHit physicsHit); hitInfo = new MixedRealityRaycastHit(result, physicsHit); return(result); }
/// <summary> /// Calculate solver for simple raycast with provided ray /// </summary> /// <param name="rayStep">start/end ray passed by read-only reference to avoid struct-copy performance</param> private void SimpleRaycastStepUpdate(ref RayStep rayStep) { bool isHit; RaycastHit result; // Do the cast! isHit = MixedRealityRaycaster.RaycastSimplePhysicsStep(rayStep, maxRaycastDistance, magneticSurfaces, false, out result); OnSurface = isHit; // Enforce CloseDistance Vector3 hitDelta = result.point - rayStep.Origin; float length = hitDelta.magnitude; if (length < closestDistance) { result.point = rayStep.Origin + rayStep.Direction * closestDistance; } // Apply results if (isHit) { GoalPosition = result.point + surfaceNormalOffset * result.normal + surfaceRayOffset * rayStep.Direction; GoalRotation = CalculateMagnetismOrientation(rayStep.Direction, result.normal); } }
/// <summary> /// Perform a Unity physics Raycast to determine which scene objects with a collider is currently being gazed at, if any. /// </summary> /// <param name="pointer"></param> /// <param name="prioritizedLayerMasks"></param> private static void RaycastPhysics(PointerData pointer, LayerMask[] prioritizedLayerMasks) { bool isHit = false; int rayStepIndex = 0; RayStep rayStep = default(RayStep); RaycastHit physicsHit = default(RaycastHit); Debug.Assert(pointer.Pointer.Rays != null, "No valid rays for pointer"); Debug.Assert(pointer.Pointer.Rays.Length > 0, "No valid rays for pointer"); // Check raycast for each step in the pointing source for (int i = 0; i < pointer.Pointer.Rays.Length; i++) { switch (pointer.Pointer.RaycastMode) { case RaycastModeType.Simple: if (MixedRealityRaycaster.RaycastSimplePhysicsStep(pointer.Pointer.Rays[i], prioritizedLayerMasks, out physicsHit)) { // Set the pointer source's origin ray to this step isHit = true; rayStep = pointer.Pointer.Rays[i]; rayStepIndex = i; } break; case RaycastModeType.Box: Debug.LogWarning("Box Raycasting Mode not supported for pointers."); break; case RaycastModeType.Sphere: if (MixedRealityRaycaster.RaycastSpherePhysicsStep(pointer.Pointer.Rays[i], pointer.Pointer.SphereCastRadius, prioritizedLayerMasks, out physicsHit)) { // Set the pointer source's origin ray to this step isHit = true; rayStep = pointer.Pointer.Rays[i]; rayStepIndex = i; } break; default: throw new ArgumentOutOfRangeException(); } if (isHit) { break; } } if (isHit) { pointer.UpdateHit(physicsHit, rayStep, rayStepIndex); } else { pointer.UpdateHit(); } }
private void BoxRaycastStepUpdate(RayStep rayStep) { Vector3 scale = transform.lossyScale; float scaleOverride = ScaleOverride; if (scaleOverride > 0) { scale = scale.normalized * scaleOverride; } Quaternion orientation = orientationMode == OrientModeEnum.None ? Quaternion.LookRotation(rayStep.Direction, Vector3.up) : CalculateMagnetismOrientation(rayStep.Direction, Vector3.up); Matrix4x4 targetMatrix = Matrix4x4.TRS(Vector3.zero, orientation, scale); if (boxCollider == null) { boxCollider = GetComponent <BoxCollider>(); } Debug.Assert(boxCollider != null, $"Missing a box collider for Surface Magnetism on {gameObject}"); Vector3 extents = boxCollider.size; Vector3[] positions; Vector3[] normals; bool[] hits; if (MixedRealityRaycaster.RaycastBoxPhysicsStep(rayStep, extents, transform.position, targetMatrix, maxDistance, magneticSurfaces, boxRaysPerEdge, orthographicBoxCast, out positions, out normals, out hits)) { Plane plane; float distance; // Place an unconstrained plane down the ray. Don't use vertical constrain. FindPlacementPlane(rayStep.Origin, rayStep.Direction, positions, normals, hits, boxCollider.size.x, maximumNormalVariance, false, orientationMode == OrientModeEnum.None, out plane, out distance); // If placing on a horizontal surface, need to adjust the calculated distance by half the app height float verticalCorrectionOffset = 0; if (IsNormalVertical(plane.normal) && !Mathf.Approximately(rayStep.Direction.y, 0)) { float boxSurfaceVerticalOffset = targetMatrix.MultiplyVector(new Vector3(0, extents.y * 0.5f, 0)).magnitude; Vector3 correctionVector = boxSurfaceVerticalOffset * (rayStep.Direction / rayStep.Direction.y); verticalCorrectionOffset = -correctionVector.magnitude; } float boxSurfaceOffset = targetMatrix.MultiplyVector(new Vector3(0, 0, extents.z * 0.5f)).magnitude; // Apply boxSurfaceOffset to ray direction and not surface normal direction to reduce sliding GoalPosition = rayStep.Origin + rayStep.Direction * Mathf.Max(closeDistance, distance + surfaceRayOffset + boxSurfaceOffset + verticalCorrectionOffset) + plane.normal * (0 * boxSurfaceOffset + surfaceNormalOffset); GoalRotation = CalculateMagnetismOrientation(rayStep.Direction, plane.normal); OnSurface = true; } else { OnSurface = false; } }
/// <summary> /// Perform a Unity physics Raycast to determine which scene objects with a collider is currently being gazed at, if any. /// </summary> /// <param name="pointer"></param> /// <param name="prioritizedLayerMasks"></param> /// <param name="hitResult"></param> private static void RaycastPhysics(IMixedRealityPointer pointer, LayerMask[] prioritizedLayerMasks, PointerHitResult hitResult) { float rayStartDistance = 0; var 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; } // Check raycast for each step in the pointing source for (int i = 0; i < pointerRays.Length; i++) { switch (pointer.RaycastMode) { case RaycastMode.Simple: if (MixedRealityRaycaster.RaycastSimplePhysicsStep(pointerRays[i], prioritizedLayerMasks, out var simplePhysicsHit) && simplePhysicsHit.collider != pointer.NearInteractionCollider) { // Set the pointer source's origin ray to this step UpdatePointerRayOnHit(pointerRays, simplePhysicsHit, i, rayStartDistance, hitResult); return; } break; case RaycastMode.Box: // TODO box raycast mode Debug.LogWarning("Box Raycasting Mode not supported for pointers."); break; case RaycastMode.Sphere: if (MixedRealityRaycaster.RaycastSpherePhysicsStep(pointerRays[i], pointer.SphereCastRadius, prioritizedLayerMasks, out var spherePhysicsHit) && spherePhysicsHit.collider != pointer.NearInteractionCollider) { // Set the pointer source's origin ray to this step UpdatePointerRayOnHit(pointerRays, spherePhysicsHit, i, rayStartDistance, hitResult); return; } break; // TODO Sphere Overlap default: Debug.LogError($"Invalid raycast mode {pointer.RaycastMode} for {pointer.PointerName} pointer."); break; } rayStartDistance += pointer.Rays[i].Length; } }
/// <inheritdoc /> public bool SphereCast(RayStep step, float radius, LayerMask[] prioritizedLayerMasks, bool focusIndividualCompoundCollider, out MixedRealityRaycastHit hitInfo) { Profiler.BeginSample("[MRTK] DefaultRaycastProvider.SphereCast"); var result = MixedRealityRaycaster.RaycastSpherePhysicsStep(step, radius, step.Length, prioritizedLayerMasks, focusIndividualCompoundCollider, out RaycastHit physicsHit); hitInfo = new MixedRealityRaycastHit(result, physicsHit); Profiler.EndSample(); // SphereCast return(result); }
/// <summary> /// Perform a Unity physics Raycast 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 RaycastPhysics(PointerData pointerData, LayerMask[] prioritizedLayerMasks) { RayStep[] pointerRays = pointerData.Pointer.Rays; if (pointerRays == null) { Debug.LogError($"No valid rays for {pointerData.Pointer.PointerName} pointer."); return; } if (pointerRays.Length <= 0) { Debug.LogError($"No valid rays for {pointerData.Pointer.PointerName} pointer"); return; } // Check raycast for each step in the pointing source for (int i = 0; i < pointerRays.Length; i++) { RaycastHit physicsHit; switch (pointerData.Pointer.RaycastMode) { case RaycastMode.Simple: if (MixedRealityRaycaster.RaycastSimplePhysicsStep(pointerRays[i], prioritizedLayerMasks, out physicsHit)) { // Set the pointer source's origin ray to this step UpdatePointerRayOnHit(pointerData, pointerRays, in physicsHit, i); return; } break; case RaycastMode.Box: Debug.LogWarning("Box Raycasting Mode not supported for pointers."); break; case RaycastMode.Sphere: if (MixedRealityRaycaster.RaycastSpherePhysicsStep(pointerRays[i], pointerData.Pointer.SphereCastRadius, prioritizedLayerMasks, out physicsHit)) { // Set the pointer source's origin ray to this step UpdatePointerRayOnHit(pointerData, pointerRays, in physicsHit, i); return; } break; default: Debug.LogError($"Invalid raycast mode {pointerData.Pointer.RaycastMode} for {pointerData.Pointer.PointerName} pointer."); break; } } pointerData.UpdateHit(); }
private bool IsPointerRayHitSelf() { if (currentInputSource == null || currentPointer == null) { return(false); } if (currentPointer.Rays.Length > 0) { RaycastHit result; LayerMask[] magneticSurfaces = { UnityEngine.Physics.DefaultRaycastLayers }; if (MixedRealityRaycaster.RaycastSimplePhysicsStep(currentPointer.Rays[0], Mathf.Infinity, magneticSurfaces, out result)) { if (result.collider.gameObject == this.gameObject) { return(true); } } return(false); } return(false); }
public bool SphereCast( RayStep step, float radius, LayerMask[] prioritizedLayerMasks, bool focusIndividualCompoundCollider, out MixedRealityRaycastHit hitInfo) { // For now, this is just using the default behavior for sphere cast. // Leaving MapRenderer integration for a future change. var result = MixedRealityRaycaster.RaycastSpherePhysicsStep( step, radius, step.Length, prioritizedLayerMasks, focusIndividualCompoundCollider, out RaycastHit physicsHit); hitInfo = new MixedRealityRaycastHit(result, physicsHit); return(result); }
/// <summary> /// Perform a Unity physics Raycast 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 RaycastPhysics(PointerData pointerData, LayerMask[] prioritizedLayerMasks) { bool isHit = false; int rayStepIndex = 0; RayStep rayStep = default; RaycastHit physicsHit = default; if (pointerData.Pointer.Rays == null) { Debug.LogError($"No valid rays for {pointerData.Pointer.PointerName} pointer."); return; } if (pointerData.Pointer.Rays.Length <= 0) { Debug.LogError($"No valid rays for {pointerData.Pointer.PointerName} pointer"); return; } // Check raycast for each step in the pointing source for (int i = 0; i < pointerData.Pointer.Rays.Length; i++) { switch (pointerData.Pointer.RaycastMode) { case RaycastModeType.Simple: if (MixedRealityRaycaster.RaycastSimplePhysicsStep(pointerData.Pointer.Rays[i], prioritizedLayerMasks, out physicsHit)) { // Set the pointer source's origin ray to this step isHit = true; rayStep = pointerData.Pointer.Rays[i]; rayStepIndex = i; } break; case RaycastModeType.Box: Debug.LogWarning("Box Raycasting Mode not supported for pointers."); break; case RaycastModeType.Sphere: if (MixedRealityRaycaster.RaycastSpherePhysicsStep(pointerData.Pointer.Rays[i], pointerData.Pointer.SphereCastRadius, prioritizedLayerMasks, out physicsHit)) { // Set the pointer source's origin ray to this step isHit = true; rayStep = pointerData.Pointer.Rays[i]; rayStepIndex = i; } break; default: Debug.LogError($"Invalid raycast mode {pointerData.Pointer.RaycastMode} for {pointerData.Pointer.PointerName} pointer."); break; } if (isHit) { break; } } if (isHit) { pointerData.UpdateHit(physicsHit, rayStep, rayStepIndex); } else { pointerData.UpdateHit(); } }
/// <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; } }
public bool Raycast( RayStep step, LayerMask[] prioritizedLayerMasks, bool focusIndividualCompoundCollider, out MixedRealityRaycastHit hitInfo) { var hasPhysicsHit = MixedRealityRaycaster.RaycastSimplePhysicsStep( step, prioritizedLayerMasks, focusIndividualCompoundCollider, out RaycastHit physicsHit); MapRendererRaycastHit?closestMapHitInfo = null; MapRenderer closestMapRenderer = null; foreach (var mapRenderer in _mapRenderers) { if ( mapRenderer.Raycast( step, out var mapHitInfo, hasPhysicsHit ? physicsHit.distance : step.Length)) { if (hasPhysicsHit) { if (physicsHit.distance > mapHitInfo.Distance) { if (!closestMapHitInfo.HasValue || closestMapHitInfo.Value.Distance > mapHitInfo.Distance) { closestMapRenderer = mapRenderer; closestMapHitInfo = mapHitInfo; } } } else { if (!closestMapHitInfo.HasValue || closestMapHitInfo.Value.Distance > mapHitInfo.Distance) { closestMapRenderer = mapRenderer; closestMapHitInfo = mapHitInfo; } } } } if (closestMapHitInfo != null) { hitInfo = new MixedRealityRaycastHit(); var mapRendererHitInfo = closestMapHitInfo.Value; hitInfo.distance = mapRendererHitInfo.Distance; hitInfo.point = mapRendererHitInfo.Point; hitInfo.normal = mapRendererHitInfo.Normal; hitInfo.transform = closestMapRenderer.transform; return(true); } else { hitInfo = new MixedRealityRaycastHit(hasPhysicsHit, physicsHit); return(hasPhysicsHit); } }