Ejemplo n.º 1
0
        private static int CompareHits(ProbeHit a, ProbeHit b)
        {
            var distanceA = a.distance ?? Mathf.Infinity;
            var distanceB = b.distance ?? Mathf.Infinity;

            return(distanceA.CompareTo(distanceB));
        }
Ejemplo n.º 2
0
        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();
            }
        }
Ejemplo n.º 3
0
        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);
                }
            }
        }