/** * Initialize a new instance of Quick Edit, taking care of caching and setting up the appropriate stores. */ void Initialize() { SceneView.onSceneGUIDelegate += OnSceneGUI; Undo.undoRedoPerformed += UndoRedoPerformed; if (selection == null) { selection = ScriptableObject.CreateInstance <ElementCache>(); selection.hideFlags = HideFlags.DontSave; } if (selection.mesh == null) { MeshFilter mf = Selection.transforms.Select(x => x.GetComponentInChildren <MeshFilter>()).FirstOrDefault(); if (mf == null) { SkinnedMeshRenderer mr = Selection.transforms.Select(x => x.GetComponentInChildren <SkinnedMeshRenderer>()).FirstOrDefault(); if (mr == null || mr.sharedMesh == null) { qe_Editor_Utility.ShowNotification("No Mesh Selected"); EditorApplication.delayCall += Close; } else { SetSelection(mr.gameObject); } } else { SetSelection(mf.gameObject); } } else { SceneView.RepaintAll(); } LoadIcons(); }
public static bool VertexRaycast(Vector2 mousePosition, int rectSize, ElementCache selection, out int index) { qe_Mesh mesh = selection.mesh; float bestDistance = Mathf.Infinity; float distance = 0f; index = -1; GameObject go = HandleUtility.PickGameObject(mousePosition, false); if( go == null || go != selection.transform.gameObject ) { Camera cam = SceneView.lastActiveSceneView.camera; int width = Screen.width; int height = Screen.height; Rect mouseRect = new Rect(mousePosition.x - (rectSize/2f), mousePosition.y - (rectSize/2f), rectSize, rectSize); List<int> user = (List<int>) selection.mesh.GetUserIndices(); for(int i = 0; i < user.Count; i++) { if( mouseRect.Contains( HandleUtility.WorldToGUIPoint(selection.verticesInWorldSpace[user[i]]) ) ) { Vector3 v = cam.WorldToScreenPoint(selection.verticesInWorldSpace[user[i]]); distance = Vector2.Distance(mousePosition, v); if( distance < bestDistance ) { if( v.z <= 0 || v.x < 0 || v.y < 0 || v.x > width || v.y > height ) continue; if( PointIsOccluded(mesh, selection.verticesInWorldSpace[user[i]]) ) continue; index = user[i]; bestDistance = Vector2.Distance(v, mousePosition); } } } } else { // Test culling List<qe_RaycastHit> hits; Ray ray = HandleUtility.GUIPointToWorldRay(mousePosition); if( MeshRaycast(ray, mesh, out hits, Mathf.Infinity, Culling.FrontBack) ) { // Sort from nearest hit to farthest hits.Sort( (x, y) => x.Distance.CompareTo(y.Distance) ); // Find the nearest edge in the hit faces Vector3[] v = mesh.vertices; for(int i = 0; i < hits.Count; i++) { if( PointIsOccluded(mesh, mesh.transform.TransformPoint(hits[i].Point)) ) continue; foreach(int tri in mesh.faces[hits[i].FaceIndex].indices) { float d = Vector3.Distance(hits[i].Point, v[tri]); if(d < bestDistance) { bestDistance = d; index = tri; } } if( Vector3.Dot(ray.direction, mesh.transform.TransformDirection(hits[i].Normal)) < 0f ) break; } if(index > -1 && Vector2.Distance(mousePosition, HandleUtility.WorldToGUIPoint(selection.verticesInWorldSpace[index])) > rectSize * 1.3f) { index = -1; } } } if( index > -1 ) index = mesh.ToUserIndex(index); return index > -1; }
public static bool VertexRaycast(Vector2 mousePosition, int rectSize, ElementCache selection, out int index) { qe_Mesh mesh = selection.mesh; float bestDistance = Mathf.Infinity; float distance = 0f; index = -1; GameObject go = HandleUtility.PickGameObject(mousePosition, false); if (go == null || go != selection.transform.gameObject) { Camera cam = SceneView.lastActiveSceneView.camera; int width = Screen.width; int height = Screen.height; Rect mouseRect = new Rect(mousePosition.x - (rectSize / 2f), mousePosition.y - (rectSize / 2f), rectSize, rectSize); List <int> user = (List <int>)selection.mesh.GetUserIndices(); for (int i = 0; i < user.Count; i++) { if (mouseRect.Contains(HandleUtility.WorldToGUIPoint(selection.verticesInWorldSpace[user[i]]))) { Vector3 v = cam.WorldToScreenPoint(selection.verticesInWorldSpace[user[i]]); distance = Vector2.Distance(mousePosition, v); if (distance < bestDistance) { if (v.z <= 0 || v.x < 0 || v.y < 0 || v.x > width || v.y > height) { continue; } if (PointIsOccluded(mesh, selection.verticesInWorldSpace[user[i]])) { continue; } index = user[i]; bestDistance = Vector2.Distance(v, mousePosition); } } } } else { // Test culling List <qe_RaycastHit> hits; Ray ray = HandleUtility.GUIPointToWorldRay(mousePosition); if (MeshRaycast(ray, mesh, out hits, Mathf.Infinity, Culling.FrontBack)) { // Sort from nearest hit to farthest hits.Sort((x, y) => x.Distance.CompareTo(y.Distance)); // Find the nearest edge in the hit faces Vector3[] v = mesh.vertices; for (int i = 0; i < hits.Count; i++) { if (PointIsOccluded(mesh, mesh.transform.TransformPoint(hits[i].Point))) { continue; } foreach (int tri in mesh.faces[hits[i].FaceIndex].indices) { float d = Vector3.Distance(hits[i].Point, v[tri]); if (d < bestDistance) { bestDistance = d; index = tri; } } if (Vector3.Dot(ray.direction, mesh.transform.TransformDirection(hits[i].Normal)) < 0f) { break; } } if (index > -1 && Vector2.Distance(mousePosition, HandleUtility.WorldToGUIPoint(selection.verticesInWorldSpace[index])) > rectSize * 1.3f) { index = -1; } } } if (index > -1) { index = mesh.ToUserIndex(index); } return(index > -1); }
/** * Checks if mouse is over an edge, and if so, returns true setting @edge. */ public static bool EdgeRaycast(Vector2 mousePosition, ElementCache selection, out qe_Edge edge) { qe_Mesh mesh = selection.mesh; Vector3 v0, v1; float bestDistance = Mathf.Infinity; float distance = 0f; edge = null; GameObject go = HandleUtility.PickGameObject(mousePosition, false); if( go == null || go != selection.transform.gameObject) { qe_Edge[] edges = mesh.userEdges; int width = Screen.width; int height = Screen.height; for(int i = 0; i < edges.Length; i++) { v0 = selection.verticesInWorldSpace[edges[i].x]; v1 = selection.verticesInWorldSpace[edges[i].y]; distance = HandleUtility.DistanceToLine(v0, v1); if ( distance < bestDistance && distance < MAX_EDGE_SELECT_DISTANCE )// && !PointIsOccluded(mesh, (v0+v1)*.5f) ) { Vector3 vs0 = SceneView.lastActiveSceneView.camera.WorldToScreenPoint(v0); // really simple frustum check (will fail on edges that have vertices outside the frustum but is visible) if( vs0.z <= 0 || vs0.x < 0 || vs0.y < 0 || vs0.x > width || vs0.y > height ) continue; Vector3 vs1 = SceneView.lastActiveSceneView.camera.WorldToScreenPoint(v1); if( vs1.z <= 0 || vs1.x < 0 || vs1.y < 0 || vs1.x > width || vs1.y > height ) continue; bestDistance = distance; edge = edges[i]; } } } else { // Test culling List<qe_RaycastHit> hits; Ray ray = HandleUtility.GUIPointToWorldRay(mousePosition); if( MeshRaycast(ray, mesh, out hits, Mathf.Infinity, Culling.FrontBack) ) { // Sort from nearest hit to farthest hits.Sort( (x, y) => x.Distance.CompareTo(y.Distance) ); // Find the nearest edge in the hit faces Vector3[] v = mesh.vertices; for(int i = 0; i < hits.Count; i++) { if( PointIsOccluded(mesh, mesh.transform.TransformPoint(hits[i].Point)) ) continue; foreach(qe_Edge e in mesh.faces[hits[i].FaceIndex].GetEdges()) { float d = HandleUtility.DistancePointLine(hits[i].Point, v[e.x], v[e.y]); if(d < bestDistance) { bestDistance = d; edge = e; } } if( Vector3.Dot(ray.direction, mesh.transform.TransformDirection(hits[i].Normal)) < 0f ) break; } if(edge != null && HandleUtility.DistanceToLine(mesh.transform.TransformPoint(v[edge.x]), mesh.transform.TransformPoint(v[edge.y])) > MAX_EDGE_SELECT_DISTANCE) { edge = null; } else { edge.x = mesh.ToUserIndex(edge.x); edge.y = mesh.ToUserIndex(edge.y); } } } return edge != null; }
/** * Checks if mouse is over an edge, and if so, returns true setting @edge. */ public static bool EdgeRaycast(Vector2 mousePosition, ElementCache selection, out qe_Edge edge) { qe_Mesh mesh = selection.mesh; Vector3 v0, v1; float bestDistance = Mathf.Infinity; float distance = 0f; edge = null; GameObject go = HandleUtility.PickGameObject(mousePosition, false); if (go == null || go != selection.transform.gameObject) { qe_Edge[] edges = mesh.userEdges; int width = Screen.width; int height = Screen.height; for (int i = 0; i < edges.Length; i++) { v0 = selection.verticesInWorldSpace[edges[i].x]; v1 = selection.verticesInWorldSpace[edges[i].y]; distance = HandleUtility.DistanceToLine(v0, v1); if (distance < bestDistance && distance < MAX_EDGE_SELECT_DISTANCE) // && !PointIsOccluded(mesh, (v0+v1)*.5f) ) { Vector3 vs0 = SceneView.lastActiveSceneView.camera.WorldToScreenPoint(v0); // really simple frustum check (will fail on edges that have vertices outside the frustum but is visible) if (vs0.z <= 0 || vs0.x < 0 || vs0.y < 0 || vs0.x > width || vs0.y > height) { continue; } Vector3 vs1 = SceneView.lastActiveSceneView.camera.WorldToScreenPoint(v1); if (vs1.z <= 0 || vs1.x < 0 || vs1.y < 0 || vs1.x > width || vs1.y > height) { continue; } bestDistance = distance; edge = edges[i]; } } } else { // Test culling List <qe_RaycastHit> hits; Ray ray = HandleUtility.GUIPointToWorldRay(mousePosition); if (MeshRaycast(ray, mesh, out hits, Mathf.Infinity, Culling.FrontBack)) { // Sort from nearest hit to farthest hits.Sort((x, y) => x.Distance.CompareTo(y.Distance)); // Find the nearest edge in the hit faces Vector3[] v = mesh.vertices; for (int i = 0; i < hits.Count; i++) { if (PointIsOccluded(mesh, mesh.transform.TransformPoint(hits[i].Point))) { continue; } foreach (qe_Edge e in mesh.faces[hits[i].FaceIndex].GetEdges()) { float d = HandleUtility.DistancePointLine(hits[i].Point, v[e.x], v[e.y]); if (d < bestDistance) { bestDistance = d; edge = e; } } if (Vector3.Dot(ray.direction, mesh.transform.TransformDirection(hits[i].Normal)) < 0f) { break; } } if (edge != null && HandleUtility.DistanceToLine(mesh.transform.TransformPoint(v[edge.x]), mesh.transform.TransformPoint(v[edge.y])) > MAX_EDGE_SELECT_DISTANCE) { edge = null; } else { edge.x = mesh.ToUserIndex(edge.x); edge.y = mesh.ToUserIndex(edge.y); } } } return(edge != null); }