void LoadSettings() { EditorApplication.delayCall += EditorHandleDrawing.ResetPreferences; m_ScenePickerPreferences = new ScenePickerPreferences() { cullMode = m_BackfaceSelectEnabled ? CullingMode.None : CullingMode.Back, selectionModifierBehavior = m_SelectModifierBehavior, rectSelectMode = m_DragSelectRectMode }; }
static float VertexRaycast(Vector3 mousePosition, ScenePickerPreferences pickerOptions, bool allowUnselected, SceneSelection selection) { Camera cam = SceneView.lastActiveSceneView.camera; selection.Clear(); s_NearestVertices.Clear(); selection.gameObject = HandleUtility.PickGameObject(mousePosition, false); float maxDistance = ScenePickerPreferences.maxPointerDistance * ScenePickerPreferences.maxPointerDistance; ProBuilderMesh hoveredMesh = selection.gameObject != null?selection.gameObject.GetComponent <ProBuilderMesh>() : null; if (allowUnselected && selection.gameObject != null) { if (hoveredMesh != null && hoveredMesh.selectable && !MeshSelection.Contains(hoveredMesh)) { GetNearestVertices(hoveredMesh, mousePosition, s_NearestVertices, maxDistance, 1); } } if (selection.mesh == null) { foreach (var mesh in MeshSelection.topInternal) { if (!mesh.selectable) { continue; } GetNearestVertices(mesh, mousePosition, s_NearestVertices, maxDistance, hoveredMesh == mesh || hoveredMesh == null ? 1.0f : ScenePickerPreferences.offPointerMultiplier); } } s_NearestVertices.Sort((x, y) => x.screenDistance.CompareTo(y.screenDistance)); for (int i = 0; i < s_NearestVertices.Count; i++) { if (!UnityEngine.ProBuilder.HandleUtility.PointIsOccluded(cam, s_NearestVertices[i].mesh, s_NearestVertices[i].worldPosition)) { selection.gameObject = s_NearestVertices[i].mesh.gameObject; selection.mesh = s_NearestVertices[i].mesh; selection.SetSingleVertex(s_NearestVertices[i].vertex); return(Mathf.Sqrt(s_NearestVertices[i].screenDistance)); } } return(Mathf.Infinity); }
void LoadSettings() { EditorMeshHandles.ResetPreferences(); m_ScenePickerPreferences = new ScenePickerPreferences() { maxPointerDistance = ScenePickerPreferences.maxPointerDistanceFuzzy, cullMode = m_BackfaceSelectEnabled ? CullingMode.None : CullingMode.Back, selectionModifierBehavior = m_SelectModifierBehavior, rectSelectMode = m_DragSelectRectMode }; // workaround for old single-key shortcuts if (s_Shortcuts.value == null || s_Shortcuts.value.Length < 1) { s_Shortcuts.SetValue(Shortcut.DefaultShortcuts().ToArray(), true); } }
// Get the object & mesh selection that the mouse is currently nearest. // A ProBuilderMesh is returned because double click actions need to know what the last selected pb_Object was. // If deepClickOffset is specified, the object + deepClickOffset in the deep select stack will be returned (instead of next). internal static float MouseRayHitTest( Vector3 mousePosition, SelectMode selectionMode, ScenePickerPreferences pickerOptions, SceneSelection selection, bool allowUnselected = false) { if (selectionMode.ContainsFlag(SelectMode.Edge | SelectMode.TextureEdge)) { return(EdgeRaycast(mousePosition, pickerOptions, allowUnselected, selection)); } if (selectionMode.ContainsFlag(SelectMode.Vertex | SelectMode.TextureVertex)) { return(VertexRaycast(mousePosition, pickerOptions, allowUnselected, selection)); } return(FaceRaycast(mousePosition, pickerOptions, allowUnselected, selection, 0, true)); }
void LoadSettings() { EditorMeshHandles.ResetPreferences(); m_ScenePickerPreferences = new ScenePickerPreferences() { offPointerMultiplier = s_PickingDistance * k_OffPointerMultiplierPercent, maxPointerDistance = s_PickingDistance, cullMode = m_BackfaceSelectEnabled ? CullingMode.None : CullingMode.Back, selectionModifierBehavior = m_SelectModifierBehavior, rectSelectMode = m_DragSelectRectMode }; #if !SHORTCUT_MANAGER // workaround for old single-key shortcuts if (s_Shortcuts.value == null || s_Shortcuts.value.Length < 1) { s_Shortcuts.SetValue(Shortcut.DefaultShortcuts().ToArray(), true); } #endif }
static float EdgeRaycast(Vector3 mousePosition, ScenePickerPreferences pickerPrefs, bool allowUnselected, SceneSelection selection) { selection.Clear(); selection.gameObject = UHandleUtility.PickGameObject(mousePosition, false); var hoveredMesh = selection.gameObject != null?selection.gameObject.GetComponent <ProBuilderMesh>() : null; float bestDistance = pickerPrefs.maxPointerDistance; float unselectedBestDistance = bestDistance; bool hoveredIsInSelection = MeshSelection.topInternal.Contains(hoveredMesh); if (hoveredMesh != null && (allowUnselected || hoveredIsInSelection)) { var tup = GetNearestEdgeOnMesh(hoveredMesh, mousePosition); if (tup.edge.IsValid() && tup.distance < pickerPrefs.maxPointerDistance) { selection.gameObject = hoveredMesh.gameObject; selection.mesh = hoveredMesh; selection.edge = tup.edge; unselectedBestDistance = tup.distance; // if it's in the selection, it automatically wins as best. if not, treat this is a fallback. if (hoveredIsInSelection) { return(tup.distance); } } } foreach (var mesh in MeshSelection.topInternal) { var trs = mesh.transform; var positions = mesh.positionsInternal; foreach (var face in mesh.facesInternal) { foreach (var edge in face.edges) { int x = edge.a; int y = edge.b; float d = UHandleUtility.DistanceToLine( trs.TransformPoint(positions[x]), trs.TransformPoint(positions[y])); if (d < bestDistance) { selection.gameObject = mesh.gameObject; selection.mesh = mesh; selection.edge = new Edge(x, y); bestDistance = d; } } } } if (selection.gameObject != null) { if (bestDistance < pickerPrefs.maxPointerDistance) { return(bestDistance); } return(unselectedBestDistance); } return(Mathf.Infinity); }
static float VertexRaycast(Vector3 mousePosition, ScenePickerPreferences pickerOptions, bool allowUnselected, SceneSelection selection) { Camera cam = SceneView.lastActiveSceneView.camera; selection.Clear(); s_NearestVertices.Clear(); selection.gameObject = HandleUtility.PickGameObject(mousePosition, false); float maxDistance = pickerOptions.maxPointerDistance * pickerOptions.maxPointerDistance; if (allowUnselected && selection.gameObject != null) { var mesh = selection.gameObject.GetComponent <ProBuilderMesh>(); if (mesh != null && mesh.selectable && !MeshSelection.Contains(mesh)) { var matches = GetNearestVertices(mesh, mousePosition, s_NearestVertices, maxDistance); for (int i = 0; i < matches; i++) { // Append `maxDistance` so that selected meshes are favored s_NearestVertices[i] = new VertexPickerEntry() { mesh = s_NearestVertices[i].mesh, vertex = s_NearestVertices[i].vertex, screenDistance = s_NearestVertices[i].screenDistance + maxDistance, worldPosition = s_NearestVertices[i].worldPosition }; } } } if (selection.mesh == null) { foreach (var mesh in MeshSelection.topInternal) { if (!mesh.selectable) { continue; } GetNearestVertices(mesh, mousePosition, s_NearestVertices, maxDistance); } } s_NearestVertices.Sort((x, y) => x.screenDistance.CompareTo(y.screenDistance)); for (int i = 0; i < s_NearestVertices.Count; i++) { if (!UnityEngine.ProBuilder.HandleUtility.PointIsOccluded(cam, s_NearestVertices[i].mesh, s_NearestVertices[i].worldPosition)) { selection.gameObject = s_NearestVertices[i].mesh.gameObject; selection.mesh = s_NearestVertices[i].mesh; selection.vertex = s_NearestVertices[i].vertex; // If mesh was unselected, remove the distance modifier if (s_NearestVertices[i].screenDistance > maxDistance) { return(Mathf.Sqrt(s_NearestVertices[i].screenDistance - maxDistance)); } return(Mathf.Sqrt(s_NearestVertices[i].screenDistance)); } } return(Mathf.Infinity); }
static float FaceRaycast(Vector3 mousePosition, ScenePickerPreferences pickerOptions, bool allowUnselected, SceneSelection selection, int deepClickOffset = 0, bool isPreview = true) { GameObject pickedGo = null; ProBuilderMesh pickedPb = null; Face pickedFace = null; int newHash = 0; // If any event modifiers are engaged don't cycle the deep click EventModifiers em = Event.current.modifiers; if (isPreview || em != EventModifiers.None) { EditorHandleUtility.GetHovered(mousePosition, s_OverlappingGameObjects); } else { EditorHandleUtility.GetAllOverlapping(mousePosition, s_OverlappingGameObjects); } selection.Clear(); float distance = Mathf.Infinity; for (int i = 0, next = 0, pickedCount = s_OverlappingGameObjects.Count; i < pickedCount; i++) { var go = s_OverlappingGameObjects[i]; var mesh = go.GetComponent <ProBuilderMesh>(); Face face = null; if (mesh != null && (allowUnselected || MeshSelection.topInternal.Contains(mesh))) { Ray ray = UHandleUtility.GUIPointToWorldRay(mousePosition); RaycastHit hit; if (UnityEngine.ProBuilder.HandleUtility.FaceRaycast(ray, mesh, out hit, Mathf.Infinity, pickerOptions.cullMode)) { face = mesh.facesInternal[hit.face]; distance = Vector2.SqrMagnitude(((Vector2)mousePosition) - HandleUtility.WorldToGUIPoint(mesh.transform.TransformPoint(hit.point))); } } // pb_Face doesn't define GetHashCode, meaning it falls to object.GetHashCode (reference comparison) int hash = face == null?go.GetHashCode() : face.GetHashCode(); if (s_DeepSelectionPrevious == hash) { next = (i + (1 + deepClickOffset)) % pickedCount; } if (next == i) { pickedGo = go; pickedPb = mesh; pickedFace = face; newHash = hash; // a prior hash was matched, this is the next. if // it's just the first iteration don't break (but do // set the default). if (next != 0) { break; } } } if (!isPreview) { s_DeepSelectionPrevious = newHash; } if (pickedGo != null) { Event.current.Use(); if (pickedPb != null) { if (pickedPb.selectable) { selection.gameObject = pickedGo; selection.mesh = pickedPb; selection.face = pickedFace; return(Mathf.Sqrt(distance)); } } // If clicked off a pb_Object but onto another gameobject, set the selection // and dip out. selection.gameObject = pickedGo; return(Mathf.Sqrt(distance)); } return(distance); }
public static ProBuilderMesh DoMouseClick(Event evt, SelectMode selectionMode, ScenePickerPreferences pickerPreferences) { bool appendModifier = EditorHandleUtility.IsAppendModifier(evt.modifiers); if (!appendModifier) { MeshSelection.SetSelection((GameObject)null); } float pickedElementDistance = Mathf.Infinity; if (selectionMode.ContainsFlag(SelectMode.Edge | SelectMode.TextureEdge)) { pickedElementDistance = EdgeRaycast(evt.mousePosition, pickerPreferences, true, s_Selection); } else if (selectionMode.ContainsFlag(SelectMode.Vertex | SelectMode.TextureVertex)) { pickedElementDistance = VertexRaycast(evt.mousePosition, pickerPreferences, true, s_Selection); } else { pickedElementDistance = FaceRaycast(evt.mousePosition, pickerPreferences, true, s_Selection, evt.clickCount > 1 ? -1 : 0, false); } evt.Use(); if (pickedElementDistance > pickerPreferences.maxPointerDistance) { if (appendModifier && Selection.gameObjects.Contains(s_Selection.gameObject)) { MeshSelection.RemoveFromSelection(s_Selection.gameObject); } else { MeshSelection.AddToSelection(s_Selection.gameObject); } return(null); } MeshSelection.AddToSelection(s_Selection.gameObject); if (s_Selection.mesh != null) { var mesh = s_Selection.mesh; if (s_Selection.face != null) { // Check for other editor mouse shortcuts first (todo proper event handling for mouse shortcuts) MaterialEditor matEditor = MaterialEditor.instance; if (matEditor != null && matEditor.ClickShortcutCheck(Event.current.modifiers, mesh, s_Selection.face)) { return(null); } UVEditor uvEditor = UVEditor.instance; if (uvEditor != null && uvEditor.ClickShortcutCheck(mesh, s_Selection.face)) { return(null); } var faces = mesh.faces as Face[] ?? mesh.faces.ToArray(); var ind = Array.IndexOf <Face>(faces, s_Selection.face); var sel = mesh.selectedFaceIndexes.IndexOf(ind); UndoUtility.RecordSelection(mesh, "Select Face"); if (sel > -1) { mesh.RemoveFromFaceSelectionAtIndex(sel); } else { mesh.AddToFaceSelection(ind); } } else if (s_Selection.edge != Edge.Empty) { int ind = mesh.IndexOf(mesh.selectedEdges, s_Selection.edge); UndoUtility.RecordSelection(mesh, "Select Edge"); if (ind > -1) { mesh.SetSelectedEdges(mesh.selectedEdges.ToArray().RemoveAt(ind)); } else { mesh.SetSelectedEdges(mesh.selectedEdges.ToArray().Add(s_Selection.edge)); } } else if (s_Selection.vertex > -1) { int ind = Array.IndexOf(mesh.selectedIndexesInternal, s_Selection.vertex); UndoUtility.RecordSelection(mesh, "Select Vertex"); if (ind > -1) { mesh.SetSelectedVertices(mesh.selectedIndexesInternal.RemoveAt(ind)); } else { mesh.SetSelectedVertices(mesh.selectedIndexesInternal.Add(s_Selection.vertex)); } } return(mesh); } return(null); }
public static void DoMouseDrag(Rect mouseDragRect, SelectMode selectionMode, ScenePickerPreferences scenePickerPreferences) { var pickingOptions = new PickerOptions() { depthTest = scenePickerPreferences.cullMode == CullingMode.Back, rectSelectMode = scenePickerPreferences.rectSelectMode }; UndoUtility.RecordSelection("Drag Select"); bool isAppendModifier = EditorHandleUtility.IsAppendModifier(Event.current.modifiers); if (!isAppendModifier) { MeshSelection.ClearElementSelection(); } bool elementsInDragRect = false; switch (selectionMode) { case SelectMode.Vertex: case SelectMode.TextureVertex: { Dictionary <ProBuilderMesh, HashSet <int> > selected = SelectionPicker.PickVerticesInRect( SceneView.lastActiveSceneView.camera, mouseDragRect, MeshSelection.topInternal, pickingOptions, EditorGUIUtility.pixelsPerPoint); foreach (var kvp in selected) { var mesh = kvp.Key; SharedVertex[] sharedIndexes = mesh.sharedVerticesInternal; HashSet <int> common; if (isAppendModifier) { common = mesh.GetSharedVertexHandles(mesh.selectedIndexesInternal); if (scenePickerPreferences.selectionModifierBehavior == SelectionModifierBehavior.Add) { common.UnionWith(kvp.Value); } else if (scenePickerPreferences.selectionModifierBehavior == SelectionModifierBehavior.Subtract) { common.RemoveWhere(x => kvp.Value.Contains(x)); } else if (scenePickerPreferences.selectionModifierBehavior == SelectionModifierBehavior.Difference) { common.SymmetricExceptWith(kvp.Value); } } else { common = kvp.Value; } elementsInDragRect |= kvp.Value.Any(); mesh.SetSelectedVertices(common.SelectMany(x => sharedIndexes[x])); } break; } case SelectMode.Face: case SelectMode.TextureFace: { Dictionary <ProBuilderMesh, HashSet <Face> > selected = SelectionPicker.PickFacesInRect( SceneView.lastActiveSceneView.camera, mouseDragRect, MeshSelection.topInternal, pickingOptions, EditorGUIUtility.pixelsPerPoint); foreach (var kvp in selected) { HashSet <Face> current; if (isAppendModifier) { current = new HashSet <Face>(kvp.Key.selectedFacesInternal); if (scenePickerPreferences.selectionModifierBehavior == SelectionModifierBehavior.Add) { current.UnionWith(kvp.Value); } else if (scenePickerPreferences.selectionModifierBehavior == SelectionModifierBehavior.Subtract) { current.RemoveWhere(x => kvp.Value.Contains(x)); } else if (scenePickerPreferences.selectionModifierBehavior == SelectionModifierBehavior.Difference) { current.SymmetricExceptWith(kvp.Value); } } else { current = kvp.Value; } elementsInDragRect |= kvp.Value.Any(); kvp.Key.SetSelectedFaces(current); } break; } case SelectMode.Edge: case SelectMode.TextureEdge: { var selected = SelectionPicker.PickEdgesInRect( SceneView.lastActiveSceneView.camera, mouseDragRect, MeshSelection.topInternal, pickingOptions, EditorGUIUtility.pixelsPerPoint); foreach (var kvp in selected) { ProBuilderMesh mesh = kvp.Key; Dictionary <int, int> common = mesh.sharedVertexLookup; HashSet <EdgeLookup> selectedEdges = EdgeLookup.GetEdgeLookupHashSet(kvp.Value, common); HashSet <EdgeLookup> current; if (isAppendModifier) { current = EdgeLookup.GetEdgeLookupHashSet(mesh.selectedEdges, common); if (scenePickerPreferences.selectionModifierBehavior == SelectionModifierBehavior.Add) { current.UnionWith(selectedEdges); } else if (scenePickerPreferences.selectionModifierBehavior == SelectionModifierBehavior.Subtract) { current.RemoveWhere(x => selectedEdges.Contains(x)); } else if (scenePickerPreferences.selectionModifierBehavior == SelectionModifierBehavior.Difference) { current.SymmetricExceptWith(selectedEdges); } } else { current = selectedEdges; } elementsInDragRect |= kvp.Value.Any(); mesh.SetSelectedEdges(current.Select(x => x.local)); } break; } } // if nothing was selected in the drag rect, clear the object selection too if (!elementsInDragRect && !isAppendModifier) { MeshSelection.ClearElementAndObjectSelection(); } ProBuilderEditor.Refresh(); SceneView.RepaintAll(); }
/// <summary> /// Get the nearest <see cref="Edge"/> to a screen position. /// </summary> /// <returns> /// Distance is returned as the screen distance to mesh, not edge. /// </returns> static float EdgeRaycast(Vector3 mousePosition, ScenePickerPreferences pickerPrefs, bool allowUnselected, SceneSelection selection) { selection.Clear(); selection.gameObject = UHandleUtility.PickGameObject(mousePosition, false); var hoveredMesh = selection.gameObject != null?selection.gameObject.GetComponent <ProBuilderMesh>() : null; float bestDistance = Mathf.Infinity; bool hoveredIsInSelection = MeshSelection.topInternal.Contains(hoveredMesh); if (hoveredMesh != null && (allowUnselected || hoveredIsInSelection)) { var tup = GetNearestEdgeOnMesh(hoveredMesh, mousePosition); if (tup.edge.IsValid()) { selection.gameObject = hoveredMesh.gameObject; selection.mesh = hoveredMesh; selection.SetSingleEdge(tup.edge); bestDistance = tup.distance; // If the nearest edge was acquired by a raycast, then the distance to mesh is 0f. if (hoveredIsInSelection) { return(tup.distance); } } } foreach (var mesh in MeshSelection.topInternal) { var trs = mesh.transform; var positions = mesh.positionsInternal; s_EdgeBuffer.Clear(); // When the pointer is over another object, apply a modifier to the distance to prefer picking the // object hovered over the currently selected var distMultiplier = (hoveredMesh == mesh || hoveredMesh == null) ? 1.0f : ScenePickerPreferences.offPointerMultiplier; foreach (var face in mesh.facesInternal) { foreach (var edge in face.edges) { int x = edge.a; int y = edge.b; float d = UHandleUtility.DistanceToLine( trs.TransformPoint(positions[x]), trs.TransformPoint(positions[y])); d *= distMultiplier; // best distance isn't set to maxPointerDistance because we want to preserve an unselected // gameobject over a selected gameobject with an out of bounds edge. if (d > ScenePickerPreferences.maxPointerDistance) { continue; } // account for stacked edges if (Mathf.Approximately(d, bestDistance)) { s_EdgeBuffer.Add(new Edge(x, y)); } else if (d < bestDistance) { s_EdgeBuffer.Clear(); s_EdgeBuffer.Add(new Edge(x, y)); selection.gameObject = mesh.gameObject; selection.mesh = mesh; selection.SetSingleEdge(new Edge(x, y)); bestDistance = d; } } } // If more than 1 edge is closest, the closest is one of the vertex. // Get closest edge to the camera. if (s_EdgeBuffer.Count > 1) { selection.SetSingleEdge(GetClosestEdgeToCamera(positions, s_EdgeBuffer)); } } return(selection.gameObject != null ? bestDistance : Mathf.Infinity); }
public static ProBuilderMesh DoMouseClick(Event evt, SelectMode selectionMode, ScenePickerPreferences pickerPreferences) { bool appendModifier = EditorHandleUtility.IsAppendModifier(evt.modifiers); bool addToSelectionModifier = EditorHandleUtility.IsSelectionAddModifier(evt.modifiers); bool addOrRemoveIfPresentFromSelectionModifier = EditorHandleUtility.IsSelectionAppendOrRemoveIfPresentModifier(evt.modifiers); bool pathSelectionModifier = EditorHandleUtility.IsSelectionPathModifier(evt.modifiers); float pickedElementDistance; if (selectionMode.ContainsFlag(SelectMode.Edge | SelectMode.TextureEdge)) { pickedElementDistance = EdgeRaycast(evt.mousePosition, pickerPreferences, k_AllowUnselected, s_Selection); } else if (selectionMode.ContainsFlag(SelectMode.Vertex | SelectMode.TextureVertex)) { pickedElementDistance = VertexRaycast(evt.mousePosition, pickerPreferences, k_AllowUnselected, s_Selection); } else { pickedElementDistance = FaceRaycast(evt.mousePosition, pickerPreferences, k_AllowUnselected, s_Selection, evt.clickCount > 1 ? -1 : 0, false); } evt.Use(); if (!appendModifier) { if (s_Selection.mesh != null) { s_Selection.mesh.ClearSelection(); } MeshSelection.SetSelection((GameObject)null); } if (pickedElementDistance > ScenePickerPreferences.maxPointerDistance) { if (appendModifier && Selection.gameObjects.Contains(s_Selection.gameObject)) { MeshSelection.RemoveFromSelection(s_Selection.gameObject); } else { MeshSelection.AddToSelection(s_Selection.gameObject); } return(null); } GameObject candidateNewActiveObject = s_Selection.gameObject; bool activeObjectSelectionChanged = Selection.gameObjects.Contains(s_Selection.gameObject) && s_Selection.gameObject != Selection.activeGameObject; if (s_Selection.mesh != null) { var mesh = s_Selection.mesh; foreach (var face in s_Selection.faces) { // Check for other editor mouse shortcuts first (todo proper event handling for mouse shortcuts) MaterialEditor matEditor = MaterialEditor.instance; if (matEditor != null && matEditor.ClickShortcutCheck(Event.current.modifiers, mesh, face)) { return(null); } UVEditor uvEditor = UVEditor.instance; if (uvEditor != null && uvEditor.ClickShortcutCheck(mesh, face)) { return(null); } var faces = mesh.faces as Face[] ?? mesh.faces.ToArray(); var ind = Array.IndexOf <Face>(faces, face); var sel = mesh.selectedFaceIndexes.IndexOf(ind); UndoUtility.RecordSelection(mesh, "Select Face"); if (sel > -1) { if (!appendModifier || addOrRemoveIfPresentFromSelectionModifier || (addToSelectionModifier && face == mesh.GetActiveFace() && !activeObjectSelectionChanged)) { mesh.RemoveFromFaceSelectionAtIndex(sel); if (addOrRemoveIfPresentFromSelectionModifier && activeObjectSelectionChanged) { candidateNewActiveObject = Selection.activeGameObject; } else if (mesh.selectedFaceCount == 0) { for (var i = MeshSelection.topInternal.Count - 1; i >= 0; i--) { if (MeshSelection.topInternal[i].selectedFaceCount > 0) { candidateNewActiveObject = MeshSelection.topInternal[i].gameObject; activeObjectSelectionChanged = true; break; } } } } else { mesh.selectedFaceIndicesInternal = mesh.selectedFaceIndicesInternal.Remove(ind); mesh.SetSelectedFaces(mesh.selectedFaceIndicesInternal.Add(ind)); } } else if (pathSelectionModifier && mesh.GetActiveFace() != null) { var pathFaces = SelectPathFaces.GetPath(mesh, Array.IndexOf <Face>(faces, mesh.GetActiveFace()), Array.IndexOf <Face>(faces, face)); foreach (var pathFace in pathFaces) { mesh.AddToFaceSelection(pathFace); } } else { mesh.AddToFaceSelection(ind); } } foreach (var edge in s_Selection.edges) { int ind = mesh.IndexOf(mesh.selectedEdges, edge); UndoUtility.RecordSelection(mesh, "Select Edge"); if (ind > -1) { if (!appendModifier || addOrRemoveIfPresentFromSelectionModifier || (addToSelectionModifier && edge == mesh.GetActiveEdge() && !activeObjectSelectionChanged)) { mesh.SetSelectedEdges(mesh.selectedEdges.ToArray().RemoveAt(ind)); if (addOrRemoveIfPresentFromSelectionModifier && activeObjectSelectionChanged) { candidateNewActiveObject = Selection.activeGameObject; } else if (mesh.selectedEdgeCount == 0) { for (var i = MeshSelection.topInternal.Count - 1; i >= 0; i--) { if (MeshSelection.topInternal[i].selectedEdgeCount > 0) { candidateNewActiveObject = MeshSelection.topInternal[i].gameObject; activeObjectSelectionChanged = true; break; } } } } else { mesh.selectedEdgesInternal = mesh.selectedEdgesInternal.Remove(edge); mesh.SetSelectedEdges(mesh.selectedEdgesInternal.Add(edge)); } } else { mesh.SetSelectedEdges(mesh.selectedEdges.ToArray().Add(edge)); } } foreach (var vertex in s_Selection.vertexes) { int ind = Array.IndexOf(mesh.selectedIndexesInternal, vertex); UndoUtility.RecordSelection(mesh, "Select Vertex"); if (ind > -1) { var sharedIndex = mesh.sharedVertexLookup[vertex]; var sharedVertex = mesh.sharedVerticesInternal[sharedIndex]; s_IndexBuffer.Clear(); foreach (var sVertex in sharedVertex) { var index = Array.IndexOf(mesh.selectedIndexesInternal, sVertex); if (index < 0) { continue; } s_IndexBuffer.Add(index); } s_IndexBuffer.Sort(); if (!appendModifier || addOrRemoveIfPresentFromSelectionModifier || (addToSelectionModifier && vertex == mesh.GetActiveVertex() && !activeObjectSelectionChanged)) { mesh.selectedIndexesInternal = mesh.selectedIndexesInternal.SortedRemoveAt(s_IndexBuffer); mesh.SetSelectedVertices(mesh.selectedIndexesInternal); if (addOrRemoveIfPresentFromSelectionModifier && activeObjectSelectionChanged) { candidateNewActiveObject = Selection.activeGameObject; } else if (mesh.selectedIndexesInternal.Length == 0) { for (var i = MeshSelection.topInternal.Count - 1; i >= 0; i--) { if (MeshSelection.topInternal[i].selectedIndexesInternal.Length > 0) { candidateNewActiveObject = MeshSelection.topInternal[i].gameObject; activeObjectSelectionChanged = true; break; } } } } else { mesh.selectedIndexesInternal = mesh.selectedIndexesInternal.SortedRemoveAt(s_IndexBuffer); mesh.SetSelectedVertices(mesh.selectedIndexesInternal.Add(vertex)); } } else { mesh.SetSelectedVertices(mesh.selectedIndexesInternal.Add(vertex)); } } if (activeObjectSelectionChanged) { MeshSelection.MakeActiveObject(candidateNewActiveObject); } else { MeshSelection.AddToSelection(candidateNewActiveObject); } return(mesh); } return(null); }
static float EdgeRaycast(Vector3 mousePosition, ScenePickerPreferences pickerPrefs, bool allowUnselected, SceneSelection selection) { selection.Clear(); selection.gameObject = UHandleUtility.PickGameObject(mousePosition, false); var hoveredMesh = selection.gameObject != null?selection.gameObject.GetComponent <ProBuilderMesh>() : null; float bestDistance = pickerPrefs.maxPointerDistance; float unselectedBestDistance = bestDistance; bool hoveredIsInSelection = MeshSelection.topInternal.Contains(hoveredMesh); if (hoveredMesh != null && (allowUnselected || hoveredIsInSelection)) { var tup = GetNearestEdgeOnMesh(hoveredMesh, mousePosition); if (tup.edge.IsValid() && tup.distance < pickerPrefs.maxPointerDistance) { selection.gameObject = hoveredMesh.gameObject; selection.mesh = hoveredMesh; selection.edge = tup.edge; unselectedBestDistance = tup.distance; // if it's in the selection, it automatically wins as best. if not, treat this is a fallback. if (hoveredIsInSelection) { return(tup.distance); } } } foreach (var mesh in MeshSelection.topInternal) { var trs = mesh.transform; var positions = mesh.positionsInternal; s_EdgeBuffer.Clear(); //When the pointer is over another object, apply a modifier to the distance to prefer picking the object hovered over the currently selected var distMultiplier = (hoveredMesh == mesh || hoveredMesh == null) ? 1.0f : pickerPrefs.offPointerMultiplier; foreach (var face in mesh.facesInternal) { foreach (var edge in face.edges) { int x = edge.a; int y = edge.b; float d = UHandleUtility.DistanceToLine( trs.TransformPoint(positions[x]), trs.TransformPoint(positions[y])); d *= distMultiplier; if (d == bestDistance) { s_EdgeBuffer.Add(new Edge(x, y)); } else if (d < bestDistance) { s_EdgeBuffer.Clear(); s_EdgeBuffer.Add(new Edge(x, y)); selection.gameObject = mesh.gameObject; selection.mesh = mesh; selection.edge = new Edge(x, y); bestDistance = d; } } } //If more than 1 edge is closest, the closest is one of the vertex. //Get closest edge to the camera. if (s_EdgeBuffer.Count > 1) { selection.edge = GetClosestEdgeToCamera(positions, s_EdgeBuffer); } } if (selection.gameObject != null) { if (bestDistance < pickerPrefs.maxPointerDistance) { return(bestDistance); } return(unselectedBestDistance); } return(Mathf.Infinity); }