static void DisableTool() { EditorGUIUtility.SetWantsMouseJumping(0); // disable allowing the user to move the mouse over the bounds of the screen GUIUtility.hotControl = GUIUtility.keyboardControl = 0; // remove the active control so that the user can use another control Event.current.Use(); // make sure no-one else can use our event toolSnapOverrides = (UVSnapSettings) ~0; pointHasSnapped = false; }
static void SnapSurfaceVertices(UVSnapSettings snapSettings, SurfaceReference surfaceReference, Vector3 intersectionPoint, float preferenceFactor, ref Vector3 snappedPoint, ref float bestDist) { if (surfaceReference == null) { return; } if ((snapSettings & UVSnapSettings.GeometryVertices) == UVSnapSettings.None) { return; } var localToWorldSpace = surfaceReference.LocalToWorldSpace; var brushMesh = surfaceReference.BrushMesh; if (brushMesh == null) { return; } Debug.Assert(surfaceReference.surfaceIndex >= 0 && surfaceReference.surfaceIndex < brushMesh.polygons.Length); var polygon = brushMesh.polygons[surfaceReference.surfaceIndex]; var edges = brushMesh.halfEdges; var vertices = brushMesh.vertices; var firstEdge = polygon.firstEdge; var lastEdge = firstEdge + polygon.edgeCount; var bestDistSqr = float.PositiveInfinity; var bestVertex = snappedPoint; for (int e = firstEdge; e < lastEdge; e++) { var worldSpaceVertex = localToWorldSpace.MultiplyPoint(vertices[edges[e].vertexIndex]); var dist_sqr = (worldSpaceVertex - intersectionPoint).sqrMagnitude; if (dist_sqr < bestDistSqr) { bestDistSqr = dist_sqr; bestVertex = worldSpaceVertex; } } if (float.IsInfinity(bestDistSqr)) { return; } var closestVertexDistance = Mathf.Sqrt(bestDistSqr) * preferenceFactor; if (closestVertexDistance < bestDist) { bestDist = closestVertexDistance; snappedPoint = bestVertex; } }
static void EnableTool(int id) { EditorGUIUtility.SetWantsMouseJumping(1); // enable allowing the user to move the mouse over the bounds of the screen jumpedMousePosition = Event.current.mousePosition; // remember the current mouse position so we can update it using Event.current.delta, // since mousePosition won't make sense any more when mouse jumping GUIUtility.hotControl = GUIUtility.keyboardControl = id; // set our tool as the active control Event.current.Use(); // make sure no-one else can use our event toolSnapOverrides = (UVSnapSettings) ~0; pointHasSnapped = false; }
static void SnapSurfaceEdges(UVSnapSettings snapSettings, SurfaceReference surfaceReference, Vector3 intersectionPoint, float preferenceFactor, ref Vector3 snappedPoint, ref float bestDist) { if (surfaceReference == null) { return; } if ((snapSettings & UVSnapSettings.GeometryEdges) == UVSnapSettings.None) { return; } var localToWorldSpace = surfaceReference.LocalToWorldSpace; var subMesh = surfaceReference.SubMesh; Debug.Assert(surfaceReference.surfaceIndex >= 0 && surfaceReference.surfaceIndex < subMesh.Polygons.Length); var grid = UnitySceneExtensions.Grid.defaultGrid; var xAxis = grid.Right; var yAxis = grid.Up; var zAxis = grid.Forward; var intersectionPlane = surfaceReference.WorldPlane.Value; var snapAxis = Axis.X | Axis.Y | Axis.Z; if (Mathf.Abs(Vector3.Dot(xAxis, intersectionPlane.normal)) >= kAlignmentEpsilon) { snapAxis &= ~Axis.X; } if (Mathf.Abs(Vector3.Dot(yAxis, intersectionPlane.normal)) >= kAlignmentEpsilon) { snapAxis &= ~Axis.Y; } if (Mathf.Abs(Vector3.Dot(zAxis, intersectionPlane.normal)) >= kAlignmentEpsilon) { snapAxis &= ~Axis.Z; } var polygons = subMesh.Polygons; var polygon = polygons[surfaceReference.surfaceIndex]; var edges = subMesh.HalfEdges; var vertices = subMesh.Vertices; var firstEdge = polygon.firstEdge; var lastEdge = firstEdge + polygon.edgeCount; for (int e = firstEdge; e < lastEdge; e++) { var twinIndex = edges[e].twinIndex; #if USE_MANAGED_CSG_IMPLEMENTATION var polygonIndex = edges[e].polygonIndex; #else // The managed CSG solution will have a polygon index stored for each half-edge // the native solution doesn't have this, however, so we need to find the polygon ourselves int polygonIndex = -1; for (int p = 0; p < polygons.Length; p++) { if (twinIndex < polygons[p].firstEdge) { continue; } if (twinIndex >= polygons[p].firstEdge + polygons[p].edgeCount) { continue; } polygonIndex = p; break; } if (polygonIndex == -1) { continue; } #endif var surfaceIndex = polygonIndex; // FIXME: throughout the code we're making assumptions about polygonIndices being the same as surfaceIndices, // this needs to be fixed var localPlane = subMesh.Orientations[surfaceIndex].localPlane; var worldPlane = localToWorldSpace.TransformPlane(localPlane); if ((CurrentSnapSettings & UVSnapSettings.GeometryGrid) != UVSnapSettings.None) { var edgeDirection = Vector3.Cross(intersectionPlane.normal, worldPlane.normal); var edgeSnapAxis = snapAxis; if (Mathf.Abs(Vector3.Dot(xAxis, edgeDirection)) >= kAlignmentEpsilon) { edgeSnapAxis &= ~Axis.X; } if (Mathf.Abs(Vector3.Dot(yAxis, edgeDirection)) >= kAlignmentEpsilon) { edgeSnapAxis &= ~Axis.Y; } if (Mathf.Abs(Vector3.Dot(zAxis, edgeDirection)) >= kAlignmentEpsilon) { edgeSnapAxis &= ~Axis.Z; } if (edgeSnapAxis == Axis.None) { continue; } float dist; var ray = new Ray(snappedPoint, xAxis); if ((edgeSnapAxis & Axis.X) != Axis.None && worldPlane.UnsignedRaycast(ray, out dist)) { var planePoint = ray.GetPoint(dist); var abs_dist = (planePoint - intersectionPoint).magnitude * preferenceFactor; if (abs_dist < bestDist) { bestDist = abs_dist; snappedPoint = planePoint; } } ray.direction = yAxis; if ((edgeSnapAxis & Axis.Y) != Axis.None && worldPlane.UnsignedRaycast(ray, out dist)) { var planePoint = ray.GetPoint(dist); var abs_dist = (planePoint - intersectionPoint).magnitude * preferenceFactor; if (abs_dist < bestDist) { bestDist = abs_dist; snappedPoint = planePoint; } } ray.direction = zAxis; if ((edgeSnapAxis & Axis.Z) != Axis.None && worldPlane.UnsignedRaycast(ray, out dist)) { var planePoint = ray.GetPoint(dist); var abs_dist = (planePoint - intersectionPoint).magnitude * preferenceFactor; if (abs_dist < bestDist) { bestDist = abs_dist; snappedPoint = planePoint; } } } else { var closestPoint = worldPlane.ClosestPointOnPlane(intersectionPoint); var dist = (closestPoint - intersectionPoint).magnitude * preferenceFactor; if (dist < bestDist) { bestDist = dist; snappedPoint = closestPoint; } } } }
static void SnapGridIntersection(UVSnapSettings snapSettings, SurfaceReference surfaceReference, Vector3 intersectionPoint, float preferenceFactor, ref Vector3 snappedPoint, ref float bestDist) { if ((snapSettings & UVSnapSettings.GeometryGrid) == UVSnapSettings.None) { return; } var grid = UnitySceneExtensions.Grid.defaultGrid; var gridSnappedPoint = Snapping.SnapPoint(intersectionPoint, grid); var worldPlane = surfaceReference.WorldPlane.Value; var xAxis = grid.Right; var yAxis = grid.Up; var zAxis = grid.Forward; var snapAxis = Axis.X | Axis.Y | Axis.Z; if (Mathf.Abs(Vector3.Dot(xAxis, worldPlane.normal)) >= kAlignmentEpsilon) { snapAxis &= ~Axis.X; } if (Mathf.Abs(Vector3.Dot(yAxis, worldPlane.normal)) >= kAlignmentEpsilon) { snapAxis &= ~Axis.Y; } if (Mathf.Abs(Vector3.Dot(zAxis, worldPlane.normal)) >= kAlignmentEpsilon) { snapAxis &= ~Axis.Z; } if (Mathf.Abs(worldPlane.GetDistanceToPoint(gridSnappedPoint)) < kDistanceEpsilon) { bestDist = (gridSnappedPoint - intersectionPoint).magnitude * preferenceFactor; snappedPoint = gridSnappedPoint; } else { float dist; var ray = new Ray(gridSnappedPoint, xAxis); if ((snapAxis & Axis.X) != Axis.None && worldPlane.UnsignedRaycast(ray, out dist)) { var planePoint = ray.GetPoint(dist); var abs_dist = (planePoint - intersectionPoint).magnitude * preferenceFactor; if (abs_dist < bestDist) { bestDist = abs_dist; snappedPoint = planePoint; } } ray.direction = yAxis; if ((snapAxis & Axis.Y) != Axis.None && worldPlane.UnsignedRaycast(ray, out dist)) { var planePoint = ray.GetPoint(dist); var abs_dist = (planePoint - intersectionPoint).magnitude * preferenceFactor; if (abs_dist < bestDist) { bestDist = abs_dist; snappedPoint = planePoint; } } ray.direction = zAxis; if ((snapAxis & Axis.Z) != Axis.None && worldPlane.UnsignedRaycast(ray, out dist)) { var planePoint = ray.GetPoint(dist); var abs_dist = (planePoint - intersectionPoint).magnitude * preferenceFactor; if (abs_dist < bestDist) { bestDist = abs_dist; snappedPoint = planePoint; } } } }
private static bool SurfaceRotateTool(SelectionType selectionType, Rect dragArea) { var id = GUIUtility.GetControlID(kSurfaceRotateHash, FocusType.Keyboard, dragArea); if (!SurfaceToolBase(id, selectionType, dragArea)) { return(false); } bool needRepaint = false; if (!IsToolEnabled(id)) { needRepaint = haveRotateStartAngle; haveRotateStartAngle = false; pointHasSnapped = false; } switch (Event.current.GetTypeForControl(id)) { // TODO: support rotating texture using keyboard? case EventType.Repaint: { if (haveRotateStartAngle) { var toWorldVector = worldDragDeltaVector; var magnitude = toWorldVector.magnitude; toWorldVector /= magnitude; // TODO: need a nicer visualization here, show delta rotation, angles etc. Handles.DrawWireDisc(worldStartPosition, worldProjectionPlane.normal, magnitude); if (haveRotateStartAngle) { var snappedToWorldVector = Quaternion.AngleAxis(rotateAngle, worldDragPlane.normal) * fromWorldVector; Handles.DrawDottedLine(worldStartPosition, worldStartPosition + (fromWorldVector * magnitude), 4.0f); Handles.DrawDottedLine(worldStartPosition, worldStartPosition + (snappedToWorldVector * magnitude), 4.0f); } else { Handles.DrawDottedLine(worldStartPosition, worldStartPosition + (toWorldVector * magnitude), 4.0f); } } if (IsToolEnabled(id)) { if (haveRotateStartAngle && pointHasSnapped) { RenderIntersectionPoint(worldIntersection); RenderVertexBox(worldIntersection); } } break; } case EventType.MouseDrag: { if (!IsToolEnabled(id)) { break; } if (StartToolDragging()) { haveRotateStartAngle = false; pointHasSnapped = false; } var toWorldVector = worldDragDeltaVector; if (!haveRotateStartAngle) { var handleSize = HandleUtility.GetHandleSize(worldStartPosition); var minDiameterSqr = handleSize * kMinRotateDiameter; // Only start rotating when we've moved the cursor far away enough from the center of rotation if (toWorldVector.sqrMagnitude > minDiameterSqr) { // Switch to rotation mode, we have a center and a start angle to compare with, // from now on, when we move the mouse we change the rotation angle relative to this first angle. haveRotateStartAngle = true; pointHasSnapped = false; fromWorldVector = toWorldVector.normalized; rotateAngle = 0; // We override the snapping settings to only allow snapping against vertices, // we do this only after we have our starting vector, so that when we rotate we're not constantly // snapping against the grid when we really just want to be able to snap against the current rotation step. // On the other hand, we do want to be able to snap against vertices .. toolSnapOverrides = UVSnapSettings.GeometryVertices; } } else { // Get the angle between 'from' and 'to' on the plane we're dragging over rotateAngle = MathExtensions.SignedAngle(fromWorldVector, toWorldVector.normalized, worldDragPlane.normal); // If we snapped against something, ignore angle snapping if (!pointHasSnapped) { rotateAngle = SnapAngle(rotateAngle); } RotateSurfacesInWorldSpace(worldStartPosition, worldDragPlane.normal, -rotateAngle); // TODO: figure out why this is reversed } break; } } return(needRepaint); }
static void SnapSurfaceEdges(UVSnapSettings snapSettings, SurfaceReference surfaceReference, Vector3 intersectionPoint, float preferenceFactor, ref Vector3 snappedPoint, ref float bestDist) { if (surfaceReference == null) { return; } if ((snapSettings & UVSnapSettings.GeometryEdges) == UVSnapSettings.None) { return; } var localToWorldSpace = surfaceReference.LocalToWorldSpace; var brushMesh = surfaceReference.BrushMesh; if (brushMesh == null) { return; } Debug.Assert(surfaceReference.surfaceIndex >= 0 && surfaceReference.surfaceIndex < brushMesh.polygons.Length); var grid = UnitySceneExtensions.Grid.defaultGrid; var xAxis = grid.Right; var yAxis = grid.Up; var zAxis = grid.Forward; var intersectionPlane = surfaceReference.WorldPlane.Value; var snapAxis = Axis.X | Axis.Y | Axis.Z; if (Mathf.Abs(Vector3.Dot(xAxis, intersectionPlane.normal)) >= kAlignmentEpsilon) { snapAxis &= ~Axis.X; } if (Mathf.Abs(Vector3.Dot(yAxis, intersectionPlane.normal)) >= kAlignmentEpsilon) { snapAxis &= ~Axis.Y; } if (Mathf.Abs(Vector3.Dot(zAxis, intersectionPlane.normal)) >= kAlignmentEpsilon) { snapAxis &= ~Axis.Z; } var polygons = brushMesh.polygons; var polygon = polygons[surfaceReference.surfaceIndex]; var halfEdges = brushMesh.halfEdges; var halfEdgePolygonIndices = brushMesh.halfEdgePolygonIndices; var vertices = brushMesh.vertices; var firstEdge = polygon.firstEdge; var lastEdge = firstEdge + polygon.edgeCount; for (int e = firstEdge; e < lastEdge; e++) { var twinIndex = halfEdges[e].twinIndex; var polygonIndex = halfEdgePolygonIndices[e]; var surfaceIndex = polygonIndex; // FIXME: throughout the code we're making assumptions about polygonIndices being the same as surfaceIndices, // this needs to be fixed var localPlaneVector = brushMesh.surfaces[surfaceIndex].localPlane; var localPlane = new Plane((Vector3)localPlaneVector, localPlaneVector.w); var worldPlane = localToWorldSpace.TransformPlane(localPlane); if ((CurrentSnapSettings & UVSnapSettings.GeometryGrid) != UVSnapSettings.None) { var edgeDirection = Vector3.Cross(intersectionPlane.normal, worldPlane.normal); var edgeSnapAxis = snapAxis; if (Mathf.Abs(Vector3.Dot(xAxis, edgeDirection)) >= kAlignmentEpsilon) { edgeSnapAxis &= ~Axis.X; } if (Mathf.Abs(Vector3.Dot(yAxis, edgeDirection)) >= kAlignmentEpsilon) { edgeSnapAxis &= ~Axis.Y; } if (Mathf.Abs(Vector3.Dot(zAxis, edgeDirection)) >= kAlignmentEpsilon) { edgeSnapAxis &= ~Axis.Z; } if (edgeSnapAxis == Axis.None) { continue; } float dist; var ray = new Ray(snappedPoint, xAxis); if ((edgeSnapAxis & Axis.X) != Axis.None && worldPlane.SignedRaycast(ray, out dist)) { var planePoint = ray.GetPoint(dist); var abs_dist = (planePoint - intersectionPoint).magnitude * preferenceFactor; if (abs_dist < bestDist) { bestDist = abs_dist; snappedPoint = planePoint; } } ray.direction = yAxis; if ((edgeSnapAxis & Axis.Y) != Axis.None && worldPlane.SignedRaycast(ray, out dist)) { var planePoint = ray.GetPoint(dist); var abs_dist = (planePoint - intersectionPoint).magnitude * preferenceFactor; if (abs_dist < bestDist) { bestDist = abs_dist; snappedPoint = planePoint; } } ray.direction = zAxis; if ((edgeSnapAxis & Axis.Z) != Axis.None && worldPlane.SignedRaycast(ray, out dist)) { var planePoint = ray.GetPoint(dist); var abs_dist = (planePoint - intersectionPoint).magnitude * preferenceFactor; if (abs_dist < bestDist) { bestDist = abs_dist; snappedPoint = planePoint; } } } else { var closestPoint = worldPlane.ClosestPointOnPlane(intersectionPoint); var dist = (closestPoint - intersectionPoint).magnitude * preferenceFactor; if (dist < bestDist) { bestDist = dist; snappedPoint = closestPoint; } } } }