public void GrabUpdate(InteractionPoint interactionPoint) { //dragging started? if (!Dragging) { foreach (var item in _initialInteractionPoses) { if (Vector3.Distance(item.Key.position, item.Value.position) > _dragThreshold) { //halt physics: if (_rigidBody != null) { _rigidBody.velocity = Vector3.zero; _rigidBody.angularVelocity = Vector3.zero; _rigidBody.isKinematic = true; } //find offset: Matrix4x4 matrix = Matrix4x4.TRS(item.Key.position, item.Key.rotation, Vector3.one); Vector3 positionOffset = matrix.inverse.MultiplyPoint3x4(transform.position); Quaternion rotationOffset = Quaternion.Inverse(item.Key.rotation) * transform.rotation; _offset = new Pose(positionOffset, rotationOffset); //resets: _position = Vector3.zero; _rotation = Quaternion.identity; //status: Dragging = true; events.OnDragBegin?.Invoke(item.Key); break; } } } //dragging? if (Dragging) { //find center of interaction points involved with this drag: Bounds dragBounds = new Bounds(activeInteractionPoints[0].position, Vector3.zero); for (int i = 1; i < activeInteractionPoints.Count; i++) { dragBounds.Encapsulate(activeInteractionPoints[i].position); } //discover drag distance and percentage; float biManualDistance = dragBounds.size.magnitude; //holders: Vector3 dragLocation = Vector3.zero; Quaternion dragOrientation = Quaternion.identity; Vector3 forward = Vector3.zero; float scaleDelta = 0; //rotation: if (activeInteractionPoints.Count == 2) { //get rotated amount: forward = activeInteractionPoints[0].position - activeInteractionPoints[1].position; Vector3 forwardNormalized = forward.normalized; Vector3 previousForward = _bimanualBaseRotation * Vector3.forward; Vector3 up = Vector3.Cross(forwardNormalized, previousForward).normalized; float angle = Vector3.SignedAngle(previousForward, forwardNormalized, up); //update rotation: Quaternion rotationDelta = Quaternion.AngleAxis(angle, up); _bimanualBaseRotation = rotationDelta * _bimanualBaseRotation; dragOrientation = _bimanualBaseRotation * _offset.rotation; } else { dragOrientation = activeInteractionPoints[0].rotation * _offset.rotation; } //position: if (activeInteractionPoints.Count == 2) { Matrix4x4 matrix = Matrix4x4.TRS(dragBounds.center, _bimanualBaseRotation, Vector3.one); dragLocation = matrix.MultiplyPoint3x4(_offset.position); } else { Matrix4x4 matrix = Matrix4x4.TRS(activeInteractionPoints[0].position, activeInteractionPoints[0].rotation, Vector3.one); dragLocation = matrix.MultiplyPoint3x4(_offset.position); } //scale: if (activeInteractionPoints.Count == 2) { scaleDelta = biManualDistance - _scaleInitialDistance; } //set smoothing origins: if (_position == Vector3.zero || _rotation == Quaternion.identity) { _position = dragLocation; _rotation = dragOrientation; } //application: if (draggable) { _position = Vector3.SmoothDamp(_position, dragLocation, ref _positionVelocity, positionSmoothTime); if (_rigidBody != null) { _rigidBody.MovePosition(_position); _averageVelocity.Add(_rigidBody.velocity); _averageAngularVelocity.Add(_rigidBody.angularVelocity); } else { transform.position = _position; } } if (rotatable) { _rotation = MotionUtilities.SmoothDamp(_rotation, dragOrientation, ref _rotationVelocity, rotationSmoothTime); if (_rigidBody != null) { _rigidBody.MoveRotation(_rotation); } else { transform.rotation = _rotation; } } if (scalable && activeInteractionPoints.Count == 2) { Vector3 proposedScale = _scaleBase + (Vector3.one * scaleDelta); //constrain scale and do not not assume uniform initial scale: if (Mathf.Max(proposedScale.x, proposedScale.y, proposedScale.z) <= maxScale && Mathf.Min(proposedScale.x, proposedScale.y, proposedScale.z) >= minScale) { transform.localScale = _scaleBase + (Vector3.one * scaleDelta); } } //visuals: if (activeInteractionPoints.Count == 2) { Lines.SetVisibility(_handConnectionLine, true); Lines.DrawLine(_handConnectionLine, Color.cyan, Color.cyan, .0005f, activeInteractionPoints[0].position, activeInteractionPoints[1].position); } //status: events.OnDragUpdate?.Invoke(activeInteractionPoints.ToArray(), _position, _rotation, scaleDelta); } }
public void GrabEnd(InteractionPoint interactionPoint) { //avoid issues with an actual physical release if StopGrab was used prior: if (activeInteractionPoints.Count == 0) { return; } //sound: if (releasedSound != null) { _audioSource.PlayOneShot(releasedSound, 1); } //colorize: foreach (var item in GetComponentsInChildren <Renderer>()) { if (item.material.HasProperty("_Color")) { item.material.SetColor("_Color", idleColor); } } Grabbed = false; //clear up bimanual manipulation: if (activeInteractionPoints.Count == 2) { activeInteractionPoints.Clear(); _initialInteractionPoses.Clear(); } //remove: _initialInteractionPoses.Remove(interactionPoint); activeInteractionPoints.Remove(interactionPoint); if (Dragging && activeInteractionPoints.Count == 0) { if (_rigidBody != null) { if (throwable && activeInteractionPoints.Count == 0) { //gavity? if (enableGravityOnRelease) { _rigidBody.useGravity = true; } //calculate an average velocity: Vector3 velocity = Vector3.zero; int start = _averageVelocity.Count - _averageVelocityCount; start = Mathf.Clamp(start, _averageVelocityEndTrim, start); int count = 0; for (int i = start; i < _averageVelocity.Count; i++) { velocity += _averageVelocity[i]; count++; } velocity /= count; _rigidBody.velocity = velocity; //calculate an average angular velocity: velocity = Vector3.zero; start = _averageAngularVelocity.Count - _averageVelocityCount; start = Mathf.Clamp(start, _averageVelocityEndTrim, start); count = 0; for (int i = start; i < _averageAngularVelocity.Count; i++) { velocity += _averageAngularVelocity[i]; count++; } velocity /= count; _rigidBody.angularVelocity = velocity; //clear: _averageVelocity.Clear(); _averageAngularVelocity.Clear(); } else { _rigidBody.velocity = Vector3.zero; _rigidBody.angularVelocity = Vector3.zero; } _rigidBody.isKinematic = false; } Dragging = false; events.OnDragEnd?.Invoke(interactionPoint); Lines.SetVisibility(_handConnectionLine, false); } events.OnGrabEnd?.Invoke(interactionPoint); }
private void HandleDragEnd(InteractionPoint interactionPoint) { Lines.SetVisibility(_lineID, false); events.OnReleased?.Invoke(); }
private void HandleDragBegin(InteractionPoint interactionPoint) { Lines.SetVisibility(_lineID, true); }
private void DrawPerimeter_HandleTriggerDown(byte controllerId, float triggerValue) { //cache room details (to avoid tilt if room analyzation updates): if (_plottedCorners.Count == 0) { _roomVerticalCenter = SurfaceDetails.VerticalCenter; _roomCeilingHeight = SurfaceDetails.CeilingHeight; _roomFloorHeight = SurfaceDetails.FloorHeight; Height = SurfaceDetails.RoomHeight; } //corner details: Vector3 controlPosition = MLInput.GetController(controllerId).Position; Vector3 cornerLocation = new Vector3(controlPosition.x, _roomVerticalCenter, controlPosition.z); //invalid placement if this proposed segment would overlap any previous ones: if (_plottedCorners.Count >= 3) { //proposed line segment: Vector2 proposedStart = new Vector2(_plottedCorners[_plottedCorners.Count - 1].position.x, _plottedCorners[_plottedCorners.Count - 1].position.z); Vector2 proposedEnd = new Vector2(cornerLocation.x, cornerLocation.z); //look for any intersections (in 2d): for (int i = 1; i < _plottedCorners.Count; i++) { //get a pervious segment: Vector2 startA = new Vector2(_plottedCorners[i - 1].position.x, _plottedCorners[i - 1].position.z); Vector2 endA = new Vector2(_plottedCorners[i].position.x, _plottedCorners[i].position.z); //is there an intersection with something previous? Vector2 previousIntersection = Vector2.zero; if (MathUtilities.LineSegmentsIntersecting(startA, endA, proposedStart, proposedEnd, false)) { //ignore this proposed corner since it would create an overlapped wall: return; } } } //bounds: if (_plottedCorners.Count == 0) { _plottedBounds = new Bounds(cornerLocation, Vector3.zero); } else { _plottedBounds.Encapsulate(cornerLocation); } //loop complete? bool loopComplete = false; if (_plottedCorners.Count > 3) { //close to first? close to last? close the loop: if (Vector3.Distance(cornerLocation, _plottedCorners[0].position) <= _loopClosureDistance || Vector3.Distance(cornerLocation, _plottedCorners[_plottedCorners.Count - 1].position) <= _loopClosureDistance) { _plottedCorners.Add(_plottedCorners[0]); loopComplete = true; } } if (!loopComplete) { //visualize corner: GameObject corner = GameObject.CreatePrimitive(PrimitiveType.Cylinder); corner.GetComponent <Renderer>().material = cornerMaterial; corner.name = $"(Corner{_plottedCorners.Count})"; corner.transform.position = cornerLocation; corner.transform.localScale = new Vector3(0.0508f, Height * .5f, 0.0508f); _plottedCorners.Add(corner.transform); //visualize boundry: Lines.DrawLine("Boundry", Color.white, Color.white, .01f, _plottedCorners.ToArray()); } else { //visualize boundry: Lines.DrawLine("Boundry", Color.white, Color.white, .01f, _plottedCorners.ToArray()); ChangeState(State.FindWalls); } }
private void RemoveDebugLines() { Lines.DestroyAllLines(); }
private void OnDisable() { Lines.SetVisibility($"Forward{GetInstanceID()}", false); Lines.SetVisibility($"Right_{GetInstanceID()}", false); Lines.SetVisibility($"Up_{GetInstanceID()}", false); }
//Update: private void Update() { Lines.DrawRay($"Forward{GetInstanceID()}", Color.blue, Color.black, transform.position, transform.forward * length, width); Lines.DrawRay($"Right_{GetInstanceID()}", Color.red, Color.black, transform.position, transform.right * length, width); Lines.DrawRay($"Up_{GetInstanceID()}", Color.green, Color.black, transform.position, transform.up * length, width); }
//Event Handlers: private void HandleFingerVisibilityChanged(ManagedFinger finger, bool visible) { Lines.SetVisibility(Name(finger), visible); }