/// <summary> /// Does the actual translation, but is independent of the hands (L or R) /// </summary> private void ActionTransformSelectionGeneric(ref TransformDelta transformDelta, uint maskId) { if (transformDelta.Rotate == Quaternion.identity && transformDelta.Scale == 1f) { // Only translate selection Native.TranslateSelection(State, transformDelta.Translate, maskId); } else { // Do full transformation // Ignore pivot mode and use hands as pivot // var doPivot = transformDelta.Mode != Mode.Mesh && // ExecuteInput.Shared.ToolTransformMode != ToolTransformMode.TransformingLR; var pivot = Vector3.zero; switch (transformDelta.Mode) { case PivotMode.Mesh: // Fall through, use hands as pivot case PivotMode.Hand: pivot = transformDelta.Pivot; break; case PivotMode.Selection: pivot = Native.GetSelectionCenter(State, maskId); break; } Native.TransformSelection(State, transformDelta.Translate, transformDelta.Scale, transformDelta.Rotate, pivot, maskId); } }
/// <returns>An instance with the default values</returns> public static MeshInputState GetInstance() { return(new MeshInputState { VisibleSelectionMask = uint.MaxValue, HarmonicShowDisplacement = true, Shared = InputManager.State, SharedPrev = InputManager.StatePrev, TransformDeltaJoint = TransformDelta.Identity() }); }
/// <summary> /// Consumes the state for the transformations /// </summary> private void ConsumeTransform() { // Consume transform if we are in the Select tool if (InputManager.State.ActiveTool == ToolType.Select) { TransformDeltaJoint = TransformDelta.Identity(); TransformDeltaL = TransformDelta.Identity(); TransformDeltaR = TransformDelta.Identity(); } DoTransformLPrev = DoTransformL; DoTransformL = false; DoTransformRPrev = DoTransformR; DoTransformR = false; }
/// <summary> /// Finds out the transformation when using both hands /// </summary> private void GetTransformTwoHanded(ref TransformDelta transformDelta, bool withRotate = true) { // Soft editing var softFactor = _firstTransformHand ? InputManager.State.GripR : InputManager.State.GripL; var softFactorSecondary = !_firstTransformHand ? InputManager.State.GripR : InputManager.State.GripL; // Scale var scale = (InputManager.State.HandPosL - InputManager.State.HandPosR).magnitude / (_transformStartHandPosL - _transformStartHandPosR).magnitude; if (float.IsNaN(scale)) { scale = 1f; } scale = (scale - 1) * softFactorSecondary + 1; transformDelta.Scale *= scale; // Rotate - Optional if (!withRotate) { return; } Vector3 v0, v1; if (_firstTransformHand) { v0 = _transformStartHandPosR - _transformStartHandPosL; v1 = InputManager.State.HandPosR - InputManager.State.HandPosL; } else { v0 = _transformStartHandPosL - _transformStartHandPosR; v1 = InputManager.State.HandPosL - InputManager.State.HandPosR; } // Implementation Note: could also use combination of Quaternion.FromToRotation() and Quaternion.Lerp() var axis = Vector3.Cross(v0, v1); var angle = Vector3.Angle(v0, v1); angle *= softFactor; transformDelta.Rotate = Quaternion.AngleAxis(angle, axis) * transformDelta.Rotate; }
/// <summary> /// Gets and consumes the transformation, applying it to the LibiglMesh <see cref="Transform"/>. /// </summary> private void ApplyTransformToMesh() { if (!_doTransformL && !_doTransformR) { return; } var transformDelta = TransformDelta.Identity(); if (transformDelta.Mode == PivotMode.Selection) { Debug.LogWarning( "Invalid pivot mode PivotMode.Selection for transforming the mesh, using PivotMode.Hand."); transformDelta.Mode = PivotMode.Hand; } // Get & Consume the transformation GetTransformDelta(true, ref transformDelta, Space.World, InputManager.State.TransformWithRotate, _isTwoHandedTransformation, _firstTransformHand); // Apply it to the mesh var uTransform = Mesh.transform; uTransform.Translate(transformDelta.Translate, Space.World); uTransform.localScale *= transformDelta.Scale; var pivotLocal = uTransform.localScale.CwiseMul(uTransform.InverseTransformPoint(transformDelta.Pivot)); if (transformDelta.Mode != PivotMode.Mesh && InputManager.State.ToolTransformMode != ToolTransformMode.TransformingLr) { uTransform.position += uTransform.rotation * pivotLocal; } uTransform.rotation = transformDelta.Rotate * uTransform.rotation; if (transformDelta.Mode != PivotMode.Mesh && InputManager.State.ToolTransformMode != ToolTransformMode.TransformingLr) { uTransform.position -= uTransform.rotation * pivotLocal; } // This should draw a line from the mesh center to the pivot // Debug.DrawRay(transformDelta.Pivot, uTransform.rotation * -pivotLocal, Color.magenta); }
/// <summary> /// Find out the <see cref="TransformDelta"/> that should be done. /// Independent of what we are transforming, mesh or selection. /// </summary> /// <param name="consumeInput">Should we reset the starting positions/rotations of the hands. /// This is unrelated to the <see cref="MeshInputState.Consume"/> function which is for the worker thread</param> /// <param name="transformDelta">Where we should add our transformation to.</param> private void GetTransformDelta(bool consumeInput, ref TransformDelta transformDelta, Space space, bool withRotate, bool isTwoHanded, bool primaryHand) { if (isTwoHanded) { GetTransformTwoHanded(ref transformDelta, withRotate); } else if (primaryHand ? _doTransformR : _doTransformL) { GetTransformOneHanded(primaryHand, ref transformDelta, withRotate); } // Update pivot to latest (overwrites for now) if (InputManager.State.ActivePivotMode == PivotMode.Hand) { transformDelta.Pivot = primaryHand ? InputManager.State.HandPosR : InputManager.State.HandPosL; } else { transformDelta.Pivot = Mesh.transform.position; } if (space == Space.Self) { // Conversions to local space var uTransform = Mesh.transform; transformDelta.Translate = uTransform.InverseTransformVector(transformDelta.Translate); transformDelta.Pivot = uTransform.InverseTransformPoint(transformDelta.Pivot); transformDelta.Rotate = Quaternion.Inverse(uTransform.rotation) * transformDelta.Rotate * uTransform.rotation; } if (consumeInput) { ResetTransformStartPositions(); } }
/// <summary> /// Finds out the transformation when using one hand /// </summary> private void GetTransformOneHanded(bool isRight, ref TransformDelta transformDelta, bool withRotate = true) { Vector3 translate; if (isRight) { translate = InputManager.State.HandPosR - _transformStartHandPosR; } else { translate = InputManager.State.HandPosL - _transformStartHandPosL; } var softFactor = isRight ? InputManager.State.GripR : InputManager.State.GripL; transformDelta.Translate += translate * softFactor; // Rotate - Optional if (!withRotate) { return; } Quaternion rotate; if (isRight) { rotate = InputManager.State.HandRotR * Quaternion.Inverse(_transformStartHandRotR); } else { rotate = InputManager.State.HandRotL * Quaternion.Inverse(_transformStartHandRotL); } transformDelta.Rotate = Quaternion.Lerp(Quaternion.identity, rotate, softFactor) * transformDelta.Rotate; }
/// <summary> /// (experimental) Combines two transformations, does not consider the pivot. /// </summary> public void Add(TransformDelta other) { Translate += other.Translate; Rotate = other.Rotate * Rotate; Scale *= other.Scale; }