void CheckDirectSelection(DeviceData deviceData, Dictionary <IMenu, MenuHideData> menuHideData, bool alternateMenuVisible) { if (m_DirectSelectionModule == null) { return; } var viewerScale = this.GetViewerScale(); var rayOrigin = deviceData.rayOrigin; var rayOriginPosition = rayOrigin.position; var heldObjects = m_DirectSelectionModule.GetHeldObjects(rayOrigin); // If this hand is holding any objects, hide its menus var hasDirectSelection = heldObjects != null && heldObjects.Count > 0; if (hasDirectSelection) { foreach (var kvp in menuHideData) { // Only set if hidden--value is reset every frame kvp.Value.hideFlags |= MenuHideFlags.HasDirectSelection; } foreach (var otherDeviceData in k_ActiveDeviceData) { if (otherDeviceData == deviceData) { continue; } var otherRayOrigin = otherDeviceData.rayOrigin; if (alternateMenuVisible) { SetAlternateMenuVisibility(otherRayOrigin, true); } // If other hand is within range to do a two-handed scale, hide its menu as well if (m_DirectSelectionModule.IsHovering(otherRayOrigin) || m_DirectSelectionModule.IsScaling(otherRayOrigin) || Vector3.Distance(otherRayOrigin.position, rayOriginPosition) < k_TwoHandHideDistance * viewerScale) { foreach (var kvp in otherDeviceData.menuHideData) { // Only set if hidden--value is reset every frame kvp.Value.hideFlags |= MenuHideFlags.HasDirectSelection; } break; } } } }
internal void UpdateMiniWorlds() { if (m_MiniWorldIgnoreListDirty) { UpdateMiniWorldIgnoreList(); m_MiniWorldIgnoreListDirty = false; } // Update MiniWorldRays foreach (var ray in m_Rays) { var miniWorldRayOrigin = ray.Key; var miniWorldRay = ray.Value; if (!miniWorldRay.proxy.active) { miniWorldRay.tester.active = false; continue; } var miniWorld = miniWorldRay.miniWorld; var inverseScale = miniWorld.miniWorldTransform.lossyScale.Inverse(); if (float.IsInfinity(inverseScale.x) || float.IsNaN(inverseScale.x)) // Extreme scales cause transform errors { continue; } // Transform into reference space var originalRayOrigin = miniWorldRay.originalRayOrigin; var referenceTransform = miniWorld.referenceTransform; var miniWorldTransform = miniWorld.miniWorldTransform; var position = originalRayOrigin.position; miniWorldRayOrigin.position = referenceTransform.TransformPoint(miniWorldTransform.InverseTransformPoint(position)); miniWorldRayOrigin.rotation = referenceTransform.rotation * Quaternion.Inverse(miniWorldTransform.rotation) * originalRayOrigin.rotation; miniWorldRayOrigin.localScale = Vector3.Scale(inverseScale, referenceTransform.localScale); // Set miniWorldRayOrigin active state based on whether controller is inside corresponding MiniWorld var originalPointerPosition = position + originalRayOrigin.forward * m_DirectSelectionModule.GetPointerLength(originalRayOrigin); var isContained = miniWorld.Contains(originalPointerPosition); miniWorldRay.tester.active = isContained; miniWorldRayOrigin.gameObject.SetActive(isContained); var miniWorldRayObjects = m_DirectSelectionModule.GetHeldObjects(miniWorldRayOrigin); var originalRayObjects = m_DirectSelectionModule.GetHeldObjects(originalRayOrigin); var hasPreview = miniWorldRay.hasPreview; if (miniWorldRayObjects == null && originalRayObjects == null && !hasPreview) { miniWorldRay.isContained = isContained; continue; } var wasContained = miniWorldRay.isContained; var dragStartedOutside = miniWorldRay.dragStartedOutside; if (isContained != wasContained) { // Early out if we grabbed a real-world object that started inside a mini world if (!isContained && miniWorldRayObjects == null) { miniWorldRay.isContained = false; continue; } // Transfer objects to and from original ray and MiniWorld ray (e.g. outside to inside mini world) var from = isContained ? originalRayOrigin : miniWorldRayOrigin; var to = isContained ? miniWorldRayOrigin : originalRayOrigin; KeyValuePair <Transform, MiniWorldRay>?overlapPair = null; MiniWorldRay incomingPreview = null; // Try to transfer objects between MiniWorlds if (miniWorldRayObjects != null && !isContained) { foreach (var kvp in m_Rays) { var otherRayOrigin = kvp.Key; var otherRay = kvp.Value; if (originalRayOrigin == otherRay.originalRayOrigin && otherRay != miniWorldRay && otherRay.isContained) { overlapPair = kvp; from = miniWorldRayOrigin; to = otherRayOrigin; break; } } } if (originalRayObjects != null && isContained && !dragStartedOutside) { //Check for other miniworlds' previews entering this ray's miniworld foreach (var kvp in m_Rays) { var otherRay = kvp.Value; if (originalRayOrigin == otherRay.originalRayOrigin && otherRay != miniWorldRay && otherRay.hasObjects) { incomingPreview = otherRay; from = originalRayOrigin; to = miniWorldRayOrigin; break; } } } var pointerLengthDiff = m_DirectSelectionModule.GetPointerLength(to) - m_DirectSelectionModule.GetPointerLength(from); m_DirectSelectionModule.TransferHeldObjects(from, to, Vector3.forward * pointerLengthDiff); if (overlapPair.HasValue) { var kvp = overlapPair.Value; miniWorldRay.TransferObjects(kvp.Value, kvp.Key); } if (incomingPreview != null) { incomingPreview.ExitPreviewMode(this); incomingPreview.TransferObjects(miniWorldRay); m_DirectSelectionModule.ResumeGrabbers(incomingPreview.node); } if (!isContained) { m_RayWasContained[originalRayOrigin] = false; //Prevent ray from showing } } if (dragStartedOutside) { miniWorldRay.isContained = isContained; continue; } var node = miniWorldRay.node; if (miniWorldRayObjects != null && !isContained && wasContained) { var containedInOtherMiniWorld = false; foreach (var world in m_Worlds) { if (miniWorld != world && world.Contains(originalPointerPosition)) { containedInOtherMiniWorld = true; } } // Transfer objects from miniworld to preview state // Don't switch to previewing the objects we are dragging if we are still in another mini world if (!containedInOtherMiniWorld) { // Check for player head var playerHead = false; foreach (var obj in miniWorldRayObjects) { if (obj.CompareTag(EditorXR.VRPlayerTag)) { playerHead = true; m_DirectSelectionModule.DropHeldObjects(node); break; } } if (!playerHead) { var scaleFactor = this.GetViewerScale() / miniWorld.referenceTransform.localScale.x; miniWorldRay.EnterPreviewMode(this, scaleFactor); m_DirectSelectionModule.SuspendGrabbers(node); } } } if (hasPreview) { // Check if we have just entered another miniworld var enterOther = false; foreach (var kvp in m_Rays) { var otherRay = kvp.Value; var otherMiniWorld = otherRay.miniWorld; if (otherMiniWorld != miniWorld && otherRay.node == node && otherMiniWorld.Contains(originalPointerPosition)) { miniWorldRay.ExitPreviewMode(this); m_DirectSelectionModule.ResumeGrabbers(node); enterOther = true; break; } } if (!enterOther) { if (!isContained) { miniWorldRay.UpdatePreview(); } else if (!wasContained) { miniWorldRay.ExitPreviewMode(this); m_DirectSelectionModule.ResumeGrabbers(node); } } } miniWorldRay.isContained = isContained; } // Update ray visibilities foreach (var deviceData in m_ToolModule.deviceData) { var proxy = deviceData.proxy; if (!proxy.active) { continue; } UpdateRayContainment(deviceData); } }