static bool FindCustomSnappingPoints(Vector3 startWorldPoint, Vector3 currentWorldPoint, Grid worldSlideGrid, int contextIndex, List <Vector3> foundWorldspacePoints) { if (!s_SnappingContext.TryGetValue(contextIndex, out var snappingContext)) { s_SnappingContext[contextIndex] = snappingContext = new SnappingContext(); } snappingContext.Clear(); s_DrawSurfaceSnapEvents.Clear(); s_DrawEdgeSnapEvents.Clear(); s_DrawVertexSnapEvents.Clear(); var edgeSnappingActive = Snapping.EdgeSnappingActive; var vertexSnappingActive = Snapping.VertexSnappingActive; var surfaceSnappingActive = Snapping.SurfaceSnappingActive; if (!edgeSnappingActive && !vertexSnappingActive && !surfaceSnappingActive) { return(false); } var surfaceSnapEvents = surfaceSnappingActive ? snappingContext.s_AllSurfaceSnapEvents : null; var edgeSnapEvents = edgeSnappingActive ? snappingContext.s_AllEdgeSnapEvents : null; var vertexSnapEvents = vertexSnappingActive ? snappingContext.s_AllVertexSnapEvents : null; var selection = Selection.gameObjects; FindClosestSnapPointsToPlane(selection, startWorldPoint, currentWorldPoint, worldSlideGrid, kArbitrarySnapDistance, surfaceSnapEvents, edgeSnapEvents, vertexSnapEvents); snappingContext.CollectAllSnapPoints(foundWorldspacePoints); return(true); }
static void FindClosestSnapPointsToPlane(GameObject[] selection, Vector3 startWorldPoint, Vector3 currentWorldPoint, Grid worldSlideGrid, float maxSnapDistance, List <SurfaceSnap> allSurfaceSnapEvents, List <EdgeSnap> allEdgeSnapEvents, List <VertexSnap> allVertexSnapEvents) { if (selection == null || selection.Length == 0) { return; } if (allSurfaceSnapEvents == null && allEdgeSnapEvents == null && allVertexSnapEvents == null) { return; } var worldSlidePlane = worldSlideGrid.PlaneXZ; var gridSnapping = Snapping.GridSnappingActive; if (gridSnapping) { var vectorX = worldSlideGrid.Right * maxSnapDistance; var vectorZ = worldSlideGrid.Forward * maxSnapDistance; var snappedWorldPoint = Snapping.SnapPoint(currentWorldPoint, worldSlideGrid); FindSnapPointsAlongRay(selection, snappedWorldPoint, vectorX, allSurfaceSnapEvents, allEdgeSnapEvents, allVertexSnapEvents); FindSnapPointsAlongRay(selection, snappedWorldPoint, vectorZ, allSurfaceSnapEvents, allEdgeSnapEvents, allVertexSnapEvents); snappedWorldPoint = Snapping.SnapPoint(startWorldPoint, worldSlideGrid); FindSnapPointsAlongRay(selection, snappedWorldPoint, vectorX, allSurfaceSnapEvents, allEdgeSnapEvents, allVertexSnapEvents); FindSnapPointsAlongRay(selection, snappedWorldPoint, vectorZ, allSurfaceSnapEvents, allEdgeSnapEvents, allVertexSnapEvents); } worldSlidePlane = new Plane(worldSlidePlane.normal, currentWorldPoint); s_SelectedBrushes.Clear(); foreach (var go in selection) { if (!go) { continue; } var node = go.GetComponent <ChiselNode>(); if (!node) { continue; } s_SelectedNodes.Clear(); node.CollectCSGTreeNodes(s_SelectedNodes); foreach (var child in s_SelectedNodes) { if (!child.Valid || child.Type != CSGNodeType.Brush) { continue; } s_SelectedBrushes.Add((CSGTreeBrush)child); } } if (s_SelectedBrushes.Count == 0) { return; } var snapDistanceSqr = maxSnapDistance * maxSnapDistance; EdgeSnap[] foundEdges = new EdgeSnap[2]; int foundEdgeCount; foreach (var csgBrush in s_SelectedBrushes) { var csgTree = csgBrush.Tree; var brushMesh = BrushMeshManager.GetBrushMesh(csgBrush.BrushMesh); var polygons = brushMesh.polygons; var halfEdges = brushMesh.halfEdges; var vertices = brushMesh.vertices; var planes = brushMesh.planes; var halfEdgePolygonIndices = brushMesh.halfEdgePolygonIndices; // TODO: store this information with brush var model = ChiselNodeHierarchyManager.FindChiselNodeByInstanceID(csgTree.UserID) as ChiselModel; var worldToNode = csgBrush.TreeToNodeSpaceMatrix * model.hierarchyItem.WorldToLocalMatrix; var nodeToWorld = model.hierarchyItem.LocalToWorldMatrix * csgBrush.NodeToTreeSpaceMatrix; var brushPoint = worldToNode.MultiplyPoint(currentWorldPoint); var brushPlane = worldToNode.TransformPlane(worldSlidePlane); if (allVertexSnapEvents != null) { if (gridSnapping) { for (int i = 0; i < vertices.Length; i++) { var vertex = vertices[i]; var dist0 = brushPlane.GetDistanceToPoint(vertex); if (math.abs(dist0) > snapDistanceSqr) { continue; } allVertexSnapEvents.Add(new VertexSnap { brush = csgBrush, vertexIndex = i, intersection = nodeToWorld.MultiplyPoint(vertex) }); } } else { for (int i = 0; i < vertices.Length; i++) { var vertex = vertices[i]; if (math.lengthsq(vertex - (float3)brushPoint) > snapDistanceSqr) { continue; } var dist0 = brushPlane.GetDistanceToPoint(vertex); if (math.abs(dist0) > snapDistanceSqr) { continue; } allVertexSnapEvents.Add(new VertexSnap { brush = csgBrush, vertexIndex = i, intersection = nodeToWorld.MultiplyPoint(vertex) }); } } } if (allSurfaceSnapEvents == null && allEdgeSnapEvents == null) { continue; } for (int surfaceIndex = 0; surfaceIndex < polygons.Length; surfaceIndex++) { var polygon = polygons[surfaceIndex]; var firstEdge = polygon.firstEdge; var lastEdge = firstEdge + polygon.edgeCount; // TODO: If point is ON plane, ignore. We don't want to "snap" to every point on that surface b/c then we won't be snapping at all foundEdgeCount = 0; for (int e0 = lastEdge - 1, e1 = firstEdge; e1 < lastEdge; e0 = e1, e1++) { var i0 = halfEdges[e0].vertexIndex; var i1 = halfEdges[e1].vertexIndex; var vertex0 = vertices[i0]; var vertex1 = vertices[i1]; var distance0 = brushPlane.GetDistanceToPoint(vertex0); var distance1 = brushPlane.GetDistanceToPoint(vertex1); // Edge is plane aligned if (math.abs(distance0) < kPlaneDistanceEpsilon && math.abs(distance1) < kPlaneDistanceEpsilon) { if (i0 < i1 && // skip duplicate edges allEdgeSnapEvents != null) { if (gridSnapping) { } else { if (ClosestPointToLine(brushPoint, vertex0, vertex1, out Vector3 newVertex)) { allEdgeSnapEvents.Add(new EdgeSnap { brush = csgBrush, surfaceIndex0 = surfaceIndex, surfaceIndex1 = halfEdgePolygonIndices[halfEdges[e1].twinIndex], vertexIndex0 = i0, vertexIndex1 = i1, intersection = nodeToWorld.MultiplyPoint(newVertex), from = nodeToWorld.MultiplyPoint(vertex0), to = nodeToWorld.MultiplyPoint(vertex1) }); } } } continue; } { if ((distance0 < -snapDistanceSqr && distance1 < -snapDistanceSqr) || (distance0 > snapDistanceSqr && distance1 > snapDistanceSqr)) { continue; } // TODO: Find intersection between plane and edge var vector = vertex0 - vertex1; var length = distance0 - distance1; var delta = distance0 / length; if (float.IsNaN(delta) || float.IsInfinity(delta)) { continue; } var newVertex = (Vector3)(vertex0 - (vector * delta)); var distanceN = brushPlane.GetDistanceToPoint(newVertex); if ((distanceN <= distance0 && distanceN <= distance1) || (distanceN >= distance0 && distanceN >= distance1)) { continue; } if ((newVertex - brushPoint).sqrMagnitude > snapDistanceSqr) { continue; } foundEdges[foundEdgeCount] = new EdgeSnap { brush = csgBrush, surfaceIndex0 = surfaceIndex, surfaceIndex1 = halfEdgePolygonIndices[halfEdges[e1].twinIndex], vertexIndex0 = i0, vertexIndex1 = i1, intersection = nodeToWorld.MultiplyPoint(newVertex), from = nodeToWorld.MultiplyPoint(vertex0), to = nodeToWorld.MultiplyPoint(vertex1) }; if (i0 < i1 && // skip duplicate edges allEdgeSnapEvents != null) { allEdgeSnapEvents.Add(foundEdges[foundEdgeCount]); } foundEdgeCount++; if (foundEdgeCount == 2) { break; } } } if (allSurfaceSnapEvents != null && foundEdgeCount > 0 && !gridSnapping) { if (foundEdgeCount == 2) { var plane = planes[surfaceIndex]; var unityPlane = new Plane(plane.xyz, plane.w); var vertex0 = foundEdges[0].intersection; var vertex1 = foundEdges[1].intersection; if (ClosestPointToLine(currentWorldPoint, vertex0, vertex1, out Vector3 closestWorldPoint)) { allSurfaceSnapEvents.Add(new SurfaceSnap { brush = csgBrush, surfaceIndex = surfaceIndex, intersection = closestWorldPoint, normal = nodeToWorld.MultiplyVector(unityPlane.normal), }); } } } } } }
public static Vector3 SnapPoint(Vector3 position, Grid grid, Axes enabledAxes = Axes.XYZ) { return(SnappingUtility.SnapPoint3D(position, grid.Spacing, grid.Right, grid.Up, grid.Forward, grid.Center, enabledAxes)); }
public static bool GetCustomSnappingPoints(Vector3 startWorldPoint, Vector3 currentWorldPoint, Grid worldSlideGrid, int contextIndex, List <Vector3> foundWorldspacePoints) { foundWorldspacePoints.Clear(); return(Snapping.FindCustomSnappingPointsMethod == null ? false : Snapping.FindCustomSnappingPointsMethod(startWorldPoint, currentWorldPoint, worldSlideGrid, contextIndex, foundWorldspacePoints) && foundWorldspacePoints.Count > 0); }
public static Vector3[] Do(int id, Vector3[] points, Vector3 handleOrigin, Vector3 handleCursorOffset, Vector3 handleNormal, Vector3 slideDir1, Vector3 slideDir2, float handleSize, SceneHandles.CapFunction capFunction, Axes axes = Axes.None, bool selectLockingAxisOnClick = false, bool noSnapping = false, Vector3? snappingSteps = null) { var evt = Event.current; switch (evt.GetTypeForControl(id)) { case EventType.MouseDown: { if (SceneHandles.InCameraOrbitMode) break; if (GUIUtility.hotControl != 0) break; if ((UnityEditor.HandleUtility.nearestControl != id || evt.button != 0) && (GUIUtility.keyboardControl != id || evt.button != 2)) break; GUIUtility.hotControl = GUIUtility.keyboardControl = id; evt.Use(); EditorGUIUtility.SetWantsMouseJumping(1); s_CurrentMousePosition = evt.mousePosition; s_StartPoints = points.ToArray(); var localToWorldMatrix = UnityEditor.Handles.matrix; var center = Grid.ActiveGrid.Center; Matrix4x4 gridSpace = Matrix4x4.identity; gridSpace.SetColumn(0, localToWorldMatrix.MultiplyVector(slideDir1).normalized); gridSpace.SetColumn(1, localToWorldMatrix.MultiplyVector(handleNormal).normalized); gridSpace.SetColumn(2, localToWorldMatrix.MultiplyVector(slideDir2).normalized); gridSpace.SetColumn(3, new Vector4(center.x, center.y, center.z, 1.0f)); var workGrid = new Grid(gridSpace, snappingSteps.HasValue ? snappingSteps.Value : Snapping.MoveSnappingSteps); s_Snapping2D.Initialize(workGrid, s_CurrentMousePosition, handleOrigin, localToWorldMatrix); s_Snapping2D.CalculateExtents(s_StartPoints); s_MovedMouse = false; break; } case EventType.MouseDrag: { if (GUIUtility.hotControl != id) break; s_MovedMouse = true; if (SceneHandles.disabled || Snapping.AreAxisLocked(axes)) break; s_CurrentMousePosition += evt.delta; evt.Use(); if (!s_Snapping2D.DragTo(s_CurrentMousePosition, noSnapping ? SnappingMode.Never: SnappingMode.Default)) break; var handleInverseMatrix = UnityEditor.Handles.inverseMatrix; var localPointDelta = s_Snapping2D.WorldSnappedDelta; var pointDelta = handleInverseMatrix.MultiplyVector(localPointDelta); if (axes != Axes.None) { if ((axes & Axes.X) == Axes.None) pointDelta.x = 0; if ((axes & Axes.Y) == Axes.None) pointDelta.y = 0; if ((axes & Axes.Z) == Axes.None) pointDelta.z = 0; } if (s_StartPoints != null) { points = new Vector3[points.Length]; // if we don't, it's hard to do Undo properly for (int i = 0; i < points.Length; i++) points[i] = SnappingUtility.Quantize(s_StartPoints[i] + pointDelta); } //SceneView.RepaintAll(); GUI.changed = true; break; } case EventType.MouseUp: { if (GUIUtility.hotControl == id && (evt.button == 0 || evt.button == 2)) { GUIUtility.hotControl = 0; GUIUtility.keyboardControl = 0; s_StartPoints = null; s_Snapping2D.Reset(); evt.Use(); EditorGUIUtility.SetWantsMouseJumping(0); SceneView.RepaintAll(); if (!s_MovedMouse && selectLockingAxisOnClick) Snapping.ActiveAxes = axes; } break; } case EventType.Layout: { if (SceneHandles.InCameraOrbitMode) break; var position = handleOrigin + handleCursorOffset; var rotation = Quaternion.LookRotation(handleNormal, slideDir1); if (capFunction != null) capFunction(id, position, rotation, handleSize, EventType.Layout); else UnityEditor.HandleUtility.AddControl(id, UnityEditor.HandleUtility.DistanceToCircle(position, handleSize * .5f)); int currentFocusControl = SceneHandleUtility.focusControl; if ((currentFocusControl == id && s_PrevFocusControl != id) || (currentFocusControl != id && s_PrevFocusControl == id)) { s_PrevFocusControl = currentFocusControl; SceneView.RepaintAll(); } break; } case EventType.Repaint: { if (axes != Axes.None) { if (GUIUtility.hotControl == id && s_Snapping2D.WorldSlideGrid != null) { var selectedColor = UnityEditor.Handles.selectedColor; selectedColor.a = 0.5f; using (new SceneHandles.DrawingScope(selectedColor)) HandleRendering.RenderSnapping3D(s_Snapping2D.WorldSlideGrid, s_Snapping2D.WorldSnappedExtents, s_Snapping2D.GridSnappedPosition, s_Snapping2D.SnapResult); } } if (capFunction == null) break; var position = handleOrigin + handleCursorOffset; var rotation = Quaternion.LookRotation(handleNormal, slideDir1); var color = SceneHandles.StateColor(SceneHandles.color, isSelected: (id == s_PrevFocusControl)); using (new SceneHandles.DrawingScope(color)) { capFunction(id, position, rotation, handleSize, EventType.Repaint); } break; } } return points; }