public GrabData(Transform rayOrigin, TransformInput input, Transform[] grabbedObjects) { this.rayOrigin = rayOrigin; this.input = input; this.grabbedObjects = grabbedObjects; Reset(); }
public GrabData(Transform rayOrigin, TransformInput input, Transform[] grabbedTransforms, Vector3 contactPoint) { this.rayOrigin = rayOrigin; this.input = input; this.grabbedTransforms = grabbedTransforms; var inverseRotation = Quaternion.Inverse(rayOrigin.rotation); m_GrabOffset = inverseRotation * (contactPoint - rayOrigin.position); CaptureInitialTransforms(); Reset(); }
public void ProcessInput(ActionMapInput input, ConsumeControlDelegate consumeControl) { m_Input = (TransformInput)input; if (!this.IsSharedUpdater(this)) { return; } var hasObject = false; var manipulatorGameObject = m_CurrentManipulator.gameObject; var gameObjects = Selection.gameObjects; if (!m_CurrentManipulator.dragging) { var directSelection = this.GetDirectSelection(); var hasLeft = m_LeftGrabData != null; var hasRight = m_RightGrabData != null; hasObject = directSelection.Count > 0 || hasLeft || hasRight; var hoveringSelection = false; foreach (var kvp in directSelection) { if (gameObjects.Contains(kvp.Value.gameObject)) { hoveringSelection = true; break; } } // Disable manipulator on direct hover or drag if (manipulatorGameObject.activeSelf && (hoveringSelection || hasLeft || hasRight)) { manipulatorGameObject.SetActive(false); } var scaleHover = false; foreach (var kvp in directSelection) { var directRayOrigin = kvp.Key; var directSelectionData = kvp.Value; if (!(hasLeft || hasRight) && this.IsMainMenuVisible(directRayOrigin)) { continue; } var directHoveredObject = directSelectionData.gameObject; var selectionCandidate = this.GetSelectionCandidate(directHoveredObject, true); // Can't select this object (it might be locked or static) if (directHoveredObject && !selectionCandidate) { continue; } if (selectionCandidate) { directHoveredObject = selectionCandidate; } if (!this.CanGrabObject(directHoveredObject, directRayOrigin)) { continue; } this.AddRayVisibilitySettings(directRayOrigin, this, false, true); // This will also disable ray selection if (!this.IsConeVisible(directRayOrigin)) { continue; } var grabbingNode = this.RequestNodeFromRayOrigin(directRayOrigin); var transformTool = linkedObjects.Cast <TransformTool>().FirstOrDefault(linkedObject => linkedObject.node == grabbingNode); if (transformTool == null) { continue; } // Check if the other hand is already grabbing for two-handed scale var otherData = grabbingNode == Node.LeftHand ? m_RightGrabData : m_LeftGrabData; if (otherData != null && !otherData.grabbedTransforms.Contains(directHoveredObject.transform)) { otherData = null; } if (otherData != null) { scaleHover = true; if (m_ScaleFeedback.Count == 0) { ShowScaleFeedback(grabbingNode); } } var transformInput = transformTool.m_Input; if (transformInput.select.wasJustPressed) { this.ClearSnappingState(directRayOrigin); consumeControl(transformInput.select); var grabbedObjects = new HashSet <Transform> { directHoveredObject.transform }; grabbedObjects.UnionWith(Selection.transforms); if (objectsGrabbed != null && !m_Scaling) { objectsGrabbed(directRayOrigin, grabbedObjects); } var grabData = new GrabData(directRayOrigin, transformInput, grabbedObjects.ToArray(), directSelectionData.contactPoint); if (grabbingNode == Node.LeftHand) { m_LeftGrabData = grabData; } else { m_RightGrabData = grabData; } ShowGrabFeedback(grabbingNode); if (otherData != null) { m_ScaleFirstNode = grabbingNode == Node.LeftHand ? Node.RightHand : Node.LeftHand; otherData.StartScaling(grabData); ShowScaleOptionsFeedback(otherData.twoHandedManipulateMode); m_Scaling = true; } // A direct selection has been made. Hide the manipulator until the selection changes m_DirectSelected = true; #if UNITY_EDITOR Undo.IncrementCurrentGroup(); #endif } } if (!scaleHover) { HideScaleFeedback(); } hasLeft = m_LeftGrabData != null; hasRight = m_RightGrabData != null; var leftInput = m_LeftGrabData != null ? m_LeftGrabData.input : null; var leftHeld = m_LeftGrabData != null && leftInput.select.isHeld; var rightInput = m_RightGrabData != null ? m_RightGrabData.input : null; var rightHeld = m_RightGrabData != null && rightInput.select.isHeld; if (hasLeft) { consumeControl(leftInput.cancel); consumeControl(leftInput.suppressVertical); if (!m_Scaling && leftInput.cancel.wasJustPressed) { m_LeftGrabData.Cancel(); DropHeldObjects(Node.LeftHand); hasLeft = false; } if (leftInput.select.wasJustReleased) { if (rightInput != null && rightInput.select.wasJustReleased) { HideScaleOptionFeedback(); m_Scaling = false; } DropHeldObjects(Node.LeftHand); hasLeft = false; consumeControl(leftInput.select); } } if (hasRight) { consumeControl(rightInput.cancel); consumeControl(rightInput.suppressVertical); if (!m_Scaling && rightInput.cancel.wasJustPressed) { m_RightGrabData.Cancel(); DropHeldObjects(Node.RightHand); hasRight = false; } if (rightInput.select.wasJustReleased) { if (leftInput != null && leftInput.select.wasJustReleased) { HideScaleOptionFeedback(); m_Scaling = false; } DropHeldObjects(Node.RightHand); hasRight = false; consumeControl(rightInput.select); } } if (hasLeft && hasRight && leftHeld && rightHeld && m_Scaling) // Two-handed scaling { var rightRayOrigin = m_RightGrabData.rayOrigin; var leftRayOrigin = m_LeftGrabData.rayOrigin; var leftCancel = leftInput.cancel; var rightCancel = rightInput.cancel; var scaleGrabData = m_ScaleFirstNode == Node.LeftHand ? m_LeftGrabData : m_RightGrabData; if (leftCancel.wasJustPressed) { if (scaleGrabData.twoHandedManipulateMode == TwoHandedManipulateMode.ScaleOnly) { scaleGrabData.twoHandedManipulateMode = TwoHandedManipulateMode.RotateAndScale; } else { scaleGrabData.twoHandedManipulateMode = TwoHandedManipulateMode.ScaleOnly; } ShowScaleOptionsFeedback(scaleGrabData.twoHandedManipulateMode); } if (rightCancel.wasJustPressed) { HideScaleOptionFeedback(); m_Scaling = false; if (m_ScaleFirstNode == Node.LeftHand) { m_LeftGrabData.Cancel(); } else { m_RightGrabData.Cancel(); } DropHeldObjects(Node.RightHand); DropHeldObjects(Node.LeftHand); } else if (m_ScaleFirstNode == Node.LeftHand) { m_LeftGrabData.ScaleObjects(m_RightGrabData); this.ClearSnappingState(leftRayOrigin); } else { m_RightGrabData.ScaleObjects(m_LeftGrabData); this.ClearSnappingState(rightRayOrigin); } } else { // If m_Scaling is true but both hands don't have a grab, we need to transfer back to one-handed manipulation // Offsets will change while scaling. Whichever hand keeps holding the trigger after scaling is done will need to reset itself if (m_Scaling) { if (hasLeft) { m_LeftGrabData.Reset(); if (objectsTransferred != null && m_ScaleFirstNode == Node.RightHand) { objectsTransferred(m_RightGrabData.rayOrigin, m_LeftGrabData.rayOrigin); } } if (hasRight) { m_RightGrabData.Reset(); if (objectsTransferred != null && m_ScaleFirstNode == Node.LeftHand) { objectsTransferred(m_LeftGrabData.rayOrigin, m_RightGrabData.rayOrigin); } } HideScaleOptionFeedback(); m_Scaling = false; } if (hasLeft && leftHeld) { m_LeftGrabData.UpdatePositions(this); } if (hasRight && rightHeld) { m_RightGrabData.UpdatePositions(this); } } foreach (var linkedObject in linkedObjects) { var transformTool = (TransformTool)linkedObject; var rayOrigin = transformTool.rayOrigin; if (!(m_Scaling || directSelection.ContainsKey(rayOrigin) || GrabDataForNode(transformTool.node) != null)) { this.RemoveRayVisibilitySettings(rayOrigin, this); } } } // Manipulator is disabled while direct manipulation is happening if (hasObject || m_DirectSelected) { return; } if (gameObjects.Length > 0) { if (!m_CurrentManipulator.dragging) { UpdateCurrentManipulator(); } var deltaTime = Time.deltaTime; var manipulatorTransform = manipulatorGameObject.transform; var lerp = m_CurrentlySnapping ? 1f : k_LazyFollowTranslate * deltaTime; manipulatorTransform.position = Vector3.Lerp(manipulatorTransform.position, m_TargetPosition, lerp); // Manipulator does not rotate when in global mode if (m_PivotRotation == PivotRotation.Local && m_CurrentManipulator == m_StandardManipulator) { manipulatorTransform.rotation = Quaternion.Slerp(manipulatorTransform.rotation, m_TargetRotation, k_LazyFollowRotate * deltaTime); } var selectionTransforms = Selection.transforms; #if UNITY_EDITOR Undo.RecordObjects(selectionTransforms, "Move"); #endif foreach (var t in selectionTransforms) { var targetRotation = Quaternion.Slerp(t.rotation, m_TargetRotation * m_RotationOffsets[t], k_LazyFollowRotate * deltaTime); if (t.rotation != targetRotation) { t.rotation = targetRotation; } Vector3 targetPosition; if (m_PivotMode == PivotMode.Center) // Rotate the position offset from the manipulator when rotating around center { m_PositionOffsetRotation = Quaternion.Slerp(m_PositionOffsetRotation, m_TargetRotation * Quaternion.Inverse(m_StartRotation), k_LazyFollowRotate * deltaTime); targetPosition = manipulatorTransform.position + m_PositionOffsetRotation * m_PositionOffsets[t]; } else { targetPosition = manipulatorTransform.position + m_PositionOffsets[t]; } if (t.position != targetPosition) { t.position = targetPosition; } var targetScale = Vector3.Lerp(t.localScale, Vector3.Scale(m_TargetScale, m_ScaleOffsets[t]), k_LazyFollowTranslate * deltaTime); if (t.localScale != targetScale) { t.localScale = targetScale; } } } }
public void ProcessInput(ActionMapInput input, ConsumeControlDelegate consumeControl) { m_Input = (TransformInput)input; if (!this.IsSharedUpdater(this)) { return; } var hasObject = false; var manipulatorGameObject = m_CurrentManipulator.gameObject; if (!m_CurrentManipulator.dragging) { var directSelection = this.GetDirectSelection(); var hasLeft = m_GrabData.ContainsKey(Node.LeftHand); var hasRight = m_GrabData.ContainsKey(Node.RightHand); hasObject = directSelection.Count > 0 || hasLeft || hasRight; var hoveringSelection = false; foreach (var selection in directSelection.Values) { if (Selection.gameObjects.Contains(selection.gameObject)) { hoveringSelection = true; break; } } // Disable manipulator on direct hover or drag if (manipulatorGameObject.activeSelf && (hoveringSelection || hasLeft || hasRight)) { manipulatorGameObject.SetActive(false); } foreach (var kvp in directSelection) { var directRayOrigin = kvp.Key; if (m_GrabData.Count == 0 && this.IsMainMenuVisible(directRayOrigin)) { continue; } var directHoveredObject = kvp.Value; var selectionCandidate = this.GetSelectionCandidate(directHoveredObject, true); // Can't select this object (it might be locked or static) if (directHoveredObject && !selectionCandidate) { continue; } if (selectionCandidate) { directHoveredObject = selectionCandidate; } if (!this.CanGrabObject(directHoveredObject, directRayOrigin)) { continue; } this.AddRayVisibilitySettings(directRayOrigin, this, false, true); // This will also disable ray selection if (!this.IsConeVisible(directRayOrigin)) { continue; } var grabbingNode = this.RequestNodeFromRayOrigin(directRayOrigin); var transformTool = linkedObjects.Cast <TransformTool>().FirstOrDefault(linkedObject => linkedObject.node == grabbingNode); if (transformTool == null) { continue; } var transformInput = transformTool.m_Input; if (transformInput.select.wasJustPressed) { this.ClearSnappingState(directRayOrigin); consumeControl(transformInput.select); // Check if the other hand is already grabbing for two-handed scale foreach (var grabData in m_GrabData) { var otherNode = grabData.Key; var otherData = grabData.Value; if (otherNode != grabbingNode && otherData.grabbedObjects.Contains(directHoveredObject.transform)) { m_ScaleStartDistance = (directRayOrigin.position - otherData.rayOrigin.position).magnitude; m_ScaleFirstNode = otherNode; otherData.StartScaling(); m_Scaling = true; break; } } var grabbedObjects = new HashSet <Transform> { directHoveredObject.transform }; grabbedObjects.UnionWith(Selection.transforms); if (objectsGrabbed != null && !m_Scaling) { objectsGrabbed(directRayOrigin, grabbedObjects); } m_GrabData[grabbingNode.Value] = new GrabData(directRayOrigin, transformInput, grabbedObjects.ToArray()); // A direct selection has been made. Hide the manipulator until the selection changes m_DirectSelected = true; Undo.IncrementCurrentGroup(); } } GrabData leftData; hasLeft = m_GrabData.TryGetValue(Node.LeftHand, out leftData); GrabData rightData; hasRight = m_GrabData.TryGetValue(Node.RightHand, out rightData); var leftInput = leftData != null ? leftData.input : null; var leftHeld = leftData != null && leftInput.select.isHeld; var rightInput = rightData != null ? rightData.input : null; var rightHeld = rightData != null && rightInput.select.isHeld; if (hasLeft) { if (leftInput.cancel.wasJustPressed) { DropHeldObjects(Node.LeftHand); hasLeft = false; consumeControl(leftInput.cancel); Undo.PerformUndo(); } if (leftInput.select.wasJustReleased) { DropHeldObjects(Node.LeftHand); hasLeft = false; consumeControl(leftInput.select); } } if (hasRight) { if (rightInput.cancel.wasJustPressed) { DropHeldObjects(Node.RightHand); hasRight = false; consumeControl(rightInput.cancel); Undo.PerformUndo(); } if (rightInput.select.wasJustReleased) { DropHeldObjects(Node.RightHand); hasRight = false; consumeControl(rightInput.select); } } if (hasLeft && hasRight && leftHeld && rightHeld && m_Scaling) // Two-handed scaling { var rightRayOrigin = rightData.rayOrigin; var leftRayOrigin = leftData.rayOrigin; m_ScaleFactor = (leftRayOrigin.position - rightRayOrigin.position).magnitude / m_ScaleStartDistance; if (m_ScaleFactor > 0 && m_ScaleFactor < Mathf.Infinity) { if (m_ScaleFirstNode == Node.LeftHand) { leftData.ScaleObjects(m_ScaleFactor); this.ClearSnappingState(leftRayOrigin); } else { rightData.ScaleObjects(m_ScaleFactor); this.ClearSnappingState(rightRayOrigin); } } } else { // Offsets will change while scaling. Whichever hand keeps holding the trigger after scaling is done will need to reset itself if (m_Scaling) { if (hasLeft) { leftData.Reset(); if (objectsTransferred != null && m_ScaleFirstNode == Node.RightHand) { objectsTransferred(rightData.rayOrigin, leftData.rayOrigin); } } if (hasRight) { rightData.Reset(); if (objectsTransferred != null && m_ScaleFirstNode == Node.LeftHand) { objectsTransferred(leftData.rayOrigin, rightData.rayOrigin); } } m_Scaling = false; } if (hasLeft && leftHeld) { leftData.UpdatePositions(this); } if (hasRight && rightHeld) { rightData.UpdatePositions(this); } } foreach (var linkedObject in linkedObjects) { var transformTool = (TransformTool)linkedObject; var rayOrigin = transformTool.rayOrigin; if (!(m_Scaling || directSelection.ContainsKey(rayOrigin) || m_GrabData.ContainsKey(transformTool.node.Value))) { this.RemoveRayVisibilitySettings(rayOrigin, this); } } } // Manipulator is disabled while direct manipulation is happening if (hasObject || m_DirectSelected) { return; } if (Selection.gameObjects.Length > 0) { if (!m_CurrentManipulator.dragging) { UpdateCurrentManipulator(); } var deltaTime = Time.deltaTime; var manipulatorTransform = manipulatorGameObject.transform; var lerp = m_CurrentlySnapping ? 1f : k_LazyFollowTranslate * deltaTime; manipulatorTransform.position = Vector3.Lerp(manipulatorTransform.position, m_TargetPosition, lerp); // Manipulator does not rotate when in global mode if (m_PivotRotation == PivotRotation.Local && m_CurrentManipulator == m_StandardManipulator) { manipulatorTransform.rotation = Quaternion.Slerp(manipulatorTransform.rotation, m_TargetRotation, k_LazyFollowRotate * deltaTime); } var selectionTransforms = Selection.transforms; Undo.RecordObjects(selectionTransforms, "Move"); foreach (var t in selectionTransforms) { t.rotation = Quaternion.Slerp(t.rotation, m_TargetRotation * m_RotationOffsets[t], k_LazyFollowRotate * deltaTime); if (m_PivotMode == PivotMode.Center) // Rotate the position offset from the manipulator when rotating around center { m_PositionOffsetRotation = Quaternion.Slerp(m_PositionOffsetRotation, m_TargetRotation * Quaternion.Inverse(m_StartRotation), k_LazyFollowRotate * deltaTime); t.position = manipulatorTransform.position + m_PositionOffsetRotation * m_PositionOffsets[t]; } else { t.position = manipulatorTransform.position + m_PositionOffsets[t]; } t.localScale = Vector3.Lerp(t.localScale, Vector3.Scale(m_TargetScale, m_ScaleOffsets[t]), k_LazyFollowTranslate * deltaTime); } } }
private void Awake() { trInput = GetComponent <TransformInput>(); }