private static int CompareHits(ProbeHit a, ProbeHit b) { var distanceA = a.distance ?? Mathf.Infinity; var distanceB = b.distance ?? Mathf.Infinity; return(distanceA.CompareTo(distanceB)); }
public static void PickAllNonAlloc(List <ProbeHit> hits, ProbeFilter filter, SceneView sceneView, Vector2 guiPosition, int limit = DefaultLimit) { var screenPosition = HandleUtility.GUIPointToScreenPixelCoordinate(guiPosition); var ray3D = HandleUtility.GUIPointToWorldRay(guiPosition); var worldPosition = sceneView.camera.ScreenToWorldPoint(screenPosition); var layerMask = PeekPlugin.Configuration.probeLayerMask; var raycastHits = ArrayPool <RaycastHit> .New(limit); var overlapHits = ArrayPool <Collider2D> .New(limit); var handleHits = HashSetPool <GameObject> .New(); var ancestorHits = HashSetPool <ProbeHit> .New(); #if PROBUILDER_4_OR_NEWER var proBuilderHits = ListPool <ProbeHit> .New(); #endif var gameObjectHits = DictionaryPool <GameObject, ProbeHit> .New(); try { // Raycast (3D) if (filter.raycast) { var raycastHitCount = Physics.RaycastNonAlloc(ray3D, raycastHits, Mathf.Infinity, layerMask); for (var i = 0; i < raycastHitCount; i++) { var raycastHit = raycastHits[i]; #if UNITY_2019_2_OR_NEWER if (SceneVisibilityManager.instance.IsHidden(raycastHit.transform.gameObject)) { continue; } #endif var gameObject = raycastHit.transform.gameObject; if (!gameObjectHits.TryGetValue(gameObject, out var hit)) { hit = new ProbeHit(gameObject); } hit.point = raycastHit.point; hit.distance = raycastHit.distance; gameObjectHits[gameObject] = hit; } } // Overlap (2D) if (filter.overlap) { var overlapHitCount = Physics2D.OverlapPointNonAlloc(worldPosition, overlapHits, layerMask); for (var i = 0; i < overlapHitCount; i++) { var overlapHit = overlapHits[i]; #if UNITY_2019_2_OR_NEWER if (SceneVisibilityManager.instance.IsHidden(overlapHit.transform.gameObject)) { continue; } #endif var gameObject = overlapHit.transform.gameObject; if (!gameObjectHits.TryGetValue(gameObject, out var hit)) { hit = new ProbeHit(gameObject); } hit.distance = hit.distance ?? Vector3.Distance(overlapHit.transform.position, worldPosition); gameObjectHits[gameObject] = hit; } } // Handles (Editor Default) if (filter.handles && canPickHandles) { PickAllHandlesNonAlloc(handleHits, guiPosition, limit); foreach (var handleHit in handleHits) { var gameObject = handleHit; if (!gameObjectHits.TryGetValue(gameObject, out var hit)) { hit = new ProbeHit(gameObject); } hit.distance = hit.distance ?? Vector3.Distance(handleHit.transform.position, worldPosition); gameObjectHits[gameObject] = hit; } } // Ancestors foreach (var gameObjectHit in gameObjectHits) { var gameObject = gameObjectHit.Key; var hit = gameObjectHit.Value; var parent = gameObject.transform.parent; int depth = 0; while (parent != null) { var parentGameObject = parent.gameObject; var parentHit = new ProbeHit(parentGameObject); parentHit.groupGameObject = gameObject; parentHit.distance = hit.distance ?? Vector3.Distance(parentHit.transform.position, worldPosition); parentHit.groupOrder = 1000 + depth; ancestorHits.Add(parentHit); parent = parent.parent; depth++; } } #if PROBUILDER_4_OR_NEWER // ProBuilder if (filter.proBuilder && ProBuilderEditor.instance != null) { var proBuilderMeshes = ListPool <ProBuilderMesh> .New(); try { foreach (var gameObjectHit in gameObjectHits.Values) { var proBuilderMesh = gameObjectHit.gameObject.GetComponent <ProBuilderMesh>(); if (proBuilderMesh != null) { proBuilderMeshes.Add(proBuilderMesh); } } PickProBuilderElementsNonAlloc(proBuilderHits, proBuilderMeshes, sceneView, guiPosition); } finally { proBuilderMeshes.Free(); } } #endif // Prepare final hits hits.Clear(); // Add hits foreach (var gameObjectHit in gameObjectHits.Values) { hits.Add(gameObjectHit); } foreach (var ancestorHit in ancestorHits) { hits.Add(ancestorHit); } #if PROBUILDER_4_OR_NEWER foreach (var proBuilderHit in proBuilderHits) { hits.Add(proBuilderHit); } #endif // Sort by distance hits.Sort(compareHits); } finally { raycastHits.Free(); overlapHits.Free(); handleHits.Free(); ancestorHits.Free(); #if PROBUILDER_4_OR_NEWER proBuilderHits.Free(); #endif gameObjectHits.Free(); } }
private static void PickProBuilderElementsNonAlloc(List <ProbeHit> hits, List <ProBuilderMesh> meshes, SceneView sceneView, Vector2 guiPosition) { var screenPosition = HandleUtility.GUIPointToScreenPixelCoordinate(guiPosition); var worldPosition = sceneView.camera.ScreenToWorldPoint(screenPosition); var pickRadius = PeekPlugin.Configuration.probeProBuilderRadius; var pickerOptions = PickerOptions.Default; pickerOptions.depthTest = PeekPlugin.Configuration.probeProBuilderDepthTest; var pickRect = new Rect ( guiPosition.x - pickRadius, guiPosition.y - pickRadius, 2 * pickRadius, 2 * pickRadius ); var verticesByMeshes = SelectionPicker.PickVerticesInRect(sceneView.camera, pickRect, meshes, pickerOptions, EditorGUIUtility.pixelsPerPoint); var edgesByMeshes = SelectionPicker.PickEdgesInRect(sceneView.camera, pickRect, meshes, pickerOptions, EditorGUIUtility.pixelsPerPoint); var facesByMeshes = SelectionPicker.PickFacesInRect(sceneView.camera, pickRect, meshes, pickerOptions, EditorGUIUtility.pixelsPerPoint); foreach (var verticesByMesh in verticesByMeshes) { var mesh = verticesByMesh.Key; var gameObject = mesh.gameObject; var vertices = verticesByMesh.Value; var meshVertices = mesh.GetVertices(); var sharedVertices = mesh.sharedVertices; foreach (var vertexIndex in vertices) { var hit = new ProbeHit(gameObject); var vertex = meshVertices[vertexIndex]; var sharedVertex = sharedVertices[vertexIndex]; var sharedVertexIndex = sharedVertex[0]; hit.point = vertex.position; hit.distance = Vector3.Distance(vertex.position, worldPosition); hit.label = $"{mesh.name}: Vertex {vertexIndex}"; hit.icon = PeekProBuilderIntegration.Icons.vertex; hit.groupOrder = 1; hit.selectHandler = (add) => { Selection.activeGameObject = gameObject; ProBuilderEditor.selectMode = SelectMode.Vertex; Undo.RecordObject(mesh, "Selection Change"); if (add) { mesh.SetSelectedVertices(mesh.selectedVertices.Concat(sharedVertex)); } else { mesh.SetSelectedVertices(sharedVertex); } PeekProBuilderIntegration.UpdateSelection(); }; hit.focusHandler = () => ProBuilderHighlight(new SceneSelection(mesh, sharedVertexIndex)); hit.lostFocusHandler = ClearProBuilderHighlight; hits.Add(hit); } } foreach (var edgesByMesh in edgesByMeshes) { var mesh = edgesByMesh.Key; var gameObject = mesh.gameObject; var edges = edgesByMesh.Value; var meshVertices = mesh.GetVertices(); var sharedVertices = mesh.sharedVertices; var visited = HashSetPool <(int, int)> .New(); foreach (var edge in edges) { var hit = new ProbeHit(gameObject); var vertexA = meshVertices[edge.a]; var vertexB = meshVertices[edge.b]; var center = (vertexA.position + vertexB.position) / 2; var sharedVertexIndexA = -1; var sharedVertexIndexB = -1; for (var currentSharedIndex = 0; currentSharedIndex < sharedVertices.Count; currentSharedIndex++) { var sharedVertex = sharedVertices[currentSharedIndex]; if (sharedVertex.Contains(edge.a)) { sharedVertexIndexA = currentSharedIndex; } if (sharedVertex.Contains(edge.b)) { sharedVertexIndexB = currentSharedIndex; } } var sharedVertexIndexMin = Mathf.Min(sharedVertexIndexA, sharedVertexIndexB); var sharedVertexIndexMax = Mathf.Max(sharedVertexIndexA, sharedVertexIndexB); if (visited.Contains((sharedVertexIndexMin, sharedVertexIndexMax))) { continue; } hit.point = center; hit.distance = Vector3.Distance(center, worldPosition); hit.label = $"{mesh.name}: Edge [{sharedVertexIndexMin}, {sharedVertexIndexMax}]"; hit.icon = PeekProBuilderIntegration.Icons.edge; hit.groupOrder = 2; hit.selectHandler = (add) => { Selection.activeGameObject = gameObject; ProBuilderEditor.selectMode = SelectMode.Edge; Undo.RecordObject(mesh, "Selection Change"); if (add) { mesh.SetSelectedEdges(mesh.selectedEdges.Append(edge)); } else { mesh.SetSelectedEdges(edge.Yield()); } PeekProBuilderIntegration.UpdateSelection(); }; hit.focusHandler = () => ProBuilderHighlight(new SceneSelection(mesh, edge)); hit.lostFocusHandler = ClearProBuilderHighlight; hits.Add(hit); visited.Add((sharedVertexIndexMin, sharedVertexIndexMax)); } visited.Free(); } foreach (var facesByMesh in facesByMeshes) { var mesh = facesByMesh.Key; var gameObject = mesh.gameObject; var faces = facesByMesh.Value; var meshVertices = mesh.GetVertices(); var meshFaces = mesh.faces; foreach (var face in faces) { var faceIndex = meshFaces.IndexOf(face); var hit = new ProbeHit(gameObject); var center = Vector3.zero; foreach (var vertexIndex in face.distinctIndexes) { var vertex = meshVertices[vertexIndex]; center += vertex.position; } center /= face.distinctIndexes.Count; hit.point = center; hit.distance = Vector3.Distance(center, worldPosition); hit.label = $"{mesh.name}: Face {faceIndex}"; hit.icon = PeekProBuilderIntegration.Icons.face; hit.groupOrder = 3; hit.selectHandler = (add) => { Selection.activeGameObject = gameObject; ProBuilderEditor.selectMode = SelectMode.Face; Undo.RecordObject(mesh, "Selection Change"); if (add) { mesh.SetSelectedFaces(mesh.GetSelectedFaces().Append(face)); } else { mesh.SetSelectedFaces(null); mesh.SetSelectedFaces(face.Yield()); } PeekProBuilderIntegration.UpdateSelection(); }; hit.focusHandler = () => ProBuilderHighlight(new SceneSelection(mesh, face)); hit.lostFocusHandler = ClearProBuilderHighlight; hits.Add(hit); } } }