using System.Collections.Generic; namespace UnityEngine.ProBuilder { /// /// Snapping functions (didn't exist in UnityEngine prior to 2019.3) /// static class ProBuilderSnapping { const float k_MaxRaySnapDistance = Mathf.Infinity; internal static bool IsCardinalDirection(Vector3 direction) { return Mathf.Abs(direction.x) > 0f && Mathf.Approximately(direction.y, 0f) && Mathf.Approximately(direction.z, 0f) || Mathf.Abs(direction.y) > 0f && Mathf.Approximately(direction.x, 0f) && Mathf.Approximately(direction.z, 0f) || Mathf.Abs(direction.z) > 0f && Mathf.Approximately(direction.x, 0f) && Mathf.Approximately(direction.y, 0f); } public static float Snap(float val, float snap) { if (snap == 0) return val; return snap * Mathf.Round(val / snap); } public static Vector3 Snap(Vector3 val, Vector3 snap) { return new Vector3( (Mathf.Abs(snap.x) > 0.0001f) ? Snap(val.x, snap.x) : val.x, (Mathf.Abs(snap.y) > 0.0001f) ? Snap(val.y, snap.y) : val.y, (Mathf.Abs(snap.z) > 0.0001f) ? Snap(val.z, snap.z) : val.z ); } /// /// Snap all vertices to an increment of @snapValue in world space. /// /// /// /// public static void SnapVertices(ProBuilderMesh mesh, IEnumerable indexes, Vector3 snap) { Vector3[] verts = mesh.positionsInternal; foreach (var v in indexes) verts[v] = mesh.transform.InverseTransformPoint(Snap(mesh.transform.TransformPoint(verts[v]), snap)); } internal static Vector3 GetSnappingMaskBasedOnNormalVector(Vector3 normal) { return new Vector3( (Mathf.Approximately(Mathf.Abs(normal.x), 1f)) ? 0f : 1f, (Mathf.Approximately(Mathf.Abs(normal.y), 1f)) ? 0f : 1f, (Mathf.Approximately(Mathf.Abs(normal.z), 1f)) ? 0f : 1f); } internal static Vector3 SnapValueOnRay(Ray ray, float distance, float snap, Vector3Mask mask) { var nearest = k_MaxRaySnapDistance; var forwardRay = new Ray(ray.origin, ray.direction); var backwardsRay = new Ray(ray.origin, -ray.direction); for (int i = 0; i < 3; i++) { if (mask[i] > 0f) { var dir = new Vector3Mask(new Vector3Mask((byte) (1 << i))); var prj = Vector3.Project( ray.direction * Math.MakeNonZero(distance), dir * Mathf.Sign(ray.direction[i])); var pnt = ray.origin + prj; var plane = new Plane(dir, Snap(pnt, dir * snap)); if(Mathf.Abs(plane.GetDistanceToPoint(ray.origin)) < .0001f) { nearest = 0f; continue; } float d; if (plane.Raycast(forwardRay, out d) && Mathf.Abs(d) < Mathf.Abs(nearest)) nearest = d; if (plane.Raycast(backwardsRay, out d) && Mathf.Abs(d) < Mathf.Abs(nearest)) nearest = -d; } } return ray.origin + ray.direction * (Mathf.Abs(nearest) >= k_MaxRaySnapDistance ? distance : nearest); } } }