/** * Get an array of qe_Edge from this mesh (three per-triangle). */ public qe_Edge[] GetEdges() { int[] tris = cloneMesh.triangles; qe_Edge[] edges = new qe_Edge[tris.Length]; for (int i = 0; i < tris.Length; i += 3) { edges[i + 0] = new qe_Edge(tris[i + 0], tris[i + 1]); edges[i + 1] = new qe_Edge(tris[i + 1], tris[i + 2]); edges[i + 2] = new qe_Edge(tris[i + 2], tris[i + 0]); } return(edges); }
/** * 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); }