private void Move(Vector3 move) { Vector3 displacement = Vector3.ProjectOnPlane(move, currentFace.plane.normal); Vector3 potentialPosition = position + displacement; if (currentFace.source.IsPointInsideFace(potentialPosition, EpsilonOffset)) { position = potentialPosition; } else { Vector3 clampedPosition = currentFace.SnapToFace(position, displacement); Vector3 clampedDisplacement = clampedPosition - position; position = clampedPosition; Vector3 cutDisplacement = displacement.normalized * (displacement.magnitude - clampedDisplacement.magnitude); // + 2 * EpsilonOffset if (progress != null && progress.HasNextFace && progress.NextFace.IsPointInsideFace(position, EpsilonOffset)) { progress.currentFace++; currentFace = new CachedFace(progress.CurrentFace); var ray = new Ray(position, Vector3.down); currentFace.plane.Raycast(ray, out float enter); position = ray.GetPoint(enter); while (progress.HasNextPoint && !progress.IsCurrentPointOnCurrentOrNextFaces()) { progress.currentPoint++; } Move(cutDisplacement); } else { position += currentFace.CastDisplacementOnClosestEdge(position, cutDisplacement); } } }