/// <summary> /// Given a local edge, this guarantees that both indexes belong to the same face. /// Note that this will only return the first valid edge found - there will usually /// be multiple matches (well, 2 if your geometry is sane). /// </summary> /// <param name="mesh"></param> /// <param name="edge"></param> /// <param name="validEdge"></param> /// <returns></returns> public static bool ValidateEdge(ProBuilderMesh mesh, Edge edge, out SimpleTuple <Face, Edge> validEdge) { Face[] faces = mesh.facesInternal; SharedVertex[] sharedIndexes = mesh.sharedVerticesInternal; Edge universal = GetSharedVertexHandleEdge(mesh, edge); for (int i = 0; i < faces.Length; i++) { int dist_x = -1, dist_y = -1, shared_x = -1, shared_y = -1; if (faces[i].distinctIndexesInternal.ContainsMatch(sharedIndexes[universal.a].arrayInternal, out dist_x, out shared_x) && faces[i].distinctIndexesInternal.ContainsMatch(sharedIndexes[universal.b].arrayInternal, out dist_y, out shared_y)) { int x = faces[i].distinctIndexesInternal[dist_x]; int y = faces[i].distinctIndexesInternal[dist_y]; validEdge = new SimpleTuple <Face, Edge>(faces[i], new Edge(x, y)); return(true); } } validEdge = new SimpleTuple <Face, Edge>(); return(false); }
internal static bool FaceRaycastBothCullModes(Ray worldRay, ProBuilderMesh mesh, ref SimpleTuple <Face, Vector3> back, ref SimpleTuple <Face, Vector3> front) { // Transform ray into model space worldRay.origin -= mesh.transform.position; // Why doesn't worldToLocalMatrix apply translation? worldRay.origin = mesh.transform.worldToLocalMatrix * worldRay.origin; worldRay.direction = mesh.transform.worldToLocalMatrix * worldRay.direction; var positions = mesh.positionsInternal; var faces = mesh.facesInternal; back.item1 = null; front.item1 = null; float backDistance = Mathf.Infinity; float frontDistance = Mathf.Infinity; // Iterate faces, testing for nearest hit to ray origin. Optionally ignores backfaces. for (int i = 0, fc = faces.Length; i < fc; ++i) { int[] indexes = mesh.facesInternal[i].indexesInternal; for (int j = 0, ic = indexes.Length; j < ic; j += 3) { Vector3 a = positions[indexes[j + 0]]; Vector3 b = positions[indexes[j + 1]]; Vector3 c = positions[indexes[j + 2]]; float dist; Vector3 point; if (Math.RayIntersectsTriangle(worldRay, a, b, c, out dist, out point)) { if (dist < backDistance || dist < frontDistance) { Vector3 nrm = Vector3.Cross(b - a, c - a); float dot = Vector3.Dot(worldRay.direction, nrm); if (dot < 0f) { if (dist < backDistance) { backDistance = dist; back.item1 = faces[i]; } } else { if (dist < frontDistance) { frontDistance = dist; front.item1 = faces[i]; } } } } } } if (back.item1 != null) { back.item2 = worldRay.GetPoint(backDistance); } if (front.item1 != null) { front.item2 = worldRay.GetPoint(frontDistance); } return(back.item1 != null || front.item1 != null); }