protected override void OnDragEnded(BaseHandle handle, HandleEventData eventData) { var gridItem = m_DragObject.GetComponent <AssetGridItem>(); var rayOrigin = eventData.rayOrigin; this.RemoveRayVisibilitySettings(rayOrigin, this); if (!this.IsOverShoulder(eventData.rayOrigin)) { if (gridItem.m_PreviewObjectTransform) { this.PlaceSceneObject(gridItem.m_PreviewObjectTransform, m_PreviewPrefabScale); } else { switch (data.type) { case "Prefab": case "Model": #if UNITY_EDITOR var go = (GameObject)PrefabUtility.InstantiatePrefab(data.asset); var transform = go.transform; transform.position = gridItem.transform.position; transform.rotation = MathUtilsExt.ConstrainYawRotation(gridItem.transform.rotation); #else var go = (GameObject)Instantiate(data.asset, gridItem.transform.position, gridItem.transform.rotation); #endif this.AddToSpatialHash(go); break; } } } StartCoroutine(HideGrabbedObject(m_DragObject.gameObject, gridItem.m_Cube)); }
IEnumerator AnimateHide() { m_VisibilityState = VisibilityState.TransitioningOut; foreach (var kvp in m_Faces) { var face = kvp.Value; face.visible = false; face.ClearSubmenus(); } this.RestartCoroutine(ref m_FrameRevealCoroutine, AnimateFrameReveal(m_VisibilityState)); const float kTargetScale = 0f; const float kSmoothTime = 0.06875f; var scale = transform.localScale.x; var smoothVelocity = 0f; var currentDuration = 0f; while (currentDuration < kSmoothTime) { scale = MathUtilsExt.SmoothDamp(scale, kTargetScale, ref smoothVelocity, kSmoothTime, Mathf.Infinity, Time.deltaTime); currentDuration += Time.deltaTime; transform.localScale = Vector3.one * scale; m_AlternateMenu.localScale = m_AlternateMenuOriginOriginalLocalScale * scale; yield return(null); } gameObject.SetActive(false); m_VisibilityState = VisibilityState.Hidden; var snapRotation = GetRotationForFaceIndex(GetClosestFaceIndexForRotation(currentRotation)); m_MenuFaceRotationOrigin.localRotation = Quaternion.Euler(new Vector3(0, snapRotation, 0)); // set intended target rotation m_RotationState = RotationState.AtRest; }
private IEnumerator SnapToFace(int faceIndex, float snapSpeed) { if (m_RotationState == RotationState.Snapping) { yield break; } m_RotationState = RotationState.Snapping; // When the user releases their input while rotating the menu, snap to the nearest face StartCoroutine(AnimateFrameRotationShapeChange(m_RotationState)); foreach (var face in m_MenuFaces) { face.EndVisuals(); } float rotation = currentRotation; float faceTargetRotation = GetRotationForFaceIndex(faceIndex); float smoothVelocity = 0f; float smoothSnapSpeed = 0.5f; while (Mathf.Abs(Mathf.DeltaAngle(rotation, faceTargetRotation)) > k_RotationEpsilon) { smoothSnapSpeed = MathUtilsExt.SmoothDamp(smoothSnapSpeed, snapSpeed, ref smoothVelocity, 0.0625f, Mathf.Infinity, Time.unscaledDeltaTime); rotation = Mathf.LerpAngle(rotation, faceTargetRotation, Time.unscaledDeltaTime * smoothSnapSpeed); m_MenuFaceRotationOrigin.localRotation = Quaternion.Euler(new Vector3(0, rotation, 0)); yield return(null); } m_MenuFaceRotationOrigin.localRotation = Quaternion.Euler(new Vector3(0, faceTargetRotation, 0)); // Target face index and rotation can be set separately, so both, must be kept in sync targetRotation = faceTargetRotation; m_RotationState = RotationState.AtRest; }
IEnumerator AnimateVisibility(bool visible, Action <PolyGridItem> callback) { var currentTime = 0f; // Item should always be at a scale of zero before becoming visible if (visible) { transform.localScale = Vector3.zero; } #if INCLUDE_POLY_TOOLKIT else { data.modelImportCompleted -= OnModelImportCompleted; data.thumbnailImportCompleted -= OnThumbnailImportCompleted; } #endif var currentScale = transform.localScale; var targetScale = visible ? m_IconScale * scaleFactor : Vector3.zero; while (currentTime < k_TransitionDuration) { currentTime += Time.deltaTime; transform.localScale = Vector3.Lerp(currentScale, targetScale, MathUtilsExt.SmoothInOutLerpFloat(currentTime / k_TransitionDuration)); yield return(null); } transform.localScale = targetScale; if (callback != null) { callback(this); } m_VisibilityCoroutine = null; }
void OnDrawing(Vector3 cumulativeDelta, Vector3 headPosition) { if (currentLine) { Vector3 move = cumulativeDelta - manipulationDelta; Vector3 handPosition; if (GazeGestureUtils.GetManipulationHandPosition(out handPosition)) { Vector3 fromHeadToModel = myPos - headPosition; Vector3 fromHeadToHand = handPosition - headPosition; float moveAmplifier = fromHeadToModel.magnitude / fromHeadToHand.magnitude; if (moveAmplifier > 1) { move *= moveAmplifier; } myPos += move; } CursorManager.Instance.ActiveCursor.transform.position = myPos; Vector3 pos = myPos; if (pointsList.Count == 0 || !MathUtilsExt.V3Equal(pointsList[pointsList.Count - 1], pos)) { pointsList.Add(pos); currentLine.positionCount = pointsList.Count; currentLine.SetPosition(pointsList.Count - 1, pointsList[pointsList.Count - 1]); } } else { StartDrawing(cumulativeDelta, headPosition); } manipulationDelta = cumulativeDelta; }
private IEnumerator AnimateVisibility(bool show) { if (m_VisibilityCoroutine != null) { yield break; } m_CanvasGroup.interactable = false; var smoothTime = show ? 0.35f : 0.125f; var startingOpacity = m_CanvasGroup.alpha; var targetOpacity = show ? 1f : 0f; var smoothVelocity = 0f; var currentDuration = 0f; while (currentDuration < smoothTime) { startingOpacity = MathUtilsExt.SmoothDamp(startingOpacity, targetOpacity, ref smoothVelocity, smoothTime, Mathf.Infinity, Time.unscaledDeltaTime); currentDuration += Time.unscaledDeltaTime; m_CanvasGroup.alpha = startingOpacity * startingOpacity; yield return(null); } m_CanvasGroup.alpha = targetOpacity; if (show) { m_CanvasGroup.interactable = true; } else { m_TitleIcon.SetBlendShapeWeight(0, 0); } m_VisibilityCoroutine = null; }
private IEnumerator AnimateFrameReveal(VisibilityState visibilityState) { m_MenuFrameRenderer.SetBlendShapeWeight(1, 100f); const float zeroStartBlendShapePadding = 20f; // start the blendShape at a point slightly above the full hidden value for better visibility const float kLerpEmphasisWeight = 0.25f; var smoothTime = visibilityState == VisibilityState.TransitioningIn ? 0.1875f : 0.09375f; // slower if transitioning in var currentBlendShapeWeight = m_MenuFrameRenderer.GetBlendShapeWeight(1); var targetWeight = visibilityState == VisibilityState.TransitioningIn ? 0f : 100f; var smoothVelocity = 0f; currentBlendShapeWeight = currentBlendShapeWeight > 0 ? currentBlendShapeWeight : zeroStartBlendShapePadding; var currentDuration = 0f; while (m_VisibilityState != VisibilityState.Hidden && currentDuration < smoothTime) { currentBlendShapeWeight = MathUtilsExt.SmoothDamp(currentBlendShapeWeight, targetWeight, ref smoothVelocity, smoothTime, Mathf.Infinity, Time.unscaledDeltaTime); currentDuration += Time.unscaledDeltaTime; m_MenuFrameRenderer.SetBlendShapeWeight(1, currentBlendShapeWeight * currentBlendShapeWeight); m_MenuFacesMaterial.color = Color.Lerp(m_MenuFacesColor, k_MenuFacesHiddenColor, currentBlendShapeWeight * kLerpEmphasisWeight); yield return(null); } if (m_VisibilityState == visibilityState) { m_MenuFrameRenderer.SetBlendShapeWeight(1, targetWeight); m_MenuFacesMaterial.color = targetWeight > 0 ? m_MenuFacesColor : k_MenuFacesHiddenColor; } if (m_VisibilityState == VisibilityState.Hidden) { m_MenuFrameRenderer.SetBlendShapeWeight(0, 0); } m_FrameRevealCoroutine = null; }
internal static void DropPlayerHead(Transform playerHead) { var cameraRig = CameraUtils.GetCameraRig(); var mainCamera = CameraUtils.GetMainCamera().transform; // Hide player head to avoid jarring impact var playerHeadRenderers = playerHead.GetComponentsInChildren <Renderer>(); foreach (var renderer in playerHeadRenderers) { renderer.enabled = false; } var rotationDiff = MathUtilsExt.ConstrainYawRotation(Quaternion.Inverse(mainCamera.rotation) * playerHead.rotation); var cameraDiff = cameraRig.position - mainCamera.position; cameraDiff.y = 0; var rotationOffset = rotationDiff * cameraDiff - cameraDiff; var endPosition = cameraRig.position + (playerHead.position - mainCamera.position) + rotationOffset; var endRotation = cameraRig.rotation * rotationDiff; var viewDirection = endRotation * Vector3.forward; evr.StartCoroutine(UpdateCameraRig(endPosition, viewDirection, () => { playerHead.hideFlags = defaultHideFlags; playerHead.parent = mainCamera; playerHead.localRotation = Quaternion.identity; playerHead.localPosition = Vector3.zero; foreach (var renderer in playerHeadRenderers) { renderer.enabled = true; } })); }
IEnumerator HideRay() { m_Tip.transform.localScale = Vector3.zero; // cache current width for smooth animation to target value without snapping var currentWidth = m_LineRenderer.widthStart; const float kTargetWidth = 0f; const float kSmoothTime = 0.1875f; var smoothVelocity = 0f; var currentDuration = 0f; while (currentDuration < kSmoothTime) { currentDuration += Time.deltaTime; currentWidth = MathUtilsExt.SmoothDamp(currentWidth, kTargetWidth, ref smoothVelocity, kSmoothTime, Mathf.Infinity, Time.deltaTime); m_LineRenderer.widthStart = currentWidth; m_LineRenderer.widthEnd = currentWidth; yield return(null); } m_LineRenderer.widthStart = kTargetWidth; m_LineRenderer.widthEnd = kTargetWidth; m_RayVisibilityCoroutine = null; }
IEnumerator AnimatePulseColor() { const float kTargetDuration = 1f; m_PulseDuration = 0f; var maxShaderLineRadius = new Vector3(0.03f, 0f, 100f); var minShaderLineRadius = new Vector3(0.005f, 0f, 100f); var currentVector3ShaderLineRadius = m_HintLineMaterial.GetVector(k_ShaderLineRadiusPropertyName); var currentColor = m_ScrollLineRenderer.colorStart; // The line stand & end colors are the same; fetch only one of them while (m_PulseDuration < kTargetDuration) { var shapedDuration = MathUtilsExt.SmoothInOutLerpFloat(m_PulseDuration / kTargetDuration); var newColor = Color.Lerp(currentColor, m_PulseColor, shapedDuration); m_ScrollLineRenderer.colorStart = newColor; m_ScrollLineRenderer.colorEnd = newColor; m_PulseDuration += Time.unscaledDeltaTime * 5; m_HintLineMaterial.SetVector(k_ShaderLineRadiusPropertyName, Vector3.Lerp(currentVector3ShaderLineRadius, maxShaderLineRadius, shapedDuration)); yield return(null); } while (m_PulseDuration > 0f) { var shapedDuration = MathUtilsExt.SmoothInOutLerpFloat(m_PulseDuration / kTargetDuration); var newColor = Color.Lerp(m_VisibleColor, m_PulseColor, shapedDuration); m_ScrollLineRenderer.colorStart = newColor; m_ScrollLineRenderer.colorEnd = newColor; m_PulseDuration -= Time.unscaledDeltaTime * 1.5f; m_HintLineMaterial.SetVector(k_ShaderLineRadiusPropertyName, Vector3.Lerp(minShaderLineRadius, maxShaderLineRadius, shapedDuration)); yield return(null); } m_ScrollLineRenderer.colorStart = m_VisibleColor; m_ScrollLineRenderer.colorEnd = m_VisibleColor; m_PulseDuration = 0f; }
IEnumerator ShowButtonList() { m_ButtonList.gameObject.SetActive(true); const float kTargetDuration = 0.5f; var currentAlpha = m_ButtonListCanvasGroup.alpha; var kTargetAlpha = 1f; var transitionAmount = 0f; var velocity = 0f; var currentDuration = 0f; while (currentDuration < kTargetDuration) { currentDuration += Time.deltaTime; transitionAmount = MathUtilsExt.SmoothDamp(transitionAmount, 1f, ref velocity, kTargetDuration, Mathf.Infinity, Time.deltaTime); m_ButtonListGrid.spacing = new Vector2(0f, Mathf.Lerp(m_HiddenButtonListYSpacing, 0f, transitionAmount)); m_ButtonListCanvasGroup.alpha = Mathf.Lerp(currentAlpha, kTargetAlpha, transitionAmount); yield return(null); } m_ButtonListGrid.spacing = new Vector2(0f, 0f); m_ButtonListCanvasGroup.alpha = 1f; m_ShowButtonListCoroutine = null; }
IEnumerator AnimateShow() { m_VisibilityState = VisibilityState.TransitioningIn; foreach (var kvp in m_Faces) { kvp.Value.visible = true; } this.RestartCoroutine(ref m_FrameRevealCoroutine, AnimateFrameReveal(m_VisibilityState)); const float faceDelay = 0.1f; var count = 0; foreach (var face in m_Faces) { face.Value.Reveal(count++ *faceDelay); } const float kTargetScale = 1f; const float kSmoothTime = 0.125f; var scale = 0f; var smoothVelocity = 0f; var currentDuration = 0f; while (currentDuration < kSmoothTime) { scale = MathUtilsExt.SmoothDamp(scale, kTargetScale, ref smoothVelocity, kSmoothTime, Mathf.Infinity, Time.deltaTime); currentDuration += Time.deltaTime; transform.localScale = Vector3.one * scale; m_AlternateMenu.localScale = m_AlternateMenuOriginOriginalLocalScale * scale; yield return(null); } m_VisibilityState = VisibilityState.Visible; }
void UpdateVisuals(ITooltip tooltip, TooltipUI tooltipUI, Transform target, float lerp) { var tooltipTransform = tooltipUI.transform; var tooltipText = tooltipUI.text; if (tooltipText) { tooltipText.text = tooltip.tooltipText; } var viewerScale = getViewerScale(); tooltipTransform.localScale = m_TooltipScale * lerp * viewerScale; var placement = tooltip as ITooltipPlacement; // Adjust for alignment var offset = Vector3.zero; if (placement != null) { switch (placement.tooltipAlignment) { case TextAlignment.Right: offset = Vector3.left; break; case TextAlignment.Left: offset = Vector3.right; break; } } var rectTransform = tooltipUI.GetComponent <RectTransform>(); var rect = rectTransform.rect; var halfWidth = rect.width * 0.5f; var halfHeight = rect.height * 0.5f; if (placement != null) { offset *= halfWidth * rectTransform.lossyScale.x; } else { offset = Vector3.back * k_Offset; } MathUtilsExt.SetTransformOffset(target, tooltipTransform, offset * lerp, Quaternion.identity); if (placement != null) { var source = placement.tooltipSource; var toSource = tooltipTransform.InverseTransformPoint(source.position); // Position spheres: one at source, one on the closest edge of the tooltip var spheres = tooltipUI.spheres; spheres[0].position = source.position; var attachedSphere = spheres[1]; var boxSlope = halfHeight / halfWidth; var toSourceSlope = Mathf.Abs(toSource.y / toSource.x); halfHeight *= Mathf.Sign(toSource.y); halfWidth *= Mathf.Sign(toSource.x); attachedSphere.localPosition = toSourceSlope > boxSlope ? new Vector3(0, halfHeight) : new Vector3(halfWidth, 0); // Align dotted line var attachedSpherePosition = attachedSphere.position; toSource = source.position - attachedSpherePosition; var midPoint = attachedSpherePosition + toSource * 0.5f; var dottedLine = tooltipUI.dottedLine; var length = toSource.magnitude; var uvRect = dottedLine.uvRect; var worldScale = 1 / viewerScale; uvRect.width = length * k_UVScale * worldScale; uvRect.xMin += k_UVScrollSpeed * Time.unscaledDeltaTime; dottedLine.uvRect = uvRect; var dottedLineTransform = dottedLine.transform.parent.GetComponent <RectTransform>(); dottedLineTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, length / tooltipTransform.lossyScale.x); dottedLineTransform.position = midPoint; dottedLineTransform.rotation = Quaternion.LookRotation(toSource, -tooltipTransform.forward); } }
bool DoTwoHandedScaling(ConsumeControlDelegate consumeControl) { foreach (var linkedObject in linkedObjects) { if (((LocomotionTool)linkedObject).m_Rotating) { return(false); } } if (this.IsSharedUpdater(this)) { var crawl = m_LocomotionInput.crawl; if (crawl.isHeld) { if (m_AllowScaling) { var otherGripHeld = false; foreach (var linkedObject in linkedObjects) { var otherLocomotionTool = (LocomotionTool)linkedObject; if (otherLocomotionTool == this) { continue; } var otherLocomotionInput = otherLocomotionTool.m_LocomotionInput; if (otherLocomotionInput == null) // This can occur if crawl is pressed when EVR is opened { continue; } var otherCrawl = otherLocomotionInput.crawl; if (otherCrawl.isHeld) { otherGripHeld = true; consumeControl(crawl); consumeControl(otherCrawl); // Also consume thumbstick axes to disable radial menu consumeControl(m_LocomotionInput.horizontal); consumeControl(m_LocomotionInput.vertical); consumeControl(otherLocomotionInput.horizontal); consumeControl(otherLocomotionInput.vertical); // Pre-emptively consume thumbstick press to override UndoMenu consumeControl(m_LocomotionInput.scaleReset); consumeControl(otherLocomotionInput.scaleReset); // Also pre-emptively consume world-reset consumeControl(m_LocomotionInput.worldReset); consumeControl(otherLocomotionInput.worldReset); var thisPosition = cameraRig.InverseTransformPoint(rayOrigin.position); var otherRayOrigin = otherLocomotionTool.rayOrigin; var otherPosition = cameraRig.InverseTransformPoint(otherRayOrigin.position); var distance = Vector3.Distance(thisPosition, otherPosition); this.AddRayVisibilitySettings(rayOrigin, this, false, false); this.AddRayVisibilitySettings(otherRayOrigin, this, false, false); var rayToRay = otherPosition - thisPosition; var midPoint = thisPosition + rayToRay * 0.5f; rayToRay.y = 0; // Use for yaw rotation var pivotYaw = MathUtilsExt.ConstrainYawRotation(cameraRig.rotation); if (!m_Scaling) { m_StartScale = this.GetViewerScale(); m_StartDistance = distance; m_StartMidPoint = pivotYaw * midPoint * m_StartScale; m_StartPosition = cameraRig.position; m_StartDirection = rayToRay; m_StartYaw = cameraRig.rotation.eulerAngles.y; otherLocomotionTool.m_Scaling = true; otherLocomotionTool.m_Crawling = false; otherLocomotionTool.m_StartCrawling = false; m_ViewerScaleVisuals.leftHand = rayOrigin; m_ViewerScaleVisuals.rightHand = otherRayOrigin; m_ViewerScaleVisuals.gameObject.SetActive(true); foreach (var obj in linkedObjects) { var locomotionTool = (LocomotionTool)obj; locomotionTool.HideScaleFeedback(); locomotionTool.HideRotateFeedback(); locomotionTool.HideMainButtonFeedback(); locomotionTool.ShowResetScaleFeedback(); } } m_Scaling = true; m_StartCrawling = false; m_Crawling = false; var currentScale = Mathf.Clamp(m_StartScale * (m_StartDistance / distance), k_MinScale, k_MaxScale); var scaleReset = m_LocomotionInput.scaleReset; var scaleResetHeld = scaleReset.isHeld; var otherScaleReset = otherLocomotionInput.scaleReset; var otherScaleResetHeld = otherScaleReset.isHeld; // Press both thumb buttons to reset scale if (scaleResetHeld && otherScaleResetHeld) { m_AllowScaling = false; rayToRay = otherRayOrigin.position - rayOrigin.position; midPoint = rayOrigin.position + rayToRay * 0.5f; var currOffset = midPoint - cameraRig.position; cameraRig.position = midPoint - currOffset / currentScale; cameraRig.rotation = Quaternion.AngleAxis(m_StartYaw, Vector3.up); ResetViewerScale(); } var worldReset = m_LocomotionInput.worldReset; var worldResetHeld = worldReset.isHeld; if (worldResetHeld) { consumeControl(worldReset); } var otherWorldReset = otherLocomotionInput.worldReset; var otherWorldResetHeld = otherWorldReset.isHeld; if (otherWorldResetHeld) { consumeControl(otherWorldReset); } // Press both triggers to reset to origin if (worldResetHeld && otherWorldResetHeld) { m_AllowScaling = false; cameraRig.position = VRView.headCenteredOrigin; cameraRig.rotation = Quaternion.identity; ResetViewerScale(); } if (m_AllowScaling) { var yawSign = Mathf.Sign(Vector3.Dot(Quaternion.AngleAxis(90, Vector3.down) * m_StartDirection, rayToRay)); var currentYaw = m_StartYaw + Vector3.Angle(m_StartDirection, rayToRay) * yawSign; var currentRotation = Quaternion.AngleAxis(currentYaw, Vector3.up); midPoint = currentRotation * midPoint * currentScale; var pos = m_StartPosition + m_StartMidPoint - midPoint; cameraRig.position = pos; cameraRig.rotation = currentRotation; this.SetViewerScale(currentScale); } break; } } if (!otherGripHeld) { CancelScale(); } } } else { CancelScale(); } } return(m_Scaling); }
public void ProcessInput(ActionMapInput input, ConsumeControlDelegate consumeControl) { var blinkInput = (BlinkLocomotion)input; if (m_State == State.Moving) { return; } foreach (var linkedObject in linkedObjects) { if (linkedObject.Equals(this)) { continue; } var blinkTool = (BlinkLocomotionTool)linkedObject; if (blinkTool.m_State != State.Inactive) { return; } } var yawValue = blinkInput.yaw.value; var forwardValue = blinkInput.forward.value; m_Grip = blinkInput.grip.isHeld ? blinkInput.grip : null; m_Thumb = blinkInput.thumb.isHeld ? blinkInput.thumb : null; if (this.IsSharedUpdater(this)) { if (m_Grip != null) { if (m_AllowScaling) { var otherGrip = false; foreach (var linkedObject in linkedObjects) { if (linkedObject.Equals(this)) { continue; } var blinkTool = (BlinkLocomotionTool)linkedObject; if (blinkTool.m_Grip != null) { otherGrip = true; consumeControl(m_Grip); consumeControl(blinkTool.m_Grip); var thisPosition = cameraRig.InverseTransformPoint(rayOrigin.position); var otherRayOrigin = blinkTool.rayOrigin; var otherPosition = cameraRig.InverseTransformPoint(otherRayOrigin.position); var distance = Vector3.Distance(thisPosition, otherPosition); var rayToRay = otherPosition - thisPosition; var midPoint = thisPosition + rayToRay * 0.5f; rayToRay.y = 0; // Use for yaw rotation var pivotYaw = MathUtilsExt.ConstrainYawRotation(cameraRig.rotation); if (!m_Scaling) { m_StartScale = this.GetViewerScale(); m_StartDistance = distance; m_StartMidPoint = pivotYaw * midPoint * m_StartScale; m_StartPosition = cameraRig.position; m_StartDirection = rayToRay; m_StartYaw = cameraRig.rotation.eulerAngles.y; m_EnableJoystick = false; blinkTool.m_EnableJoystick = false; CreateViewerScaleVisuals(rayOrigin, otherRayOrigin); } m_Scaling = true; var currentScale = m_StartScale * (m_StartDistance / distance); // Press both thumb buttons to reset if (m_Thumb != null && blinkTool.m_Thumb != null) { m_AllowScaling = false; rayToRay = otherRayOrigin.position - rayOrigin.position; midPoint = rayOrigin.position + rayToRay * 0.5f; var currOffset = midPoint - cameraRig.position; this.SetViewerScale(1f); cameraRig.position = midPoint - currOffset / currentScale; cameraRig.rotation = Quaternion.AngleAxis(m_StartYaw, Vector3.up); consumeControl(m_Thumb); consumeControl(blinkTool.m_Thumb); if (m_ViewerScaleVisuals) { ObjectUtils.Destroy(m_ViewerScaleVisuals.gameObject); } } if (currentScale < k_MinScale) { currentScale = k_MinScale; } if (currentScale > k_MaxScale) { currentScale = k_MaxScale; } if (m_AllowScaling) { var yawSign = Mathf.Sign(Vector3.Dot(Quaternion.AngleAxis(90, Vector3.down) * m_StartDirection, rayToRay)); var currentYaw = m_StartYaw + Vector3.Angle(m_StartDirection, rayToRay) * yawSign; var currentRotation = Quaternion.AngleAxis(currentYaw, Vector3.up); midPoint = currentRotation * midPoint * currentScale; cameraRig.position = m_StartPosition + m_StartMidPoint - midPoint; cameraRig.rotation = currentRotation; this.SetViewerScale(currentScale); m_ViewerScaleVisuals.viewerScale = currentScale; m_BlinkVisuals.viewerScale = currentScale; Shader.SetGlobalFloat(k_WorldScaleProperty, 1f / currentScale); } break; } } if (!otherGrip) { CancelScale(); } } } else { CancelScale(); } } bool isVive = proxyType == typeof(ViveProxy); if (m_EnableJoystick && (!isVive || m_Thumb != null)) { var viewerCamera = CameraUtils.GetMainCamera(); if (Mathf.Abs(yawValue) > Mathf.Abs(forwardValue)) { if (!Mathf.Approximately(yawValue, 0)) { if (node == Node.LeftHand) { var direction = viewerCamera.transform.right; direction.y = 0; direction.Normalize(); Translate(yawValue, isVive, direction); } else { var speed = yawValue * k_SlowRotationSpeed; var threshold = isVive ? k_RotationThresholdVive : k_RotationThreshold; if (Mathf.Abs(yawValue) > threshold) { speed = k_FastRotationSpeed * Mathf.Sign(yawValue); } cameraRig.RotateAround(viewerCamera.transform.position, Vector3.up, speed * Time.deltaTime); } consumeControl(blinkInput.yaw); } } else { if (!Mathf.Approximately(forwardValue, 0)) { var direction = Vector3.up; if (node == Node.LeftHand) { direction = viewerCamera.transform.forward; direction.y = 0; direction.Normalize(); } Translate(forwardValue, isVive, direction); consumeControl(blinkInput.forward); } } } if (blinkInput.blink.wasJustPressed && !m_BlinkVisuals.outOfMaxRange) { m_State = State.Aiming; this.HideDefaultRay(rayOrigin); this.LockRay(rayOrigin, this); m_BlinkVisuals.ShowVisuals(); consumeControl(blinkInput.blink); } else if (m_State == State.Aiming && blinkInput.blink.wasJustReleased) { this.UnlockRay(rayOrigin, this); this.ShowDefaultRay(rayOrigin); if (!m_BlinkVisuals.outOfMaxRange) { m_BlinkVisuals.HideVisuals(); StartCoroutine(MoveTowardTarget(m_BlinkVisuals.locatorPosition)); } else { m_BlinkVisuals.enabled = false; m_State = State.Inactive; } } }
IEnumerator PlaceSceneObjectCoroutine(Transform obj, Vector3 targetScale) { var go = obj.gameObject; // Don't let us direct select while placing this.RemoveFromSpatialHash(go); var start = Time.realtimeSinceStartup; var currTime = 0f; obj.parent = null; var startScale = obj.localScale; var startPosition = ObjectUtils.GetBounds(obj).center; var pivotOffset = obj.position - startPosition; var startRotation = obj.rotation; var targetRotation = MathUtilsExt.ConstrainYawRotation(startRotation); //Get bounds at target scale and rotation (scaled and rotated from bounds center) var origScale = obj.localScale; obj.localScale = targetScale; obj.rotation = targetRotation; var rotationDiff = Quaternion.Inverse(startRotation) * targetRotation; var scaleDiff = targetScale.magnitude / startScale.magnitude; var targetPivotOffset = rotationDiff * pivotOffset * scaleDiff; obj.position = startPosition + targetPivotOffset; var bounds = ObjectUtils.GetBounds(obj); obj.localScale = origScale; obj.localRotation = startRotation; obj.position = startPosition + pivotOffset; // We want to position the object so that it fits within the camera perspective at its original scale var camera = CameraUtils.GetMainCamera(); var halfAngle = camera.fieldOfView * 0.5f; var perspective = halfAngle + k_InstantiateFOVDifference; var camPosition = camera.transform.position; var forward = startPosition - camPosition; var distance = bounds.size.magnitude / Mathf.Tan(perspective * Mathf.Deg2Rad); var targetPosition = bounds.center; if (distance > forward.magnitude && obj.localScale != targetScale) { targetPosition = camPosition + forward.normalized * distance; } startPosition += pivotOffset; targetPosition += targetPivotOffset; while (currTime < k_GrowDuration) { currTime = Time.realtimeSinceStartup - start; var t = currTime / k_GrowDuration; var tSquared = t * t; obj.localScale = Vector3.Lerp(startScale, targetScale, tSquared); obj.position = Vector3.Lerp(startPosition, targetPosition, tSquared); obj.rotation = Quaternion.Lerp(startRotation, targetRotation, tSquared); yield return(null); } obj.localScale = targetScale; Selection.activeGameObject = go; this.AddToSpatialHash(go); #if UNITY_EDITOR Undo.IncrementCurrentGroup(); #endif }
void UpdateVisuals(ITooltip tooltip, TooltipUI tooltipUI, Transform target, float lerp) { var tooltipTransform = tooltipUI.transform; lerp = MathUtilsExt.SmoothInOutLerpFloat(lerp); // shape the lerp for better presentation var tooltipText = tooltipUI.text; if (tooltipText) { tooltipText.text = tooltip.tooltipText; tooltipText.color = Color.Lerp(Color.clear, Color.white, lerp); } var viewerScale = this.GetViewerScale(); tooltipTransform.localScale = m_TooltipScale * lerp * viewerScale; TooltipData toolTipData; m_Tooltips.TryGetValue(tooltip, out toolTipData); var highlightMaterial = toolTipData != null ? toolTipData.customHighlightMaterial : m_HighlightMaterial; tooltipUI.highlight.material = highlightMaterial; m_TooltipBackgroundMaterial.SetColor("_Color", Color.Lerp(UnityBrandColorScheme.darker, m_OriginalBackgroundColor, lerp)); var placement = tooltip as ITooltipPlacement; // Adjust for alignment var offset = Vector3.zero; if (placement != null) { switch (placement.tooltipAlignment) { case TextAlignment.Right: offset = Vector3.left; break; case TextAlignment.Left: offset = Vector3.right; break; } } var rectTransform = tooltipUI.GetComponent <RectTransform>(); var rect = rectTransform.rect; var halfWidth = rect.width * 0.5f; var halfHeight = rect.height * 0.5f; if (placement != null) { offset *= halfWidth * rectTransform.lossyScale.x; } else { offset = Vector3.back * k_Offset * this.GetViewerScale(); } MathUtilsExt.SetTransformOffset(target, tooltipTransform, offset * lerp, Quaternion.identity); if (placement != null) { var source = placement.tooltipSource; var toSource = tooltipTransform.InverseTransformPoint(source.position); // Position spheres: one at source, one on the closest edge of the tooltip var spheres = tooltipUI.spheres; spheres[0].position = source.position; var attachedSphere = spheres[1]; var boxSlope = halfHeight / halfWidth; var toSourceSlope = Mathf.Abs(toSource.y / toSource.x); halfHeight *= Mathf.Sign(toSource.y); halfWidth *= Mathf.Sign(toSource.x); attachedSphere.localPosition = toSourceSlope > boxSlope ? new Vector3(0, halfHeight) : new Vector3(halfWidth, 0); // Align dotted line var attachedSpherePosition = attachedSphere.position; toSource = source.position - attachedSpherePosition; var midPoint = attachedSpherePosition + toSource * 0.5f; var dottedLine = tooltipUI.dottedLine; var length = toSource.magnitude; var uvRect = dottedLine.uvRect; var worldScale = 1 / viewerScale; uvRect.width = length * k_UVScale * worldScale; uvRect.xMin += k_UVScrollSpeed * Time.deltaTime; dottedLine.uvRect = uvRect; var dottedLineTransform = dottedLine.transform.parent.GetComponent <RectTransform>(); dottedLineTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, length / tooltipTransform.lossyScale.x); dottedLineTransform.position = midPoint; dottedLineTransform.rotation = Quaternion.LookRotation(toSource, -tooltipTransform.forward); } }
public void OnDragging() { if (m_Resizing) { var viewerScale = m_WorkspaceUI.GetViewerScale(); var pointerPosition = m_WorkspaceUI.GetPointerPosition(rayOrigin); var dragVector = (pointerPosition - m_DragStart) / viewerScale; var bounds = m_WorkspaceUI.bounds; var transform = m_WorkspaceUI.transform; var positionOffsetForward = Vector3.Dot(dragVector, transform.forward) * 0.5f; var positionOffsetRight = Vector3.Dot(dragVector, transform.right) * 0.5f; switch (m_Direction) { default: bounds.size = m_BoundsSizeStart + Vector3.back * Vector3.Dot(dragVector, transform.forward); positionOffsetRight = 0; break; case ResizeDirection.Back: bounds.size = m_BoundsSizeStart + Vector3.forward * Vector3.Dot(dragVector, transform.forward); positionOffsetRight = 0; break; case ResizeDirection.Left: bounds.size = m_BoundsSizeStart + Vector3.left * Vector3.Dot(dragVector, transform.right); positionOffsetForward = 0; break; case ResizeDirection.Right: bounds.size = m_BoundsSizeStart + Vector3.right * Vector3.Dot(dragVector, transform.right); positionOffsetForward = 0; break; case ResizeDirection.Front | ResizeDirection.Left: bounds.size = m_BoundsSizeStart + Vector3.left * Vector3.Dot(dragVector, transform.right) + Vector3.back * Vector3.Dot(dragVector, transform.forward); break; case ResizeDirection.Front | ResizeDirection.Right: bounds.size = m_BoundsSizeStart + Vector3.right * Vector3.Dot(dragVector, transform.right) + Vector3.back * Vector3.Dot(dragVector, transform.forward); break; case ResizeDirection.Back | ResizeDirection.Left: bounds.size = m_BoundsSizeStart + Vector3.left * Vector3.Dot(dragVector, transform.right) + Vector3.forward * Vector3.Dot(dragVector, transform.forward); break; case ResizeDirection.Back | ResizeDirection.Right: bounds.size = m_BoundsSizeStart + Vector3.right * Vector3.Dot(dragVector, transform.right) + Vector3.forward * Vector3.Dot(dragVector, transform.forward); break; } if (m_WorkspaceUI.resize != null) { m_WorkspaceUI.resize(bounds); } var currentExtents = m_WorkspaceUI.bounds.extents; var extents = bounds.extents; var absRight = Mathf.Abs(positionOffsetRight); var absForward = Mathf.Abs(positionOffsetForward); var positionOffset = transform.right * (absRight - (currentExtents.x - extents.x)) * Mathf.Sign(positionOffsetRight) + transform.forward * (absForward - (currentExtents.z - extents.z)) * Mathf.Sign(positionOffsetForward); m_WorkspaceUI.transform.parent.position = m_PositionStart + positionOffset * viewerScale; m_WorkspaceUI.OnResizing(rayOrigin); } else { MathUtilsExt.SetTransformOffset(rayOrigin, m_WorkspaceUI.transform.parent, m_PositionOffset, m_RotationOffset); m_WorkspaceUI.OnMoving(rayOrigin); } }
internal void UpdateMiniWorlds(ConsumeControlDelegate consumeControl) { if (m_MiniWorldIgnoreListDirty) { UpdateMiniWorldIgnoreList(); m_MiniWorldIgnoreListDirty = false; } var objectsGrabber = evr.m_DirectSelection.objectsGrabber; foreach (var kvp in m_MiniWorldInputs) { kvp.Key.ProcessInput(kvp.Value, consumeControl); } // 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; miniWorldRayOrigin.position = referenceTransform.position + Vector3.Scale(miniWorld.miniWorldTransform.InverseTransformPoint(originalRayOrigin.position), miniWorld.referenceTransform.localScale); miniWorldRayOrigin.rotation = referenceTransform.rotation * Quaternion.Inverse(miniWorld.miniWorldTransform.rotation) * originalRayOrigin.rotation; miniWorldRayOrigin.localScale = Vector3.Scale(inverseScale, referenceTransform.localScale); var directSelection = evr.m_DirectSelection; // 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 directSelectInput = (DirectSelectInput)miniWorldRay.directSelectInput; var dragObjects = miniWorldRay.dragObjects; if (dragObjects == null) { var heldObjects = objectsGrabber.GetHeldObjects(miniWorldRayOrigin); if (heldObjects != null) { // Only one ray can grab an object, otherwise PlaceObject is called on each trigger release // This does not prevent TransformTool from doing two-handed scaling var otherRayHasObject = false; foreach (var otherRay in m_Rays.Values) { if (otherRay != miniWorldRay && otherRay.dragObjects != null) { otherRayHasObject = true; } } if (!otherRayHasObject) { miniWorldRay.dragObjects = heldObjects; var scales = new Vector3[heldObjects.Length]; var dragGameObjects = new GameObject[heldObjects.Length]; for (var i = 0; i < heldObjects.Length; i++) { var dragObject = heldObjects[i]; scales[i] = dragObject.transform.localScale; dragGameObjects[i] = dragObject.gameObject; } var totalBounds = ObjectUtils.GetBounds(dragGameObjects); var maxSizeComponent = totalBounds.size.MaxComponent(); if (!Mathf.Approximately(maxSizeComponent, 0f)) { miniWorldRay.previewScaleFactor = Vector3.one * (k_PreviewScale * Viewer.GetViewerScale() / maxSizeComponent); } miniWorldRay.originalScales = scales; } } } // Transfer objects to and from original ray and MiniWorld ray (e.g. outside to inside mini world) if (directSelection != null && isContained != miniWorldRay.wasContained) { var pointerLengthDiff = directSelection.GetPointerLength(miniWorldRayOrigin) - directSelection.GetPointerLength(originalRayOrigin); var from = isContained ? originalRayOrigin : miniWorldRayOrigin; var to = isContained ? miniWorldRayOrigin : originalRayOrigin; if (isContained || miniWorldRay.dragObjects == null) { objectsGrabber.TransferHeldObjects(from, to, pointerLengthDiff * Vector3.forward); } } // Transfer objects between MiniWorlds if (dragObjects == null) { if (isContained) { foreach (var kvp in m_Rays) { var otherRayOrigin = kvp.Key; var otherRay = kvp.Value; var otherObjects = otherRay.dragObjects; if (otherRay != miniWorldRay && !otherRay.wasContained && otherObjects != null) { dragObjects = otherObjects; miniWorldRay.dragObjects = otherObjects; miniWorldRay.originalScales = otherRay.originalScales; miniWorldRay.previewScaleFactor = otherRay.previewScaleFactor; otherRay.dragObjects = null; if (directSelection != null) { var heldObjects = objectsGrabber.GetHeldObjects(otherRayOrigin); if (heldObjects != null) { objectsGrabber.TransferHeldObjects(otherRayOrigin, miniWorldRayOrigin, Vector3.zero); // Set the new offset to zero because the object will have moved (this could be improved by taking original offset into account) } } break; } } } } if (isContained && !miniWorldRay.wasContained) { Rays.HideRay(originalRayOrigin, true); Rays.LockRay(originalRayOrigin, this); } if (!isContained && miniWorldRay.wasContained) { Rays.UnlockRay(originalRayOrigin, this); Rays.ShowRay(originalRayOrigin, true); } if (dragObjects == null) { miniWorldRay.wasContained = isContained; continue; } var previewScaleFactor = miniWorldRay.previewScaleFactor; var positionOffsets = miniWorldRay.originalPositionOffsets; var rotationOffsets = miniWorldRay.originalRotationOffsets; var originalScales = miniWorldRay.originalScales; if (directSelectInput.select.isHeld) { if (isContained) { // Scale the object back to its original scale when it re-enters the MiniWorld if (!miniWorldRay.wasContained) { for (var i = 0; i < dragObjects.Length; i++) { var dragObject = dragObjects[i]; dragObject.localScale = originalScales[i]; MathUtilsExt.SetTransformOffset(miniWorldRayOrigin, dragObject, positionOffsets[i], rotationOffsets[i]); } // Add the object (back) to TransformTool if (directSelection != null) { objectsGrabber.GrabObjects(miniWorldRay.node, miniWorldRayOrigin, directSelectInput, dragObjects); } } } else { // Check for player head for (var i = 0; i < dragObjects.Length; i++) { var dragObject = dragObjects[i]; if (dragObject.CompareTag(k_VRPlayerTag)) { if (directSelection != null) { objectsGrabber.DropHeldObjects(miniWorldRayOrigin); } // Drop player at edge of MiniWorld miniWorldRay.dragObjects = null; dragObjects = null; break; } } if (dragObjects == null) { continue; } if (miniWorldRay.wasContained) { var containedInOtherMiniWorld = false; foreach (var world in m_Worlds) { if (miniWorld != world && world.Contains(originalPointerPosition)) { containedInOtherMiniWorld = true; } } // Don't switch to previewing the objects we are dragging if we are still in another mini world if (!containedInOtherMiniWorld) { for (var i = 0; i < dragObjects.Length; i++) { var dragObject = dragObjects[i]; // Store the original scale in case the object re-enters the MiniWorld originalScales[i] = dragObject.localScale; dragObject.localScale = Vector3.Scale(dragObject.localScale, previewScaleFactor); } // Drop from TransformTool to take control of object if (directSelection != null) { objectsGrabber.DropHeldObjects(miniWorldRayOrigin, out positionOffsets, out rotationOffsets); miniWorldRay.originalPositionOffsets = positionOffsets; miniWorldRay.originalRotationOffsets = rotationOffsets; miniWorldRay.wasHeld = true; } } } for (var i = 0; i < dragObjects.Length; i++) { var dragObject = dragObjects[i]; var rotation = originalRayOrigin.rotation; var position = originalRayOrigin.position + rotation * Vector3.Scale(previewScaleFactor, positionOffsets[i]); MathUtilsExt.LerpTransform(dragObject, position, rotation * rotationOffsets[i]); } } } // Release the current object if the trigger is no longer held if (directSelectInput.select.wasJustReleased) { var rayPosition = originalRayOrigin.position; for (var i = 0; i < dragObjects.Length; i++) { var dragObject = dragObjects[i]; // If the user has pulled an object out of the MiniWorld, use PlaceObject to grow it back to its original scale if (!isContained) { if (evr.m_Viewer.IsOverShoulder(originalRayOrigin)) { evr.m_SceneObjectModule.DeleteSceneObject(dragObject.gameObject); } else { dragObject.localScale = originalScales[i]; var rotation = originalRayOrigin.rotation; dragObject.position = rayPosition + rotation * positionOffsets[i]; dragObject.rotation = rotation * rotationOffsets[i]; } } } miniWorldRay.dragObjects = null; miniWorldRay.wasHeld = false; } miniWorldRay.wasContained = isContained; } }
// Animate the LocalScale of the asset towards a common/unified scale // used when the asset is magnetized/attached to the proxy, after grabbing it from the asset grid IEnumerator ShowGrabbedObject() { var currentLocalScale = m_DragObject.localScale; var currentPreviewOffset = Vector3.zero; var currentPreviewRotationOffset = Quaternion.identity; if (m_PreviewObjectClone) { currentPreviewOffset = m_PreviewObjectClone.localPosition; } var currentTime = 0f; var currentVelocity = 0f; const float kDuration = 1f; var targetScale = Vector3.one * k_IconPreviewScale; var pivotOffset = Vector3.zero; var rotationOffset = Quaternion.AngleAxis(30, Vector3.right); if (m_PreviewObjectClone) { var viewerScale = this.GetViewerScale(); var maxComponent = m_PreviewBounds.size.MaxComponent() / viewerScale; targetScale = Vector3.one * maxComponent; // Object will preview at the same size when grabbed var previewExtents = m_PreviewBounds.extents / viewerScale; pivotOffset = m_PreviewPivotOffset / viewerScale; // If bounds are greater than offset, set to bounds if (previewExtents.y > pivotOffset.y) { pivotOffset.y = previewExtents.y; } if (previewExtents.z > pivotOffset.z) { pivotOffset.z = previewExtents.z; } if (maxComponent < k_MinPreviewScale) { // Object will be preview at the minimum scale targetScale = Vector3.one * k_MinPreviewScale; pivotOffset = pivotOffset * scaleFactor + (Vector3.up + Vector3.forward) * 0.5f * k_MinPreviewScale; } if (maxComponent > k_MaxPreviewScale) { // Object will be preview at the maximum scale targetScale = Vector3.one * k_MaxPreviewScale; pivotOffset = pivotOffset * scaleFactor + (Vector3.up + Vector3.forward) * 0.5f * k_MaxPreviewScale; } } while (currentTime < kDuration - 0.05f) { if (m_DragObject == null) { yield break; // Exit coroutine if m_GrabbedObject is destroyed before the loop is finished } currentTime = MathUtilsExt.SmoothDamp(currentTime, kDuration, ref currentVelocity, 0.5f, Mathf.Infinity, Time.deltaTime); m_DragObject.localScale = Vector3.Lerp(currentLocalScale, targetScale, currentTime); if (m_PreviewObjectClone) { m_PreviewObjectClone.localPosition = Vector3.Lerp(currentPreviewOffset, pivotOffset, currentTime); m_PreviewObjectClone.localRotation = Quaternion.Lerp(currentPreviewRotationOffset, rotationOffset, currentTime); // Compensate for preview origin rotation } yield return(null); } m_DragObject.localScale = targetScale; }
public void Update(Transform parent) { MathUtilsExt.SetTransformOffset(parent, transform, m_LocalPositionOffset, m_RotationOffset); }
void UpdateVisuals(ITooltip tooltip, TooltipData tooltipData, float lerp) { var target = tooltipData.GetTooltipTarget(tooltip); var tooltipUI = tooltipData.tooltipUI; var placement = tooltipData.placement; var orientationWeight = tooltipData.orientationWeight; var tooltipTransform = tooltipUI.transform; lerp = MathUtilsExt.SmoothInOutLerpFloat(lerp); // shape the lerp for better presentation var transitionLerp = MathUtilsExt.SmoothInOutLerpFloat(1.0f - Mathf.Clamp01((Time.time - tooltipData.transitionTime) / k_ChangeTransitionDuration)); var viewerScale = this.GetViewerScale(); tooltipTransform.localScale = m_TooltipScale * lerp * viewerScale; // Adjust for alignment var offset = GetTooltipOffset(tooltipUI, placement, tooltipData.transitionOffset * transitionLerp); // The rectTransform expansion is handled in the Tooltip dynamically, based on alignment & text length var rotationOffset = Quaternion.identity; var camTransform = CameraUtils.GetMainCamera().transform; if (Vector3.Dot(camTransform.forward, target.forward) < 0) { rotationOffset *= k_FlipYRotation; } if (Vector3.Dot(camTransform.up, target.up) + orientationWeight < 0) { rotationOffset *= k_FlipZRotation; tooltipData.orientationWeight = -k_TextOrientationWeight; } else { tooltipData.orientationWeight = k_TextOrientationWeight; } MathUtilsExt.SetTransformOffset(target, tooltipTransform, offset * lerp, rotationOffset); if (placement != null) { //TODO: Figure out why rect gives us different height/width than GetWorldCorners tooltipUI.rectTransform.GetWorldCorners(k_Corners); var bottomLeft = k_Corners[0]; var halfWidth = (bottomLeft - k_Corners[2]).magnitude * 0.5f; var halfHeight = (bottomLeft - k_Corners[1]).magnitude * 0.5f; var source = placement.tooltipSource; var toSource = tooltipTransform.InverseTransformPoint(source.position); // Position spheres: one at source, one on the closest edge of the tooltip var spheres = tooltipUI.spheres; spheres[0].position = source.position; var attachedSphere = spheres[1]; var boxSlope = halfHeight / halfWidth; var toSourceSlope = Mathf.Abs(toSource.y / toSource.x); var parentScale = attachedSphere.parent.lossyScale; halfHeight *= Mathf.Sign(toSource.y) / parentScale.x; halfWidth *= Mathf.Sign(toSource.x) / parentScale.y; attachedSphere.localPosition = toSourceSlope > boxSlope ? new Vector3(0, halfHeight) : new Vector3(halfWidth, 0); // Align dotted line var attachedSpherePosition = attachedSphere.position; toSource = source.position - attachedSpherePosition; var midPoint = attachedSpherePosition + toSource * 0.5f; var dottedLine = tooltipUI.dottedLine; var length = toSource.magnitude; var uvRect = dottedLine.uvRect; var worldScale = 1 / viewerScale; uvRect.width = length * k_UVScale * worldScale; uvRect.xMin += k_UVScrollSpeed * Time.deltaTime; dottedLine.uvRect = uvRect; var dottedLineTransform = dottedLine.transform.parent.GetComponent <RectTransform>(); dottedLineTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, length / tooltipTransform.lossyScale.x); dottedLineTransform.position = midPoint; dottedLineTransform.rotation = Quaternion.LookRotation(toSource, -tooltipTransform.forward); } }
public void GetCurrentOffsets(Transform parent) { MathUtilsExt.GetTransformOffset(parent, transform, out m_LocalPositionOffset, out m_RotationOffset); m_OriginalLocalPositionOffset = m_LocalPositionOffset; }