internal void OnWorkspaceCreated(IWorkspace workspace) { var miniWorldWorkspace = workspace as MiniWorldWorkspace; if (!miniWorldWorkspace) { return; } miniWorldWorkspace.zoomSliderMax = evr.GetModule <SpatialHashModule>().GetMaxBounds().size.MaxComponent() / miniWorldWorkspace.contentBounds.size.MaxComponent(); var miniWorld = miniWorldWorkspace.miniWorld; m_Worlds.Add(miniWorld); var intersectionModule = evr.GetModule <IntersectionModule>(); Rays.ForEachProxyDevice(deviceData => { var miniWorldRayOrigin = InstantiateMiniWorldRay(); miniWorldRayOrigin.parent = workspace.transform; var tester = miniWorldRayOrigin.GetComponentInChildren <IntersectionTester>(); tester.active = false; m_Rays[miniWorldRayOrigin] = new MiniWorldRay { originalRayOrigin = deviceData.rayOrigin, miniWorld = miniWorld, proxy = deviceData.proxy, node = deviceData.node, directSelectInput = deviceData.directSelectInput, tester = tester }; intersectionModule.AddTester(tester); evr.GetModule <HighlightModule>().AddRayOriginForNode(deviceData.node, miniWorldRayOrigin); if (deviceData.proxy.active) { if (deviceData.node == Node.LeftHand) { miniWorldWorkspace.leftRayOrigin = deviceData.rayOrigin; } if (deviceData.node == Node.RightHand) { miniWorldWorkspace.rightRayOrigin = deviceData.rayOrigin; } } }, false); }
internal void OnWorkspaceCreated(IWorkspace workspace) { var miniWorldWorkspace = workspace as MiniWorldWorkspace; if (!miniWorldWorkspace) { return; } miniWorldWorkspace.zoomSliderMax = evr.GetModule <SpatialHashModule>().GetMaxBounds().size.MaxComponent() / miniWorldWorkspace.contentBounds.size.MaxComponent(); var miniWorld = miniWorldWorkspace.miniWorld; var worldID = m_Worlds.Count; miniWorld.miniWorldTransform.name = string.Format("Miniworld {0}", worldID); m_Worlds.Add(miniWorld); var intersectionModule = evr.GetModule <IntersectionModule>(); Rays.ForEachProxyDevice(deviceData => { var node = deviceData.node; var rayOrigin = deviceData.rayOrigin; var proxy = deviceData.proxy; var miniWorldRayOrigin = InstantiateMiniWorldRay(); miniWorldRayOrigin.name = string.Format("{0} Miniworld {1} Ray", node, worldID); miniWorldRayOrigin.parent = workspace.transform; var tester = miniWorldRayOrigin.GetComponentInChildren <IntersectionTester>(); tester.active = false; m_Rays[miniWorldRayOrigin] = new MiniWorldRay(rayOrigin, miniWorld, proxy, node, tester); intersectionModule.AddTester(tester); evr.GetModule <HighlightModule>().AddRayOriginForNode(node, miniWorldRayOrigin); if (proxy.active) { if (node == Node.LeftHand) { miniWorldWorkspace.leftRayOrigin = rayOrigin; } if (node == Node.RightHand) { miniWorldWorkspace.rightRayOrigin = rayOrigin; } } }, false); }
public void TransferObjects(MiniWorldRay destinationRay, Transform rayOrigin = null) { var destinationGrabData = destinationRay.m_GrabData; destinationGrabData.AddRange(m_GrabData); m_GrabData.Clear(); destinationRay.dragStartedOutside = dragStartedOutside; if (rayOrigin) { foreach (var grabData in destinationGrabData) { grabData.GetCurrentOffsets(rayOrigin); } } }
internal void UpdateMiniWorlds() { if (m_MiniWorldIgnoreListDirty) { UpdateMiniWorldIgnoreList(); m_MiniWorldIgnoreListDirty = false; } var directSelection = evr.GetNestedModule <DirectSelection>(); // 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; miniWorldRayOrigin.position = referenceTransform.TransformPoint(miniWorldTransform.InverseTransformPoint(originalRayOrigin.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 = originalRayOrigin.position + originalRayOrigin.forward * DirectSelection.GetPointerLength(originalRayOrigin); var isContained = miniWorld.Contains(originalPointerPosition); miniWorldRay.tester.active = isContained; miniWorldRayOrigin.gameObject.SetActive(isContained); var miniWorldRayObjects = directSelection.GetHeldObjects(miniWorldRayOrigin); var originalRayObjects = directSelection.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 = DirectSelection.GetPointerLength(to) - DirectSelection.GetPointerLength(from); directSelection.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); directSelection.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(k_VRPlayerTag)) { playerHead = true; directSelection.DropHeldObjects(node); break; } } if (!playerHead) { var scaleFactor = this.GetViewerScale() / miniWorld.referenceTransform.localScale.x; miniWorldRay.EnterPreviewMode(this, scaleFactor); directSelection.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); directSelection.ResumeGrabbers(node); enterOther = true; break; } } if (!enterOther) { if (!isContained) { miniWorldRay.UpdatePreview(); } else if (!wasContained) { miniWorldRay.ExitPreviewMode(this); directSelection.ResumeGrabbers(node); } } } miniWorldRay.isContained = isContained; } // Update ray visibilities foreach (var deviceData in evr.m_DeviceData) { var proxy = deviceData.proxy; if (!proxy.active) { continue; } UpdateRayContaimnent(deviceData); } }
void CreateWorkspace(Type t, Action <IWorkspace> createdCallback = null) { var cameraTransform = U.Camera.GetMainCamera().transform; var workspace = (IWorkspace)U.Object.CreateGameObjectWithComponent(t, U.Camera.GetViewerPivot()); m_Workspaces.Add(workspace); workspace.destroyed += OnWorkspaceDestroyed; ConnectInterfaces(workspace); //Explicit setup call (instead of setting up in Awake) because we need interfaces to be hooked up first workspace.Setup(); var offset = kDefaultWorkspaceOffset; offset.z += workspace.vacuumBounds.extents.z; var workspaceTransform = workspace.transform; workspaceTransform.position = cameraTransform.TransformPoint(offset); workspaceTransform.rotation *= Quaternion.LookRotation(cameraTransform.forward) * kDefaultWorkspaceTilt; m_Vacuumables.Add(workspace); if (createdCallback != null) { createdCallback(workspace); } // MiniWorld is a special case that we handle due to all of the mini world interactions var miniWorldWorkspace = workspace as MiniWorldWorkspace; if (!miniWorldWorkspace) { return; } var miniWorld = miniWorldWorkspace.miniWorld; m_MiniWorlds.Add(miniWorld); ForEachRayOrigin((proxy, rayOriginPair, device, deviceData) => { var miniWorldRayOrigin = InstantiateMiniWorldRay(); miniWorldRayOrigin.parent = workspace.transform; #if ENABLE_MINIWORLD_RAY_SELECTION // Use the mini world ray origin instead of the original ray origin m_InputModule.AddRaycastSource(proxy, rayOriginPair.Key, deviceData.uiInput, miniWorldRayOrigin, (source) => { if (!IsRayActive(source.rayOrigin)) { return(false); } if (source.hoveredObject) { return(!m_Workspaces.Any(w => source.hoveredObject.transform.IsChildOf(w.transform))); } return(true); }); #endif var tester = miniWorldRayOrigin.GetComponentInChildren <IntersectionTester>(); tester.active = false; m_MiniWorldRays[miniWorldRayOrigin] = new MiniWorldRay { originalRayOrigin = rayOriginPair.Value, miniWorld = miniWorld, proxy = proxy, node = rayOriginPair.Key, directSelectInput = deviceData.directSelectInput, tester = tester }; m_IntersectionModule.AddTester(tester); }, false); UpdatePlayerHandleMaps(); }
private void CreateWorkspace(Type t) { var defaultOffset = Workspace.kDefaultOffset; var defaultTilt = Workspace.kDefaultTilt; var viewerPivot = U.Camera.GetViewerPivot(); Vector3 position = viewerPivot.position + defaultOffset; Quaternion rotation = defaultTilt; float arcLength = Mathf.Atan(Workspace.kDefaultBounds.x / (defaultOffset.z - Workspace.kDefaultBounds.z * 0.5f)) * Mathf.Rad2Deg //Calculate arc length at front of workspace + kWorkspaceAnglePadding; //Need some extra padding because workspaces are tilted float heightOffset = Workspace.kDefaultBounds.y + kWorkspaceYPadding; //Need padding in Y as well float currentRotation = arcLength; float currentHeight = 0; int count = 0; int direction = 1; Vector3 halfBounds = Workspace.kDefaultBounds * 0.5f; //While the current position is occupied, try a new one while (Physics.CheckBox(position, halfBounds, rotation) && count++ < kMaxWorkspacePlacementAttempts) { //The next position will be rotated by currentRotation, as if the hands of a clock Quaternion rotateAroundY = Quaternion.AngleAxis(currentRotation * direction, Vector3.up); position = viewerPivot.position + rotateAroundY * defaultOffset + Vector3.up * currentHeight; rotation = rotateAroundY * defaultTilt; //Every other iteration, rotate a little further if (direction < 0) { currentRotation += arcLength; } //Switch directions every iteration (left, right, left, right) direction *= -1; //If we've one more than half way around, we have tried the whole circle, bump up one level and keep trying if (currentRotation > 180) { direction = -1; currentRotation = 0; currentHeight += heightOffset; } } Workspace workspace = (Workspace)U.Object.CreateGameObjectWithComponent(t, U.Camera.GetViewerPivot()); m_AllWorkspaces.Add(workspace); workspace.destroyed += OnWorkspaceDestroyed; ConnectInterfaces(workspace); workspace.transform.position = position; workspace.transform.rotation = rotation; //Explicit setup call (instead of setting up in Awake) because we need interfaces to be hooked up first workspace.Setup(); var miniWorld = workspace as IMiniWorld; if (miniWorld == null) { return; } m_MiniWorlds.Add(miniWorld); foreach (var proxy in m_AllProxies) { foreach (var rayOriginBase in proxy.rayOrigins) { foreach (var device in InputSystem.devices) // Find device tagged with the node that matches this RayOrigin node { var node = GetDeviceNode(device); if (node.HasValue && node.Value == rayOriginBase.Key) { DeviceData deviceData; if (m_DeviceData.TryGetValue(device, out deviceData)) { // Create MiniWorld rayOrigin var miniWorldRayOrigin = new GameObject("MiniWorldRayOrigin").transform; miniWorldRayOrigin.parent = workspace.transform; var uiInput = CreateActionMapInput(m_InputModule.actionMap, device); m_PlayerHandle.maps.Insert(m_PlayerHandle.maps.IndexOf(deviceData.uiInput), uiInput); // Add RayOrigin transform, proxy and ActionMapInput references to input module list of sources m_InputModule.AddRaycastSource(proxy, rayOriginBase.Key, uiInput, miniWorldRayOrigin); m_MiniWorldRays[miniWorldRayOrigin] = new MiniWorldRay() { originalRayOrigin = rayOriginBase.Value, miniWorld = miniWorld, proxy = proxy, uiInput = uiInput }; } break; } } } } }