Beispiel #1
0
        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);
        }
Beispiel #2
0
        /// <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;
            }
        }