private void UpdateInteract(Hand hand, float3 handPos, ref HandState state) { if (UseToolAction.GetStateDown(hand.handType)) { state.IsActionHeld = true; if (state.HoveredHalfEdge != Entity.Null) { CreateNewVertexAtHover(ref state); } if (MultiSelectAction.GetState(hand.handType)) { StartSelecting(ref state); } else { StartDragging(handPos, ref state); } } else if (state.IsActionHeld && UseToolAction.GetState(hand.handType)) { if (state.IsDragging) { UpdateDragging(hand, handPos, ref state); return; } UpdateSelecting(ref state); } if (state.IsActionHeld && UseToolAction.GetStateUp(hand.handType)) { state.IsActionHeld = false; if (state.IsDragging) { StopDragging(ref state); } } }
private void Update() { if (TargetLevel == null) { return; } var player = Player.instance; var leftValid = player.leftHand.TryGetPointerPosition(out var leftWorldPos) && LeftHandActive; var rightValid = player.rightHand.TryGetPointerPosition(out var rightWorldPos) && RightHandActive; var leftPressed = leftValid && UseToolAction.GetStateDown(SteamVR_Input_Sources.LeftHand); var rightPressed = rightValid && UseToolAction.GetStateDown(SteamVR_Input_Sources.RightHand); var leftReleased = leftValid && UseToolAction.GetStateUp(SteamVR_Input_Sources.LeftHand); var rightReleased = rightValid && UseToolAction.GetStateUp(SteamVR_Input_Sources.RightHand); _leftHeld &= leftValid && UseToolAction.GetState(SteamVR_Input_Sources.LeftHand); _rightHeld &= rightValid && UseToolAction.GetState(SteamVR_Input_Sources.RightHand); var leftLocalPos = TargetLevel.transform.InverseTransformPoint(leftWorldPos); var rightLocalPos = TargetLevel.transform.InverseTransformPoint(rightWorldPos); var crosshairsInvalid = false; // New anchor points if anything pressed or released if (leftPressed || rightPressed || leftReleased || rightReleased) { _leftLocalAnchor = leftLocalPos; _rightLocalAnchor = rightLocalPos; _leftHeld |= leftPressed; _rightHeld |= rightPressed; crosshairsInvalid = true; } // Check for new scale / rotation target if (_leftHeld && _rightHeld) { _worldPivotPos = (leftWorldPos + rightWorldPos) * 0.5f; var betweenAnchorDiff = _rightLocalAnchor - _leftLocalAnchor; var betweenLocalDiff = rightLocalPos - leftLocalPos; var isScaling = Mathf.Abs(betweenAnchorDiff.normalized.y) >= Mathf.Sqrt(0.5f); if (isScaling) { var sizeRatio = betweenLocalDiff.magnitude / betweenAnchorDiff.magnitude; var newScale = TargetLevel.transform.localScale.x * sizeRatio; var logNewScale = math.log10(newScale); var bestScale = 1f; var bestLogScaleDiff = float.PositiveInfinity; foreach (var scale in _scales) { var logScale = math.log10(scale); var logScaleDiff = math.abs(logScale - logNewScale); if (logScaleDiff < bestLogScaleDiff) { bestLogScaleDiff = logScaleDiff; bestScale = scale; } } if (bestScale != _targetScale) { _prevScale = _targetScale; _targetScale = bestScale; _scaleTimer = 1f; player.leftHand.TriggerHapticPulse(500); player.rightHand.TriggerHapticPulse(500); UpdateScaleText(); } } else { var betweenAnchorAngle = Mathf.Atan2(betweenAnchorDiff.z, betweenAnchorDiff.x) * Mathf.Rad2Deg; var betweenLocalAngle = Mathf.Atan2(betweenLocalDiff.z, betweenLocalDiff.x) * Mathf.Rad2Deg; var angleDiff = Mathf.DeltaAngle(betweenLocalAngle, betweenAnchorAngle); var targetAngle = TargetLevel.transform.localEulerAngles.y + angleDiff; targetAngle = math.round(targetAngle / SnapAngle) * SnapAngle; targetAngle -= math.floor(targetAngle / 360f) * 360f; if (Mathf.DeltaAngle(_targetAngle, targetAngle) != 0f) { _prevAngle = _targetAngle; _targetAngle = targetAngle; _angleTimer = 1f; player.leftHand.TriggerHapticPulse(500); player.rightHand.TriggerHapticPulse(500); UpdateAngleText(); } } if (isScaling != _isScaling) { _isScaling = isScaling; crosshairsInvalid = true; } } // Handle rotation / scale animation var rotatedOrScaled = false; if (_scaleTimer > 0f) { _scaleTimer -= Time.deltaTime / EasingTime; var t = Mathf.Clamp01(1f - _scaleTimer); var scale = _prevScale + Easing.InOutCubic(t) * (_targetScale - _prevScale); TargetLevel.transform.localScale = Vector3.one * scale; rotatedOrScaled = true; } if (_angleTimer > 0f) { _angleTimer -= Time.deltaTime / EasingTime; var t = Mathf.Clamp01(1f - _angleTimer); var angle = _prevAngle + Easing.InOutCubic(t) * Mathf.DeltaAngle(_prevAngle, _targetAngle); var curAngle = TargetLevel.transform.localEulerAngles.y; TargetLevel.transform.RotateAround(_worldPivotPos, Vector3.up, angle - curAngle); rotatedOrScaled = true; } // Local positions will have changed if scale or rotation changed if (rotatedOrScaled) { leftLocalPos = TargetLevel.transform.InverseTransformPoint(leftWorldPos); rightLocalPos = TargetLevel.transform.InverseTransformPoint(rightWorldPos); } // Grab translation if (_leftHeld || _rightHeld) { Vector3 anchor, pos; if (_leftHeld && _rightHeld) { anchor = (_leftLocalAnchor + _rightLocalAnchor) * 0.5f; pos = (leftLocalPos + rightLocalPos) * 0.5f; } else { anchor = _leftHeld ? _leftLocalAnchor : _rightLocalAnchor; pos = _leftHeld ? leftLocalPos : rightLocalPos; } var localDiff = pos - anchor; var worldDiff = TargetLevel.transform.TransformVector(localDiff); TargetLevel.transform.Translate(worldDiff, Space.World); } // Update widgets if (crosshairsInvalid) { UpdateCrosshairTextures(); } if (Text.gameObject.activeSelf) { Text.transform.position = _worldPivotPos; Text.transform.rotation = Quaternion.LookRotation(_worldPivotPos - Player.instance.hmdTransform.position); } }