public static void ImportImage(string path) { path = Path.Combine(App.MediaLibraryPath(), "Images", path); var image = new ReferenceImage(path); image.RequestLoad(allowMainThread: true); var tr = new TrTransform(); tr.translation = ApiManager.Instance.BrushPosition; tr.rotation = ApiManager.Instance.BrushRotation; CreateWidgetCommand createCommand = new CreateWidgetCommand( WidgetManager.m_Instance.ImageWidgetPrefab, tr); SketchMemoryScript.m_Instance.PerformAndRecordCommand(createCommand); ImageWidget imageWidget = createCommand.Widget as ImageWidget; imageWidget.ReferenceImage = image; imageWidget.Show(true); createCommand.SetWidgetCost(imageWidget.GetTiltMeterCost()); WidgetManager.m_Instance.WidgetsDormant = false; SketchControlsScript.m_Instance.EatGazeObjectInput(); SelectionManager.m_Instance.RemoveFromSelection(false); }
/// Pass a Canvas parent, and a transform in that canvas's space. /// If overrideDesc passed, use that for the visuals -- m_CurrentBrush does not change. public void CreateNewLine(CanvasScript canvas, TrTransform xf_CS, ParametricStrokeCreator creator, BrushDescriptor overrideDesc = null) { // If straightedge is enabled, we may have a minimum size requirement. // Initialize parametric stroke creator for our type of straightedge. // Maybe change the brush to a proxy brush. BrushDescriptor desc = overrideDesc != null ? overrideDesc : m_CurrentBrush; m_CurrentCreator = creator; // Parametric creators want control over the brush size. if (m_CurrentCreator != null) { m_ParametricCreatorBackupStrokeSize = m_CurrentBrushSize; m_CurrentBrushSize = m_CurrentCreator.ProcessBrushSize(m_CurrentBrushSize); } m_LastUsedBrushSize_CS = (1 / Coords.CanvasPose.scale) * BrushSizeAbsolute; m_LineLength_CS = 0.0f; m_CurrentLine = BaseBrushScript.Create( canvas.transform, xf_CS, desc, m_CurrentColor, m_CurrentBrushSize); }
/// Copies and pastes the current selection to the current canvas. public void DuplicateSelection(bool offsetDuplicate = false) { TrTransform xf = SelectionManager.m_Instance.SelectionTransform; if (offsetDuplicate) { // Scoot all the strokes and widgets. // TODO: Make this relative to the user's facing. Vector3 offset = m_DuplicateOffset / App.Scene.Pose.scale * 0.5f; xf.translation += offset; } // Lil' jiggle. var controller = InputManager.ControllerName.Brush; if (SketchControlsScript.m_Instance.OneHandGrabController != InputManager.ControllerName.None) { controller = SketchControlsScript.m_Instance.OneHandGrabController; } InputManager.m_Instance.TriggerHapticsPulse(controller, 3, 0.15f, 0.07f); AudioManager.m_Instance.PlayDuplicateSound(InputManager.m_Instance.GetControllerPosition(controller)); SketchMemoryScript.m_Instance.PerformAndRecordCommand(new DuplicateSelectionCommand(xf)); }
// A simplified version of TwoPointObjectTransformation. The following properties are true: // 1. The object-local-space direction between the left and right hands remains constant. // 2. The object-local-space position of LerpUnclamped(left, right, constraintPositionT) remains // constant. // 3. obj1 has the same scale as obj0. // 4. (Corollary of 1-3) The object-local-space positions of left and right remain constant, if // the distance between them does not change. public static TrTransform TwoPointObjectTransformationNoScale( TrTransform gripL0, TrTransform gripR0, TrTransform gripL1, TrTransform gripR1, TrTransform obj0, float constraintPositionT) { // Vectors from left-hand to right-hand Vector3 vLR0 = (gripR0.translation - gripL0.translation); Vector3 vLR1 = (gripR1.translation - gripL1.translation); Vector3 pivot0; TrTransform xfDelta; { pivot0 = Vector3.LerpUnclamped(gripL0.translation, gripR0.translation, constraintPositionT); var pivot1 = Vector3.LerpUnclamped(gripL1.translation, gripR1.translation, constraintPositionT); xfDelta.translation = pivot1 - pivot0; xfDelta.translation = Vector3.LerpUnclamped( gripL1.translation - gripL0.translation, gripR1.translation - gripR0.translation, constraintPositionT); // TODO: check edge cases: // - |vLR0| or |vLR1| == 0 (ie, from and/or to are undefined) // - vLR1 == vLR0 * -1 (ie, infinite number of axes of rotation) xfDelta.rotation = Quaternion.FromToRotation(vLR0, vLR1); xfDelta.scale = 1; } Quaternion deltaL = ConstrainRotationDelta(gripL0.rotation, gripL1.rotation, vLR0); Quaternion deltaR = ConstrainRotationDelta(gripR0.rotation, gripR1.rotation, vLR0); xfDelta = TrTransform.R(Quaternion.Slerp(deltaL, deltaR, 0.5f)) * xfDelta; // Set pivot point xfDelta = xfDelta.TransformBy(TrTransform.T(pivot0)); return(xfDelta * obj0); }
public void Deserialize() { m_Scene.Read(m_xformName, m_UsdCamera); var basisMat = Matrix4x4.identity; if (m_UnitsInMeters) { basisMat[0, 0] *= App.METERS_TO_UNITS; basisMat[1, 1] *= App.METERS_TO_UNITS; basisMat[2, 2] *= -1 * App.METERS_TO_UNITS; } m_UsdCamera.transform = ExportUtils.ChangeBasis(m_UsdCamera.transform, basisMat, basisMat.inverse); TrTransform xf_WS = UsdXformToWorldSpaceXform(m_UsdCamera); TrTransform old_WS = TrTransform.FromTransform(transform); TrTransform new_WS = TrTransform.Lerp(old_WS, xf_WS, 1 - m_Smoothing); new_WS.scale = m_UsdCameraInfo.eyeScale != 0 ? m_UsdCameraInfo.eyeScale : 1; new_WS.ToTransform(transform); // Pre-M23.3, .usd files won't have fov defined, so this value will be negative. if (m_UsdCamera.fov > 0) { // A bit brute force, but we're running through all cameras in the scene to make // sure the preview shows the modified fov. for (int i = 0; i < m_PlaybackCameras.Length; ++i) { if (m_PlaybackCameras[i].gameObject.activeInHierarchy && m_PlaybackCameras[i].isActiveAndEnabled) { m_PlaybackCameras[i].fieldOfView = m_UsdCamera.fov; } } } }
public void TestTransformVector4AsZDistance() { TrTransform randomXf = RandomTr(); int listSize = 10; var list = RandomVector4List(listSize); var listDuplicate = new List <Vector4>(list); int iVert = 3; int iVertEnd = 8; // Do the original version. for (int i = iVert; i < iVertEnd; i++) { list[i] = new Vector4(list[i].x, list[i].y, randomXf.scale * list[i].z, list[i].w); } // Do the math utils version. MathUtils.TransformVector4AsZDistance(randomXf.scale, iVert, iVertEnd, listDuplicate.GetBackingArray()); // Check results. for (int i = 0; i < listSize; i++) { AssertAlmostEqual(list[i], listDuplicate[i]); } }
public override Bounds GetBounds_SelectionCanvasSpace() { if (m_Capsule != null) { TrTransform colliderToCanvasXf = App.Scene.SelectionCanvas.Pose.inverse * TrTransform.FromTransform(m_Capsule.transform); Bounds bounds = new Bounds(colliderToCanvasXf * m_Capsule.center, Vector3.zero); // Transform the corners of the widget bounds into canvas space and extend the total bounds // to encapsulate them. Vector3 capsuleSize = new Vector3(2 * m_Capsule.radius, m_Capsule.height, 2 * m_Capsule.radius); for (int i = 0; i < 8; i++) { bounds.Encapsulate(colliderToCanvasXf * (m_Capsule.center + Vector3.Scale( capsuleSize, new Vector3((i & 1) == 0 ? -0.5f : 0.5f, (i & 2) == 0 ? -0.5f : 0.5f, (i & 4) == 0 ? -0.5f : 0.5f)))); } return(bounds); } return(base.GetBounds_SelectionCanvasSpace()); }
/// Changes the coordinate system of an active transformation. /// /// 'this' should be an active transformation, like "rotate 10 degrees about up". /// Its input and output coordinate systems should be the same. /// /// 'rhs' should be a passive transformation -- like a WorldFromObject /// coordinate change (aka a pose). Its input coordinate system should /// be the same as the coordinate system of 'this'. /// /// Returns a transform that performs the same action as 'this', but that operates /// in a different coordinate system: the output coordinate system of 'rhs'. /// /// See also https://en.wikipedia.org/wiki/Active_and_passive_transformation public TrTransform TransformBy(TrTransform rhs) { // Solving "X * rhs == rhs * this" for X, we get // // X = rhs * this * inv(rhs) // // However, this naive calculation is inaccurate; manually expanding and // simplifying allows an unnecessary multiply+divide by rhs.scale to be // removed. // // This increases accuracy of .translation and .scale, and avoids problems // when rhs is non-invertible as a result of zero scale. Quaternion similar = (rhs.rotation * this.rotation * rhs.rotation.TrueInverse()); Vector3 retTrans = similar * (-this.scale * rhs.translation) + rhs.rotation * (rhs.scale * this.translation) + rhs.translation; return(new TrTransform { translation = retTrans, rotation = similar, scale = this.scale }); }
public override Bounds GetBounds_SelectionCanvasSpace() { if (m_Collider != null) { SphereCollider sphere = m_Collider as SphereCollider; TrTransform colliderToCanvasXf = App.Scene.SelectionCanvas.Pose.inverse * TrTransform.FromTransform(m_Collider.transform); Bounds bounds = new Bounds(colliderToCanvasXf * sphere.center, Vector3.zero); // Transform the corners of the widget bounds into canvas space and extend the total bounds // to encapsulate them. for (int i = 0; i < 8; i++) { bounds.Encapsulate(colliderToCanvasXf * (sphere.center + sphere.radius * new Vector3((i & 1) == 0 ? -1.0f : 1.0f, (i & 2) == 0 ? -1.0f : 1.0f, (i & 4) == 0 ? -1.0f : 1.0f))); } return(bounds); } return(base.GetBounds_SelectionCanvasSpace()); }
override public void ResetBrushForPreview(TrTransform localPointerXf) { base.ResetBrushForPreview(localPointerXf); m_UpdateTangentRequest.Clear(); }
protected override void InitBrush(BrushDescriptor desc, TrTransform localPointerXf) { base.InitBrush(desc, localPointerXf); m_UpdateTangentRequest.Clear(); }
public TrTransform this[Transform t] { get { return(TrTransform.FromTransform(t)); } set { value.ToTransform(t); } }
public void SetLossyTransform(TrTransform transform) { vRigPosition = transform.translation; qRigRotation = transform.rotation; qAutoOrientJointLocalRotation = Quaternion.identity; }
/// Like TwoPointNonUniformScale, but instead of scaling, adds size to an axis public static TrTransform TwoPointObjectTransformationAxisResize( Vector3 vScaleAxis0, float sizeAlongAxis, TrTransform gripL0, TrTransform gripR0, // prev TrTransform gripL1, TrTransform gripR1, // next TrTransform obj0, out float deltaScale, float deltaScaleMin = 0, float deltaScaleMax = float.PositiveInfinity) { // The vectors from left -> right hand can be decomposed into // "along scale axis" and "across scale axis". // The length of "along scale axis" varies; the change is the amount of scaling. // The length of "across scale axis" remains constant, because it doesn't scale. bool shrinkageSideIsLeft; float allowedShrinkage; float along0; Vector3 vAcross; { Vector3 vLR0 = (gripR0.translation - gripL0.translation); along0 = Vector3.Dot(vLR0, vScaleAxis0); // Prevent negative scale by ensuring Sign(along0) == Sign(along1). // This causes the scale to turn into rotation. Note that Sign(along1) always == 1. // It also simplifies the following along0 and shrinkage checks. float sign = Mathf.Sign(along0); along0 *= sign; vScaleAxis0 *= sign; vAcross = vLR0 - along0 * vScaleAxis0; Vector3 center = obj0.translation; float halfExtent = sizeAlongAxis / 2; // Allow the right edge to be pushed all the way to the left hand, but no farther; // and vice versa for the left edge + right hand. float leftShrinkage = halfExtent - Vector3.Dot(vScaleAxis0, gripL0.translation - center); float rightShrinkage = halfExtent - Vector3.Dot(vScaleAxis0, center - gripR0.translation); if (leftShrinkage < rightShrinkage) { allowedShrinkage = leftShrinkage; shrinkageSideIsLeft = true; } else { allowedShrinkage = rightShrinkage; shrinkageSideIsLeft = false; } // Might be < 0 if both hands are outside the extents (which won't normally happen) allowedShrinkage = Mathf.Max(0, allowedShrinkage); } float along1; { // Calculate |vAlong1| using the identity: // |vLR|^2 = |vAlong|^2 + |vAcross|^2 Vector3 vLR1 = (gripR1.translation - gripL1.translation); float along1Squared = vLR1.sqrMagnitude - vAcross.sqrMagnitude; if (along1Squared < 0) { // Impossible to satisfy the constraint. We can refuse to scale (along1 = along0), // or clamp the scale to the nearest valid value (along1 = 0). along1 = 0; } else { along1 = Mathf.Sqrt(along1Squared); } } // Calculate and apply constraints to deltaScale { float sizeAlongAxis1 = sizeAlongAxis + Mathf.Max(-allowedShrinkage, along1 - along0); deltaScale = sizeAlongAxis1 / sizeAlongAxis; // If hands switch, treat that as rotation rather than inverting the object deltaScale = Mathf.Abs(deltaScale); deltaScale = Mathf.Clamp(deltaScale, deltaScaleMin, deltaScaleMax); // Find new hand positions. Unlike TwoPointNonUniformScale, this isn't a // simple scale of the positions. The invariant is that each hand is // a constant distance from the left/right end of the object. // // The easiest way of doing this is computing the change in position of // the left/right object endpoints and applying that to the left/right hand. // Since the object is assumed to be symmetric about the object's origin, // the left and right object endpoints move the same amount of deltaSize/2 float deltaSize = sizeAlongAxis * (deltaScale - 1); Vector3 offset = vScaleAxis0 * deltaSize; // The t values of -.5f and .5f reflect the symmetry of the object; // if it were asymmetric they would be calculated. gripL0.translation += -.5f * offset; gripR0.translation += .5f * offset; } // Reuse TwoPoint to compute T and R. return(TwoPointObjectTransformationNoScale( gripL0, gripR0, gripL1, gripR1, obj0, shrinkageSideIsLeft ? 0f : 1f)); }
// Construct transform obj1 such that: // - inv(obj0) * L0.pos == inv(obj1) * L1.pos // - inv(obj0) * R0.pos == inv(obj1) * L1.pos // // In other words, the left and right grip points on the old object // are the same as the left and right grip points on the new object. // (Note that the optional constraints may then change the result.) // // Note that if abs(R0-L0) != abs(R1-L1), then a scaling is necessary. // This methods applies scale about the passed axis only. // // Given 2 position deltas, there are 6 DOFs available: // = 3DOF (movement of average position) // + 2DOF (change of direction of vector between L and R) // + 1DOF (scaling, change of length of LR projected onto the scale axis) // // We need one more DOF to fully specify the rotation. We can get this // from L and R's rotations about the L-R vector (either old or // new, doesn't really matter). // // Pass: // scaleAxis - // Must be unit-length. Scaling is applied along this axis only. // gripL0, L1, R0, R1 - // The left and right grip points, in their old (0) and new (1) positions. // The scale portion of the TrTransform is ignored. // obj0 - // Transform of the object being manipulated. // out deltaScale - // Returns the difference in scale along the given axis. // finalScaleMin - // Ignore scaling when gripL0 and gripR0 are closer together along scaleAxis than this. // TODO: rename to finalScaleMin is a bad name for this parameter. // deltaScale{Min,Max} - // Constrains the range of deltaScale. // Negative means do not constrain that endpoint. // Note that it is very easy for zero deltaScale to be returned // // Returns: // result.position, result.rotation - // new position and rotation // result.scale - undefined; do not use // deltaScale - change in scale along vScaleAxis0, as a multiplier public static TrTransform TwoPointObjectTransformationNonUniformScale( Vector3 vScaleAxis0, TrTransform gripL0, TrTransform gripR0, // prev TrTransform gripL1, TrTransform gripR1, // next TrTransform obj0, out float deltaScale, float finalScaleMin = -1.0f, float deltaScaleMin = -1.0f, float deltaScaleMax = -1.0f ) { // The vectors from left -> right hand can be decomposed into // "along scale axis" and "across scale axis". // The length of "along scale axis" varies; the change is the amount of scaling. // The length of "across scale axis" remains constant, because it doesn't scale. float constraintPositionT = 0.5f; float along0; Vector3 vAcross; Vector3 vLR0; { vLR0 = (gripR0.translation - gripL0.translation); along0 = Vector3.Dot(vLR0, vScaleAxis0); // Prevent negative scale by ensuring Sign(along0) == Sign(along1). // This causes the scale to turn into rotation. Note that Sign(along1) always == 1. // It also simplifies the following along0 checks. float sign = Mathf.Sign(along0); along0 *= sign; vScaleAxis0 *= sign; vAcross = vLR0 - along0 * vScaleAxis0; // Ignore scaling along the axis when the controllers are too close together. // Also ignore in unstable cases. if (along0 < finalScaleMin || along0 < 1e-5f) { deltaScale = 1; return(TwoPointObjectTransformationNoScale(gripL0, gripR0, gripL1, gripR1, obj0, constraintPositionT)); } } float along1; Vector3 vLR1; { // Calculate |vAlong1| using the identity: // |vLR|^2 = |vAlong|^2 + |vAcross|^2 vLR1 = (gripR1.translation - gripL1.translation); float along1Squared = vLR1.sqrMagnitude - vAcross.sqrMagnitude; if (along1Squared < 0) { // Impossible to satisfy the constraint. We can refuse to scale (along1 = along0), // or clamp the scale to the nearest valid value (along1 = 0). along1 = 0; } else { along1 = Mathf.Sqrt(along1Squared); } } deltaScale = along1 / along0; // For min scale clamping, constrain to the object center if it's between the controllers or to // the controller closest to the object center. if (deltaScaleMin > 0 && deltaScale < deltaScaleMin) { deltaScale = deltaScaleMin; // Calculate a ratio such that (ratio * gripR0 + (1 - ratio) * gripL0) lies on the plane that // is perpendicular to the non-uniform scale axis and goes through the object center. This is // used as the pivot for the transformation. float factorL = Vector3.Dot(vScaleAxis0, gripL0.translation); float factorR = Vector3.Dot(vScaleAxis0, gripR0.translation); float factorObj = Vector3.Dot(vScaleAxis0, obj0.translation); constraintPositionT = (factorObj - factorL) / (factorR - factorL); constraintPositionT = Mathf.Clamp01(constraintPositionT); } // For max scale clamping, constrain to the position between the two controllers. if (deltaScaleMax > 0 && deltaScale > deltaScaleMax) { deltaScale = deltaScaleMax; constraintPositionT = 0.5f; } // TwoPointNoScale can be used to compute T and R since those calculations are independent of S. // In the case where deltaScale == along1 / along0 (ie., where the scale has not been clamped), // using ScalePosition here will ensure |LR0| = |LR1|, so TwoPointNoScale can be used safely. // When scale is clamped, ScalePosition will compensate the initial positions as far as they // will go until the clamp and then TwoPointNoScale will compute T and R while keeping the // passed in constraint position fixed. gripL0.translation = ScalePosition( gripL0.translation, deltaScale, obj0.translation, vScaleAxis0); gripR0.translation = ScalePosition( gripR0.translation, deltaScale, obj0.translation, vScaleAxis0); return(TwoPointObjectTransformationNoScale(gripL0, gripR0, gripL1, gripR1, obj0, constraintPositionT)); }
// Continue drawing stroke for this frame. public void Update() { if (m_isDone) { return; } var rPointerScript = m_pointer; var rPointerObject = m_pointer.gameObject; bool needMeshUpdate = false; bool needPointerUpdate = false; bool strokeFinished = false; var lastCp = new PointerManager.ControlPoint(); OverlayManager.m_Instance.UpdateProgress(SketchMemoryScript.m_Instance.GetDrawnPercent()); RdpStrokeSimplifier simplifier = QualityControls.m_Instance.StrokeSimplifier; if (simplifier.Level > 0.0f) { simplifier.CalculatePointsToDrop(m_stroke, m_pointer.CurrentBrushScript); } while (true) { if (m_nextControlPoint >= m_stroke.m_ControlPoints.Length) { needMeshUpdate = true; // Is this really necessary? strokeFinished = true; break; } var cp = m_stroke.m_ControlPoints[m_nextControlPoint]; if (!IsControlPointReady(cp)) { break; } if (!m_stroke.m_ControlPointsToDrop[m_nextControlPoint]) { rPointerScript.UpdateLineFromControlPoint(cp); needMeshUpdate = true; lastCp = cp; needPointerUpdate = true; } ++m_nextControlPoint; } if (needMeshUpdate) { rPointerScript.UpdateLineVisuals(); } if (needPointerUpdate) { // This is only really done for visual reasons var xf_GS = Coords.CanvasPose * TrTransform.TR(lastCp.m_Pos, lastCp.m_Orient); xf_GS.scale = rPointerObject.transform.GetUniformScale(); Coords.AsGlobal[rPointerObject.transform] = xf_GS; rPointerScript.SetPressure(lastCp.m_Pressure); } if (strokeFinished) { rPointerScript.EndLineFromMemory(m_stroke); m_isDone = true; } }
/// The command takes additional ownership over the objects passed, copying its /// objects into a new array that is never mutated. /// /// Initial pose is the pose of the selection from before the selection/deselection /// takes place. It's needed because if the action is to deselect the very last objects, /// the SelectionManager will automatically reset the selection transform to identity. And /// then if we want to undo that selection, we need to restore its initial transform so that /// the selection widget is appropriately rotated. /// /// Preserving the orientation of the selection widget is important for two reasons: /// 1: Aesthetics. If a user deselects a rotated selection then immediately undoes that /// deselection, it would be jarring if the selection bounds rotated. /// 2: To preserve undoing transformations of the selection widget. When the user grabs and moves /// the selection, the selection widget maintains its own movewidget commands on the stack, so /// it'd expect the widget not to have been moved by an outside party between redoing a move /// and then undoing it. public SelectCommand( ICollection <Stroke> strokes, ICollection <GrabWidget> widgets, TrTransform initialTransform, bool deselect = false, bool initial = false, bool checkForClearedSelection = false, bool isGrabbingGroup = false, bool isEndGrabbingGroup = false, BaseCommand parent = null) : base(parent) { var selectedGroups = new HashSet <SketchGroupTag>(); var strokesNotGrouped = new HashSet <Stroke>(); if (strokes != null) { // Get strokes that are not grouped and groups among selected strokes. foreach (var stroke in strokes) { if (stroke.Group == SketchGroupTag.None) { strokesNotGrouped.Add(stroke); } else { selectedGroups.Add(stroke.Group); } } } var widgetsNotGrouped = new HashSet <GrabWidget>(); if (widgets != null) { // Get widgets that are not grouped and groups among selected widgets. foreach (var widget in widgets) { if (widget.Group == SketchGroupTag.None) { widgetsNotGrouped.Add(widget); } else { selectedGroups.Add(widget.Group); } } } // Get the grouped strokes. var strokesGrouped = new HashSet <Stroke>(); foreach (var group in selectedGroups) { strokesGrouped.UnionWith(SelectionManager.m_Instance.StrokesInGroup(group)); } // Get the grouped widgets. var widgetsGrouped = new HashSet <GrabWidget>(); foreach (var group in selectedGroups) { widgetsGrouped.UnionWith(SelectionManager.m_Instance.WidgetsInGroup(group)); } m_Strokes = new List <Stroke>(); m_Strokes.AddRange(strokesGrouped); m_Strokes.AddRange(strokesNotGrouped); m_Widgets = new List <GrabWidget>(); m_Widgets.AddRange(widgetsGrouped); m_Widgets.AddRange(widgetsNotGrouped); m_InitialTransform = initialTransform; m_Deselect = deselect; m_Initial = initial; m_CheckForClearedSelection = checkForClearedSelection; m_IsGrabbingGroup = isGrabbingGroup; m_IsEndGrabbingGroup = isEndGrabbingGroup; }
void OnPoseChanged(TrTransform prev, TrTransform current) { m_CameraComponent.nearClipPlane = m_CameraClipPlanesBase.x * current.scale; m_CameraComponent.farClipPlane = m_CameraClipPlanesBase.y * current.scale; }
// -------------------------------------------------------------------------------------------- // // Tracking Methods // -------------------------------------------------------------------------------------------- // /// Clears the callbacks that get called when a new pose is received. The callbacks are saved /// So that they can be restored later with RestorePoseTracking. public void DisablePoseTracking() { m_TrackingBackupXf = TrTransform.FromTransform(GetVrCamera().transform); m_OldOnPoseApplied = NewControllerPosesApplied.GetInvocationList().Cast <Action>().ToArray(); NewControllerPosesApplied = null; }
private void OnScenePoseChanged(TrTransform prev, TrTransform current) { UpdateBoxCollider(); }
protected override void InitBrush(BrushDescriptor desc, TrTransform localPointerXf) { base.InitBrush(desc, localPointerXf); CommonInit(localPointerXf); }
void ApplyLazyInput(ref Vector3 pos, ref Quaternion rot) { if (!m_PaintingActive || !m_LazyInputActive || m_GridSnapActive) { if (m_GridSnapActive) { ApplyGridSnap(ref pos, ref rot); } m_btCursorPos = pos; m_btCursorRot = rot; m_lazyInputRate = 0; EndLazyInputVisuals(); return; } UpdateLazyInputRate(); //Vector3 beeline = pos - m_btCursorPos; // //// Vector3 beelineDelta = Vector3.Lerp(Vector3.zero, beeline, m_lazyInputRate); // //Vector3 oldCursorNormal = m_btCursorRot * Vector3.forward; //Vector3 newCursorNormal = rot * Vector3.forward; // //Vector3 forwardDelta = Vector3.ProjectOnPlane(beeline, oldCursorNormal); //Vector3 midPointDelta = Vector3.Project(Vector3.ProjectOnPlane(beeline, newCursorNormal), forwardDelta.normalized); // //float midPointLerp = Mathf.InverseLerp(0, beeline.magnitude, Vector3.Project(midPointDelta, beeline.normalized).magnitude); // //m_btCursorRot = Quaternion.Slerp(m_btCursorRot, rot, Mathf.Lerp(midPointLerp, 1, Mathf.Abs(Vector3.Dot(beeline.normalized, newCursorNormal))) * m_lazyInputRate); // //Vector3 posDelta = Vector3.Lerp(Vector3.zero, Vector3.Lerp(midPointDelta, beeline, midPointLerp), m_lazyInputRate); //m_btCursorPos = m_btCursorPos + posDelta; // //// if (beelineDelta.magnitude > 0) { //// m_btCursorPos = m_btCursorPos + beelineDelta; //// //// m_btCursorRot = Quaternion.Slerp(m_btCursorRot, rot, m_lazyInputRate); //// } TrTransform result = LazyLerp(TrTransform.TRS(m_btCursorPos, m_btCursorRot, PointerManager.m_Instance.MainPointer.BrushSizeAbsolute), TrTransform.TRS(pos, rot, PointerManager.m_Instance.MainPointer.BrushSizeAbsolute), m_lazyInputRate, m_LazyInputTangentMode); m_btCursorPos = result.translation; m_btCursorRot = result.rotation; pos = m_btCursorPos; rot = m_btCursorRot; UpdateLazyInputVisuals(); }
// // GeometryBrush API // protected override void InitBrush(BrushDescriptor desc, TrTransform localPointerXf) { base.InitBrush(desc, localPointerXf); m_geometry.Layout = GetVertexLayout(desc); }
override protected void OnButtonPressed() { if (WidgetManager.m_Instance.StencilsDisabled) { WidgetManager.m_Instance.StencilsDisabled = false; } SketchMemoryScript.m_Instance.PerformAndRecordCommand(new CreateWidgetCommand( WidgetManager.m_Instance.GetStencilPrefab(m_Type), TrTransform.FromTransform(transform))); SketchControlsScript.m_Instance.EatGazeObjectInput(); SelectionManager.m_Instance.RemoveFromSelection(false); }
private void OnSelectionTransformed(TrTransform xf_SS) { SelectionTransform = xf_SS; }
private TrTransform UsdXformToWorldSpaceXform(USD.NET.Unity.XformSample usdXform) { TrTransform xf_CS = TrTransform.FromMatrix4x4(usdXform.transform); return(TrTransform.FromTransform(App.Scene.ActiveCanvas.transform) * xf_CS); }
public void ResetInitialTransform() { m_InitialTransform = TrTransform.identity; }
protected override void MaybeCreateChildrenImpl() { // TODO: when too many children, starve an old one in order to create another. int kBranchCount = 12; int kFrondCount = 16; if (m_recursionLevel == 0) { // Trunk if (m_children.Count == 0) { InitializeAndAddChild(new PbChildIdentityXf(), m_trunkBrush, m_trunkColor); } if (DistanceSinceLastKnotBasedChild() > m_branchFrequency && m_children.Count < kBranchCount + 1) { int salt = m_children.Count; // Children 1 - 13 are the branches; early ones grow faster. float growthPercent = (kBranchCount + 1 - (float)m_children.Count) / kBranchCount; TrTransform offset = // Branches don't extend as quickly as the trunk TrTransform.S(m_branchScale * growthPercent) * // Randomly place around the tree TrTransform.R(m_rng.InRange(salt, 0f, 360f), Vector3.forward) * // Angle the branches backwards (away from the stroke tip) TrTransform.R(120, Vector3.right); InitializeAndAddChild( new PbChildWithOffset(m_knots.Count - 1, AttachFrame.LineTangent, offset, 0), m_Desc, // Recurse with same brush Color.white, m_branchRelativeSize); } } else if (m_recursionLevel == 1) { // Branch if (m_children.Count == 0) { InitializeAndAddChild(new PbChildIdentityXf(), m_branchBrush, m_branchColor); } // TODO: would like this frequency to be higher for tinier branches if (DistanceSinceLastKnotBasedChild() > m_frondFrequency && m_children.Count < kFrondCount + 1) { float growthPercent = 1; // (kFrondCount + 1 - (float)m_children.Count) / kFrondCount; for (int deg = -30; deg <= 30; deg += 60) { TrTransform offset = // Fronds don't grow as quickly as the branch TrTransform.S(m_frondScale * growthPercent) * TrTransform.R(deg, Vector3.up); InitializeAndAddChild( new PbChildWithOffset(m_knots.Count - 1, AttachFrame.LineTangent, offset, 0), m_frondBrush, m_frondColor, m_frondRelativeSize); TrTransform decoOffset = TrTransform.T(m_decoOffset); InitializeAndAddChild( new PbChildWithOffset(-1, AttachFrame.LineTangent, decoOffset, m_decoTwist), m_decoBrush, Color.white, m_frondRelativeSize); } } } }
private void OnScenePoseChanged(TrTransform prev, TrTransform current) { m_ContainerBloat *= prev.scale / current.scale; UpdateScale(); }
// Constructs an updated transform obj1 such that the object-space // positions of the left and right grip are invariant. More generally, // all points on the line L->R are invariant. Precisely: // // - inv(obj0) * L0.pos == inv(obj1) * L1.pos // - inv(obj0) * R0.pos == inv(obj1) * L1.pos // // If abs(R0-L0) != abs(R1-L1), then a scaling is necessary. // This method chooses to apply a uniform scale. // // If scale bounds kick in, only a single point on the L->R line can // be made invariant; see bUseLeftAsPivot for how this is chosen. // // Given 2 position deltas, there are 6 DOFs available: // = 3DOF (movement of average position) // + 2DOF (change of direction of vector between L and R) // + 1DOF (scaling, change of length of vector between L and R) // // One more DOF is needed to fully specify the rotation. This method // chooses to get it from L and R's rotations about the L-R vector. // // Pass: // gripL0, L1, R0, R1 - // The left and right grip points, in their old (0) and new (1) positions. // The scale portion of the TrTransform is ignored. // obj0 - // Transform of the object being manipulated. // deltaScale{Min,Max} - // Constrains the range of result.scale. // Negative means do not constrain that endpoint. // rotationAxisConstraint - // Constrains the value of result.rotation. If passed, the delta rotation // from obj0 -> result will only be about this axis. // bUseLeftAsPivot - // Controls the invariant point if scale constraints are applied. // If false, uses the midpoint between L and R. // If true, uses the point L. // // Returns: // New position, rotation, and scale static public TrTransform TwoPointObjectTransformation( TrTransform gripL0, TrTransform gripR0, // prev TrTransform gripL1, TrTransform gripR1, // next TrTransform obj0, float deltaScaleMin = -1.0f, float deltaScaleMax = -1.0f, Vector3 rotationAxisConstraint = default(Vector3), bool bUseLeftAsPivot = false) { // Vectors from left-hand to right-hand Vector3 vLR0 = (gripR0.translation - gripL0.translation); Vector3 vLR1 = (gripR1.translation - gripL1.translation); // World-space position whose object-space position is used to constrain obj1 // inv(obj0) * vInvariant0 = inv(obj1) * vInvariant1 Vector3 vInvariant0, vInvariant1; { // Use left grip or average of grips as pivot point. Maybe switch the // bool to be a parametric t instead, so if caller wants to use right // grip as pivot they don't need to swap arguments? float t = bUseLeftAsPivot ? 0f : 0.5f; vInvariant0 = Vector3.Lerp(gripL0.translation, gripR0.translation, t); vInvariant1 = Vector3.Lerp(gripL1.translation, gripR1.translation, t); } // Strategy: // 1. Move invariant point to the correct spot, with a translation. // 2. Rotate about that point. // 3. Uniform scale about that point. // Items 2 and 3 can happen in the same TrTransform, since rotation // and uniform scale commute as long as they use the same pivot. TrTransform xfDelta1 = TrTransform.T(vInvariant1 - vInvariant0); TrTransform xfDelta23; { // calculate worldspace scale; will adjust center-of-scale later float dist0 = vLR0.magnitude; float dist1 = vLR1.magnitude; float deltaScale = (dist0 == 0) ? 1 : dist1 / dist0; // Clamp scale if requested. if (deltaScaleMin >= 0) { deltaScale = Mathf.Max(deltaScale, deltaScaleMin); } if (deltaScaleMax >= 0) { deltaScale = Mathf.Min(deltaScale, deltaScaleMax); } // This gets the left-right axis pointing in the correct direction Quaternion qSwing0To1 = Quaternion.FromToRotation(vLR0, vLR1); // This applies some twist about that left-right axis. The choice of constraint axis // (vLR0 vs vLR1) depends on whether qTwist is right- or left-multiplied vs qReach. Quaternion qTwistAbout0 = Quaternion.Slerp( ConstrainRotationDelta(gripL0.rotation, gripL1.rotation, vLR0), ConstrainRotationDelta(gripR0.rotation, gripR1.rotation, vLR0), 0.5f); Quaternion qDelta = qSwing0To1 * qTwistAbout0; // Constrain the rotation if requested. if (rotationAxisConstraint != default(Vector3)) { qDelta = ConstrainRotationDelta(Quaternion.identity, qDelta, rotationAxisConstraint); } xfDelta23 = TrTransform .TRS(Vector3.zero, qDelta, deltaScale) .TransformBy(TrTransform.T(vInvariant1)); } return(xfDelta23 * xfDelta1 * obj0); }