diff --git a/Assets/Scripts/tools/Extruder.cs b/Assets/Scripts/tools/Extruder.cs index 7b181827..657baa1a 100644 --- a/Assets/Scripts/tools/Extruder.cs +++ b/Assets/Scripts/tools/Extruder.cs @@ -90,6 +90,8 @@ public class Extruder : MonoBehaviour /// private bool isSnapping = false; + private Face nearestFace; + /// /// Every tool is implemented as MonoBehaviour, which means it may do no work in its constructor. /// As such, this setup method must be called before the tool is used for it to have a valid state. @@ -106,7 +108,7 @@ public void Setup(Model model, ControllerMain controllerMain, PeltzerController controllerMain.ControllerActionHandler += ControllerEventHandler; } - private ExtrusionOperation.ExtrusionParams BuildExtrusionParams() + private ExtrusionOperation.ExtrusionParams BuildExtrusionParams(bool flipped) { // Note: ExtrusionParams is a struct, so this is stack allocated and doesn't generate garbage. ExtrusionOperation.ExtrusionParams extrusionParams = new ExtrusionOperation.ExtrusionParams(); @@ -116,6 +118,7 @@ private ExtrusionOperation.ExtrusionParams BuildExtrusionParams() extrusionParams.rotationPivotModel = peltzerController.LastPositionModel; extrusionParams.rotationModel = peltzerController.LastRotationModel * Quaternion.Inverse(extrusionBeginOrientation); + extrusionParams.flipped = flipped; return extrusionParams; } @@ -172,7 +175,14 @@ private void Update() triggerUpToRelease = true; } - ExtrusionOperation.ExtrusionParams extrusionParams = BuildExtrusionParams(); + bool towards = true; + if (nearestFace != null) + { + var faceVector = nearestFace.normal; + var dragVector = peltzerController.LastPositionModel - extrusionBeginPosition; + towards = Vector3.Dot(faceVector, dragVector) > 0; + } + ExtrusionOperation.ExtrusionParams extrusionParams = BuildExtrusionParams(!towards); foreach (ExtrusionOperation operation in extrusions) { operation.UpdateExtrudeGuide(extrusionParams); @@ -397,7 +407,15 @@ private void ReleaseMesh() List commands = new List(); Dictionary modifiedMeshes = new Dictionary(); Dictionary> newVerticesInModifiedMeshes = new Dictionary>(); - ExtrusionOperation.ExtrusionParams extrusionParams = BuildExtrusionParams(); + + bool towards = true; + if (nearestFace != null) + { + var faceVector = nearestFace.normal; + var dragVector = peltzerController.LastPositionModel - extrusionBeginPosition; + towards = Vector3.Dot(faceVector, dragVector) > 0; + } + ExtrusionOperation.ExtrusionParams extrusionParams = BuildExtrusionParams(!towards); foreach (ExtrusionOperation extrusion in extrusions) { @@ -473,6 +491,9 @@ private void ControllerEventHandler(object sender, ControllerEventArgs args) return; } } + + nearestFace = selector.GetNearestFace(peltzerController.LastPositionModel); + triggerUpToRelease = false; waitingToDetermineReleaseType = true; triggerDownTime = Time.time; diff --git a/Assets/Scripts/tools/ExtrusionOperation.cs b/Assets/Scripts/tools/ExtrusionOperation.cs index 480333e3..5c632a65 100644 --- a/Assets/Scripts/tools/ExtrusionOperation.cs +++ b/Assets/Scripts/tools/ExtrusionOperation.cs @@ -49,6 +49,7 @@ public struct ExtrusionParams // Indicates the point about which the extruded face should be rotated, AFTER the translation. // This is in MODEL space. public Vector3 rotationPivotModel; + public bool flipped; } /// @@ -476,7 +477,7 @@ public static List BuildExtrusionSides( if (extrusionParams.lockToNormal) { var extrudedPoint = GridUtils.SnapToGrid(extrusionParams.translationModel); - projectedDelta = mesh.rotation * face.normal * extrudedPoint.magnitude; + projectedDelta = mesh.rotation * face.normal * (extrudedPoint.magnitude * (extrusionParams.flipped ? -1 : 1)); } else { diff --git a/Assets/Scripts/tools/Selector.cs b/Assets/Scripts/tools/Selector.cs index 7c5a6df6..1451e1d5 100644 --- a/Assets/Scripts/tools/Selector.cs +++ b/Assets/Scripts/tools/Selector.cs @@ -1563,5 +1563,20 @@ public void AddSelectedMeshForTest(int meshId) { selectedMeshes.Add(meshId); } + + public Face GetNearestFace(Vector3 pos) + { + float selectionThreshold = faceClosenessThreshold * INCREASED_SELECTION_FACTOR; + spatialIndex.FindFacesClosestTo(pos, selectionThreshold, + false, out List> temp); + if (temp.Count == 0) + { + return null; + } + var facekey = temp[0].value; + var mesh = model.GetMesh(facekey.meshId); + var face = mesh.GetFace(facekey.faceId); + return face; + } } }