Exemplo n.º 1
0
    // Every face should be a triangle! So call Triangulate first
    public void SplitInLeftAndRightMesh(HalfEdgeMesh left, HalfEdgeMesh right)
    {
        // Have to re-index everything :(
        Dictionary <Vector3, short> leftVertDict  = new Dictionary <Vector3, short>();
        Dictionary <Vector3, short> rightVertDict = new Dictionary <Vector3, short>();

        // First add the vertices, and get their indices
        short lVertIdx = 0;
        short rVertIdx = 0;

        foreach (HEVertex v in vertices)
        {
            HEVertex newVL = new HEVertex {
                v = v.v, heIndex = v.heIndex
            };
            HEVertex newVR = new HEVertex {
                v = v.v, heIndex = v.heIndex
            };
            if (v.config == PlaneConfig.Left)
            {
                newVL.config = PlaneConfig.Left;
                leftVertDict.Add(v.v, lVertIdx);
                left.vertices.Add(newVL);
                lVertIdx++;
            }
            else if (v.config == PlaneConfig.Right)
            {
                newVR.config = PlaneConfig.Right;
                rightVertDict.Add(v.v, rVertIdx);
                right.vertices.Add(newVR);
                rVertIdx++;
            }
            else
            {
                newVR.config = PlaneConfig.On;
                newVL.config = PlaneConfig.On;
                leftVertDict.Add(v.v, lVertIdx);
                left.vertices.Add(newVL);
                lVertIdx++;
                rightVertDict.Add(v.v, rVertIdx);
                right.vertices.Add(newVR);
                rVertIdx++;
            }
        }
        // The dicts should map old idx -> new idx...
        Dictionary <short, short> leftEdgeIdxMap  = new Dictionary <short, short>();
        Dictionary <short, short> rightEdgeIdxMap = new Dictionary <short, short>();
        Dictionary <short, short> leftFaceIdxMap  = new Dictionary <short, short>();
        Dictionary <short, short> rightFaceIdxMap = new Dictionary <short, short>();
        int lEdgeIdx = 0;
        int lFaceIdx = 0;
        int rEdgeIdx = 0;
        int rFaceIdx = 0;

        // Build the idx maps
        foreach (HalfEdge h in halfEdges)
        {
            PlaneConfig pConfig = GetFaceConfig(faces[h.faceIndex]);
            if (pConfig == PlaneConfig.Left)
            {
                leftEdgeIdxMap.Add(h.index, (short)lEdgeIdx);
                left.halfEdges.Add(h.Copy());
                lEdgeIdx++;
                if (!leftFaceIdxMap.ContainsKey(h.faceIndex))
                {
                    left.faces.Add(faces[h.faceIndex].Copy());
                    left.faces[lFaceIdx].heIndex = (short)(lEdgeIdx - 1);
                    leftFaceIdxMap.Add(h.faceIndex, (short)lFaceIdx);
                    lFaceIdx++;
                }
            }
            else if (pConfig == PlaneConfig.Right)
            {
                rightEdgeIdxMap.Add(h.index, (short)rEdgeIdx);
                right.halfEdges.Add(h.Copy());
                rEdgeIdx++;
                if (!rightFaceIdxMap.ContainsKey(h.faceIndex))
                {
                    right.faces.Add(faces[h.faceIndex].Copy());
                    right.faces[rFaceIdx].heIndex = (short)(rEdgeIdx - 1);
                    rightFaceIdxMap.Add(h.faceIndex, (short)rFaceIdx);
                    rFaceIdx++;
                }
            }
            else   // On, not possible for a face?
            {
                // ...
            }
        }
        // Update all the indices and stuff
        // Edge case is if both vertices are ON the plane, then they don't have an opposite edge
        // I think I will leave it and deal with it when triangulating the cap
        foreach (KeyValuePair <short, short> kvp in leftEdgeIdxMap)
        {
            // The edge
            left.halfEdges[kvp.Value].faceIndex = leftFaceIdxMap[halfEdges[kvp.Key].faceIndex];
            left.halfEdges[kvp.Value].nextIndex = leftEdgeIdxMap[halfEdges[kvp.Key].nextIndex];
            left.halfEdges[kvp.Value].verIndex  = leftVertDict[vertices[halfEdges[kvp.Key].verIndex].v];
            left.halfEdges[kvp.Value].index     = kvp.Value;
            // face done in loop above

            // Update vertices edge index, doesn't matter if we overwrite
            left.vertices[left.halfEdges[kvp.Value].verIndex].heIndex = kvp.Value;
        }
        foreach (KeyValuePair <short, short> kvp in rightEdgeIdxMap)
        {
            // The edge
            right.halfEdges[kvp.Value].faceIndex = rightFaceIdxMap[halfEdges[kvp.Key].faceIndex];
            right.halfEdges[kvp.Value].nextIndex = rightEdgeIdxMap[halfEdges[kvp.Key].nextIndex];
            right.halfEdges[kvp.Value].verIndex  = rightVertDict[vertices[halfEdges[kvp.Key].verIndex].v];
            right.halfEdges[kvp.Value].index     = kvp.Value;
            // face done in loop above

            // Update vertices edge index, doesn't matter if we overwrite
            right.vertices[right.halfEdges[kvp.Value].verIndex].heIndex = kvp.Value;
        }
    }
Exemplo n.º 2
0
    public void CutWithPlane(Plane plane)
    {
        float      sTime = Time.realtimeSinceStartup;
        GameObject child = gameObject.transform.GetChild(0).gameObject;

        meshFilter = child.GetComponent <MeshFilter>();
        mesh       = meshFilter.mesh;
        InitHalfEdgeMesh();
        bool[]          visited      = new bool[heMesh.halfEdges.Count];
        List <HalfEdge> newHalfEdges = new List <HalfEdge>();
        int             s            = heMesh.halfEdges.Count;
        int             rightCount   = 0;
        int             leftCount    = 0;
        Vector3         newVertCoord = Vector3.zero;
        int             onCount      = 0;

        /*
         * Dictionary<Vector3, Vector2> uvMap = new Dictionary<Vector3, Vector2>();
         * List<Vector2> uvs = new List<Vector2>();
         * mesh.GetUVs(0, uvs);
         * for (int i = 0; i < mesh.vertices.Length; i++)
         * {
         *  if (!uvMap.ContainsKey(mesh.vertices[i])) {
         *      uvMap.Add(mesh.vertices[i], uvs[i]);
         *  }
         * }*/
        for (int i = 0; i < s; i++)
        {
            if (visited[i])
            {
                continue;
            }
            // mark this and the opposite as visited
            HalfEdge he    = heMesh.halfEdges[i];
            HalfEdge heOpp = heMesh.halfEdges[he.oppositeIndex];
            visited[he.index]    = true;
            visited[heOpp.index] = true;

            // Check if intersection with plane
            Vector3 v0 = heMesh.vertices[he.verIndex].v;
            Vector3 v1 = heMesh.vertices[heOpp.verIndex].v;

            // First Set vertex plane config
            Vector3 c0     = v0 - plane.point;
            Vector3 c1     = v1 - plane.point;
            float   c0_dot = Vector3.Dot(c0, plane.normal);
            float   c1_dot = Vector3.Dot(c1, plane.normal);
            float   eps    = 0.0001f;
            if (Mathf.Abs(c0_dot) < eps)
            {
                heMesh.vertices[he.verIndex].config = PlaneConfig.On;
            }
            else if (c0_dot <= -eps)
            {
                heMesh.vertices[he.verIndex].config = PlaneConfig.Right;
                rightCount++;
            }
            else if (c0_dot >= eps)
            {
                heMesh.vertices[he.verIndex].config = PlaneConfig.Left;
                leftCount++;
            }
            if (Mathf.Abs(c1_dot) < eps)
            {
                heMesh.vertices[heOpp.verIndex].config = PlaneConfig.On;
            }
            else if (c1_dot <= -eps)
            {
                rightCount++;
                heMesh.vertices[heOpp.verIndex].config = PlaneConfig.Right;
            }
            else if (c1_dot >= eps)
            {
                leftCount++;
                heMesh.vertices[heOpp.verIndex].config = PlaneConfig.Left;
            }

            float   t;
            Vector3 iPoint = Plane.LinePlaneIntersect(plane, v0, v1, out t);
            if (t > 1.0f - eps || t < 0.0f + eps)
            {
                // No intersection on line segment OR parallel with plane
                continue;
            }
            // Debug.Log(t);
            // add new intersection vertex to half-edge structure
            HEVertex iVert = new HEVertex();
            iVert.v       = iPoint;
            onCount      += 1;
            newVertCoord += iPoint;
            iVert.heIndex = (short)heMesh.halfEdges.Count;
            iVert.config  = PlaneConfig.On;
            heMesh.vertices.Add(iVert);
            HalfEdge[] newHEs = HalfEdge.CreateFromTwo(he, heOpp, (short)heMesh.halfEdges.Count, (short)(heMesh.vertices.Count - 1));
            heMesh.halfEdges.Add(newHEs[0]);
            heMesh.halfEdges.Add(newHEs[1]);
            iPoints.Add(iPoint);
        }
        if (leftCount == 0 || rightCount == 0)
        {
            // Do nothing!!!!
            return;
        }
        heMesh.Triangulate();
        HalfEdgeMesh rightMesh = new HalfEdgeMesh();
        HalfEdgeMesh leftMesh  = new HalfEdgeMesh();

        heMesh.SplitInLeftAndRightMesh(leftMesh, rightMesh);

        GameObject         copy      = Instantiate(objectToCopy);
        GameObject         childCopy = copy.transform.GetChild(0).gameObject;
        SliceableWithPlane copyDebug = copy.GetComponent <SliceableWithPlane>();

        newVertCoord /= (float)onCount;

        rightMesh.CapClipPlane(plane.normal, newVertCoord);
        copyDebug.heMesh          = rightMesh;
        copyDebug.meshFilter      = childCopy.GetComponent <MeshFilter>();
        copyDebug.meshFilter.mesh = rightMesh.GetMesh();
        //  MeshFilter mfCpy = copy.GetComponent<MeshFilter>();
        leftMesh.CapClipPlane(-plane.normal, newVertCoord);
        meshFilter.mesh = leftMesh.GetMesh();

        /*
         * List<Vector2> newUVs = new List<Vector2>();
         * foreach (Vector3 v in meshFilter.mesh.vertices)
         * {
         *  if (!uvMap.ContainsKey(v))
         *  {
         *      newUVs.Add(Vector2.zero);
         *  } else
         *  {
         *      newUVs.Add(uvMap[v]);
         *  }
         * }
         * meshFilter.mesh.SetUVs(0, newUVs);
         */
        copyDebug.cutPlane = cutPlane;
        //heMesh.CreateStructureFromMesh(mesh);
        //copyDebug.heMesh.CreateStructureFromMesh(copyDebug.meshFilter.mesh);
        child.GetComponent <MeshCollider>().sharedMesh = null;
        child.GetComponent <MeshCollider>().sharedMesh = meshFilter.mesh;

        childCopy.GetComponent <MeshCollider>().sharedMesh = null;
        childCopy.GetComponent <MeshCollider>().sharedMesh = copyDebug.meshFilter.mesh;
        //  child.GetComponent<MeshCollider>().gameObject.SetActive(true);
        float eTime = Time.realtimeSinceStartup - sTime;

        Debug.Log("Time taken = " + eTime);
    }
Exemplo n.º 3
0
    public void CreateStructureFromMesh(Mesh mesh)
    {
        faces.Clear();
        vertices.Clear();
        halfEdges.Clear();
        int[]     meshTriangles = mesh.triangles;
        Vector3[] meshVertices  = mesh.vertices;
        Vector3[] meshNormals   = mesh.normals;

        // One face per triangle. Add normals
        for (int i = 0; i < meshTriangles.Length; i += 3)
        {
            HEFace f = new HEFace();
            // Take the mean of the triangle normals
            Vector3 n = meshNormals[meshTriangles[i]] + meshNormals[meshTriangles[i + 1]] + meshNormals[meshTriangles[i + 2]];
            n        = n / 3.0f;
            f.normal = n.normalized;
            faces.Add(f);
        }

        // Simplify mesh vertices i.e. remove duplicates.
        // There are duplicate vertices since they have different normals
        // Use a dictionary to store the vertices and their new indices
        Dictionary <Vector3, int> d        = new Dictionary <Vector3, int>();
        List <Vector3>            newVerts = new List <Vector3>();
        List <int> newTris = new List <int>();
        int        newIdx  = 0;

        for (int i = 0; i < meshVertices.Length; i++)
        {
            if (!d.ContainsKey(meshVertices[i]))
            {
                d[meshVertices[i]] = newIdx;
                newVerts.Add(meshVertices[i]);
                newIdx++;
            }
        }
        // Update the triangle indices to the new vertex indices.
        for (int i = 0; i < meshTriangles.Length; i++)
        {
            newTris.Add(d[meshVertices[meshTriangles[i]]]);
        }
        // Set to updated values
        meshVertices  = newVerts.ToArray();
        meshTriangles = newTris.ToArray();

        // Init the vertices with vertex data, but not half-edge
        for (int i = 0; i < meshVertices.Length; i++)
        {
            HEVertex vert = new HEVertex
            {
                v = meshVertices[i]
            };
            vertices.Add(vert);
        }

        // Dictionary for opposite lookup. Build in first loop over triangles, used in the second.
        // key is v0v1
        Dictionary <string, List <short> > edgeMap = new Dictionary <string, List <short> >();

        // Start with creating the halfedges and filling in everything except oppositite
        for (int i = 0; i < meshTriangles.Length; i += 3)
        {
            // Stored 3-by-3 indices. e.g. 0,1,2 forms the first triangle.
            short i0 = (short)i;
            short i1 = (short)(i + 1);
            short i2 = (short)(i + 2);

            // Triangles are in clockwise order in Unity
            HalfEdge h0 = new HalfEdge();
            HalfEdge h1 = new HalfEdge();
            HalfEdge h2 = new HalfEdge();

            h0.index = i0;
            h1.index = i1;
            h2.index = i2;

            h0.faceIndex = (short)(i0 / 3);
            h1.faceIndex = (short)(i0 / 3);
            h2.faceIndex = (short)(i0 / 3);

            h0.verIndex = (short)meshTriangles[i];
            h1.verIndex = (short)meshTriangles[i + 1];
            h2.verIndex = (short)meshTriangles[i + 2];

            // Set the vertices halfedge index. It doesn't matter if we overwrite previously set values.
            vertices[meshTriangles[i]].heIndex     = i0;
            vertices[meshTriangles[i + 1]].heIndex = i1;
            vertices[meshTriangles[i + 2]].heIndex = i2;
            // next entries. Unity wants clockwise order of vertices
            h0.nextIndex = h1.index;
            h1.nextIndex = h2.index;
            h2.nextIndex = h0.index;

            // Add them!
            halfEdges.Add(h0);
            halfEdges.Add(h1);
            halfEdges.Add(h2);

            // set face HalfEdge index. i0 is a multiple of 3
            faces[i0 / 3].heIndex = i0;
            // Fill edgemap, three times :)
            string sum;
            // This check is required so the ordering is consistent
            if (h0.verIndex >= h1.verIndex)
            {
                sum = h0.verIndex.ToString() + h1.verIndex.ToString();
            }
            else
            {
                sum = h1.verIndex.ToString() + h0.verIndex.ToString();
            }
            if (!edgeMap.ContainsKey(sum))
            {
                List <short> l = new List <short>();
                // add the face index
                l.Add(i0);
                edgeMap.Add(sum, l);
            }
            else
            {
                edgeMap[sum].Add(i0);
            }

            if (h1.verIndex >= h2.verIndex)
            {
                sum = h1.verIndex.ToString() + h2.verIndex.ToString();
            }
            else
            {
                sum = h2.verIndex.ToString() + h1.verIndex.ToString();
            }
            if (!edgeMap.ContainsKey(sum))
            {
                List <short> l = new List <short>();
                // add the face index
                l.Add(i1);
                edgeMap.Add(sum, l);
            }
            else
            {
                edgeMap[sum].Add(i1);
            }

            if (h0.verIndex >= h2.verIndex)
            {
                sum = h0.verIndex.ToString() + h2.verIndex.ToString();
            }
            else
            {
                sum = h2.verIndex.ToString() + h0.verIndex.ToString();
            }
            if (!edgeMap.ContainsKey(sum))
            {
                List <short> l = new List <short>();
                // add the face index
                l.Add(i2);
                edgeMap.Add(sum, l);
            }
            else
            {
                edgeMap[sum].Add(i2);
            }
        }

        // Fill the opposite entries
        for (int i = 0; i < meshTriangles.Length; i += 3)
        {
            // each edge is shared between exactly two faces
            // Stored 3-by-3 indices. e.g. 0,1,2 forms the first triangle.
            short    i0 = (short)i;
            short    i1 = (short)(i + 1);
            short    i2 = (short)(i + 2);
            HalfEdge h0 = halfEdges[i0];
            HalfEdge h1 = halfEdges[i1];
            HalfEdge h2 = halfEdges[i2];
            // First edge
            // Use our edgeMap to find opposites
            string sum;
            if (h0.verIndex >= h1.verIndex)
            {
                sum = h0.verIndex.ToString() + h1.verIndex.ToString();
            }
            else
            {
                sum = h1.verIndex.ToString() + h0.verIndex.ToString();
            }
            List <short> l = edgeMap[sum];

            short h0Idx = l[0];
            short h1Idx = l[1];
            halfEdges[h0Idx].oppositeIndex = h1Idx;
            halfEdges[h1Idx].oppositeIndex = h0Idx;

            // Second edge
            if (h1.verIndex >= h2.verIndex)
            {
                sum = h1.verIndex.ToString() + h2.verIndex.ToString();
            }
            else
            {
                sum = h2.verIndex.ToString() + h1.verIndex.ToString();
            }
            l = edgeMap[sum];

            h0Idx = l[0];
            h1Idx = l[1];
            halfEdges[h0Idx].oppositeIndex = h1Idx;
            halfEdges[h1Idx].oppositeIndex = h0Idx;

            // Third edge
            if (h0.verIndex >= h2.verIndex)
            {
                sum = h0.verIndex.ToString() + h2.verIndex.ToString();
            }
            else
            {
                sum = h2.verIndex.ToString() + h0.verIndex.ToString();
            }
            l = edgeMap[sum];

            h0Idx = l[0];
            h1Idx = l[1];
            halfEdges[h0Idx].oppositeIndex = h1Idx;
            halfEdges[h1Idx].oppositeIndex = h0Idx;
        }
    }
Exemplo n.º 4
0
    public void CapClipPlane(Vector3 planeNormal, Vector3 newVertCoord)
    {
        // VERY IMPORTANT: Changes the half-edge structure but it is not a complete structure!
        // No oppositeIndices are added. Can be made complete by generating the mesh and then turn the mesh
        // into a half-edge structure. Major hack and major performance loss.


        // Idea:
        // Cap the clip by generating a new vertex at the center of the clipping area.
        // Then take all faces with two ON vertices and create a new face :- )
        // Then do MeshFromHalfedge -> and back again for a good half-edge structure....

        // Calculate new vertex pos
        Vector3 centerVert = new Vector3(0.0f, 0.0f, 0.0f);

        foreach (HEVertex v in vertices)
        {
            if (v.config == PlaneConfig.On)
            {
                centerVert += v.v;
            }
        }
        centerVert = centerVert / (float)vertices.Count;
        HEVertex newVert = new HEVertex
        {
            v      = newVertCoord,
            config = PlaneConfig.On
        };

        vertices.Add(newVert);
        short verIdx = (short)(vertices.Count - 1);

        // Get all faces with two ON vertices
        Dictionary <short, List <short> > onFaces = GetTwoOnFaces();

        foreach (KeyValuePair <short, List <short> > kvp in onFaces)
        {
            // Make new face
            HalfEdge h0    = new HalfEdge();
            HalfEdge h1    = new HalfEdge();
            HalfEdge h2    = new HalfEdge();
            short    heIdx = (short)(halfEdges.Count);
            h0.index     = heIdx;
            h1.index     = (short)(heIdx + 1);
            h2.index     = (short)(heIdx + 2);
            h0.nextIndex = h1.index;
            h1.nextIndex = h2.index;
            h2.nextIndex = h0.index;
            h0.verIndex  = kvp.Value[0];
            h1.verIndex  = verIdx;
            h2.verIndex  = kvp.Value[1];
            // check correct winding order
            Vector3 v1     = (vertices[h1.verIndex].v - vertices[h0.verIndex].v).normalized;
            Vector3 v2     = (vertices[h2.verIndex].v - vertices[h0.verIndex].v).normalized;
            Vector3 c      = Vector3.Cross(v1, v2).normalized;
            Vector3 diff   = c - planeNormal;
            float   diff_m = diff.magnitude;

            // Debug.Log("Cross = " + (Vector3.Cross(v1.normalized, v2.normalized) - planeNormal.normalized).magnitude + ". Normal = " + planeNormal + ". " + (Vector3.Cross(v1.normalized, v2.normalized)));
            if (diff_m >= 0.01f)
            {
                h0.nextIndex = h2.index;
                h1.nextIndex = h0.index;
                h2.nextIndex = h1.index;
            }
            HEFace newFace = new HEFace
            {
                heIndex = h0.index,
                normal  = planeNormal
            };
            short faceIdx = (short)faces.Count;
            h0.faceIndex = faceIdx;
            h1.faceIndex = faceIdx;
            h2.faceIndex = faceIdx;
            halfEdges.Add(h0);
            halfEdges.Add(h1);
            halfEdges.Add(h2);
            faces.Add(newFace);
        }
    }
Exemplo n.º 5
0
        /**
         * Splits a vertex in two along a plane. Returns true if the vertex can be split, false otherwise. Does not create new border
         * edges inside the tear in order to prevent non-manifold vertices emerging, so it is only suitable for realtime cloth tearing.
         * \param vertex the vertex to split.
         * \param splitPlane plane to split the vertex at.
         * \param newVertex the newly created vertex after the split operation has been performed.
         * \param vertices new mesh vertices list after the split operation.
         * \param removedEdges list of edge ids removed after splitting the vertex.
         * \param addedEdges list of edge ids added after splitting the vertex.
         * \param oldAndNewEdges a dictionary relating old and new edge ids.
         */
        public bool SplitVertex(HEVertex vertex, Plane splitPlane, out HEVertex newVertex, out Vector3[] vertices, out HashSet<int> removedEdges, out HashSet<int> addedEdges, out Dictionary<int,int> oldAndNewEdges)
        {
            // initialize return values:
            removedEdges = new HashSet<int>();
            addedEdges = new HashSet<int>();
            oldAndNewEdges = new Dictionary<int,int>();
            newVertex = null;

            // initialize face lists for each side of the split plane.
            List<HEFace> side1Faces = new List<HEFace>();
            List<HEFace> side2Faces = new List<HEFace>();
            HashSet<int> side2Edges = new HashSet<int>();

            // Get a copy of mesh vertices:
            vertices = input.vertices;

            // classify adjacent faces depending on which side of the cut plane they reside in:
            foreach(HEFace face in GetNeighbourFacesEnumerator(vertex)){

            int v1 = heEdges[face.edges[0]].startVertex;
            int v2 = heEdges[face.edges[1]].startVertex;
            int v3 = heEdges[face.edges[2]].startVertex;

            //Skip this face if it doesnt contain the splitted vertex.
            if (v1 != vertex.index && v2 != vertex.index && v3 != vertex.index) continue;

            Vector3 faceCenter = (vertices[heVertices[v1].physicalIDs[0]] +
                                  vertices[heVertices[v2].physicalIDs[0]] +
                                  vertices[heVertices[v3].physicalIDs[0]]) / 3.0f;

            if (splitPlane.GetSide(faceCenter)){
                side1Faces.Add(face);
            }else{
                side2Faces.Add(face);
                foreach(int e in face.edges)
                    side2Edges.Add(e);
            }
            }

            // If the vertex cant be split, return false.
            if (side1Faces.Count == 0 || side2Faces.Count == 0) return false;

            // create new mesh vertex and triangle buffers:
            vertices = new Vector3[input.vertexCount+1];
            Array.Copy(input.vertices,vertices,input.vertexCount);

            int[] triangles = input.triangles;

            // create a new vertex:
            newVertex = new HEVertex(input.vertexCount);
            newVertex.index = heVertices.Count;
            heVertices.Add(newVertex);

            // add the new vertex to the mesh vertices buffer:
            vertices[input.vertexCount] = vertices[vertex.physicalIDs[0]];

            // Copy uvs, colors and other mesh info.
            Vector2[] uv = null;
            Vector2[] uv2 = null;
            Vector2[] uv3 = null;
            Vector2[] uv4 = null;
            Color32[] colors = null;
            if (input.uv.Length > 0){
            uv = new Vector2[input.uv.Length+1];
            Array.Copy(input.uv,uv,input.uv.Length);
            uv[input.uv.Length] = uv[vertex.physicalIDs[0]]; //TODO: could cause copying uvs from the other side of the cut...
            }
            if (input.uv2.Length > 0){
            uv2 = new Vector2[input.uv2.Length+1];
            Array.Copy(input.uv2,uv2,input.uv2.Length);
            uv2[input.uv2.Length] = uv2[vertex.physicalIDs[0]];
            }
            if (input.uv3.Length > 0){
            uv3 = new Vector2[input.uv3.Length+1];
            Array.Copy(input.uv3,uv3,input.uv3.Length);
            uv3[input.uv3.Length] = uv3[vertex.physicalIDs[0]];
            }
            if (input.uv4.Length > 0){
            uv4 = new Vector2[input.uv4.Length+1];
            Array.Copy(input.uv4,uv4,input.uv4.Length);
            uv4[input.uv4.Length] = uv4[vertex.physicalIDs[0]];
            }
            if (input.colors32.Length > 0){
            colors = new Color32[input.colors32.Length+1];
            Array.Copy(input.colors32,colors,input.colors32.Length);
            colors[input.colors32.Length] = colors[vertex.physicalIDs[0]];
            }

            // rearrange edges at side 1:
            foreach(HEFace face in side1Faces){

            // find half edges that start or end at the split vertex:
            HEEdge edgeIn = heEdges[Array.Find<int>(face.edges,e => heEdges[e].endVertex == vertex.index)];
            HEEdge edgeOut = heEdges[Array.Find<int>(face.edges,e => heEdges[e].startVertex == vertex.index)];

            int oldInID = ObiUtils.Pair(edgeIn.startVertex,edgeIn.endVertex);
            int oldOutID = ObiUtils.Pair(edgeOut.startVertex,edgeOut.endVertex);

            if (ShouldRemoveEdge(edgeIn,side2Edges.Contains(edgeIn.pair)))
                removedEdges.Add(oldInID);

            if (ShouldRemoveEdge(edgeOut,side2Edges.Contains(edgeOut.pair)))
                removedEdges.Add(oldOutID);

            // stitch half edges to new vertex
            edgeIn.endVertex = newVertex.index;
            edgeOut.startVertex = newVertex.index;

            newVertex.halfEdgeIndex = edgeOut.index;

            int newInID = ObiUtils.Pair(edgeIn.startVertex,edgeIn.endVertex);
            int newOutID = ObiUtils.Pair(edgeOut.startVertex,edgeOut.endVertex);

            addedEdges.Add(newInID);
            addedEdges.Add(newOutID);

            if (!oldAndNewEdges.ContainsKey(newInID))
            oldAndNewEdges.Add(newInID,oldInID);
            if (!oldAndNewEdges.ContainsKey(newOutID))
            oldAndNewEdges.Add(newOutID,oldOutID);

            // update mesh triangle buffer to point at new vertex where needed:
            if (triangles[face.index*3] == vertex.physicalIDs[0]) triangles[face.index*3] = newVertex.physicalIDs[0];
            if (triangles[face.index*3+1] == vertex.physicalIDs[0]) triangles[face.index*3+1] = newVertex.physicalIDs[0];
            if (triangles[face.index*3+2] == vertex.physicalIDs[0]) triangles[face.index*3+2] = newVertex.physicalIDs[0];

            }

            // update input mesh:
            input.vertices = vertices;
            input.triangles = triangles;
            if (uv != null)
            input.uv = uv;
            if (uv2 != null)
            input.uv2 = uv2;
            if (uv3 != null)
            input.uv3 = uv3;
            if (uv4 != null)
            input.uv4 = uv4;
            if (colors != null)
            input.colors32 = colors;

            _closed = false;
            _modified = true;

            return true;
        }
Exemplo n.º 6
0
        public IEnumerable<HEVertex> GetNeighbourVerticesEnumerator(HEVertex vertex)
        {
            HEEdge startEdge = heEdges[vertex.halfEdgeIndex];
            HEEdge edge = startEdge;

            do{
            edge = heEdges[edge.pair];
            yield return heVertices[edge.startVertex];
            edge = heEdges[edge.nextEdgeIndex];

            } while (edge != startEdge);
        }
Exemplo n.º 7
0
        public IEnumerable<HEFace> GetNeighbourFacesEnumerator(HEVertex vertex)
        {
            HEEdge startEdge = heEdges[vertex.halfEdgeIndex];
            HEEdge edge = startEdge;

            do{

            edge = heEdges[edge.pair];
            if (edge.faceIndex > -1)
                yield return heFaces[edge.faceIndex];
            edge = heEdges[edge.nextEdgeIndex];

            } while (edge != startEdge);
        }
Exemplo n.º 8
0
        /**
         * Analyzes the input mesh and populates the half-edge structure. Can be called as many times you want (for examples if the original mesh is modified).
         */
        public IEnumerator Generate()
        {
            if (input != null){

            heFaces.Clear();
            heVertices.Clear();
            heEdges.Clear();
            _area = 0;
            _modified = false;

            Dictionary<Vector3, HEVertex> vertexBuffer = new Dictionary<Vector3, HEVertex>();
            Dictionary<KeyValuePair<int,int>,HEEdge> edgeBuffer = new Dictionary<KeyValuePair<int,int>,HEEdge>();

            // Get copies of vertex and triangle buffers:
            Vector3[] vertices = input.vertices;
            int[] triangles = input.triangles;

            // first, create vertices:
            for(int i = 0; i < vertices.Length; i++){

                //if the vertex already exists, add physical vertex index to it.
                HEVertex vertex;
                if (vertexBuffer.TryGetValue(vertices[i], out vertex)){
                    vertex.physicalIDs.Add(i);
                }else{
                    vertex = new HEVertex(i);
                }

                vertexBuffer[vertices[i]] = vertex;

                if (i % 200 == 0)
                    yield return new CoroutineJob.ProgressInfo("Half-edge: analyzing vertices...",i/(float)vertices.Length);
            }

            // assign unique indices to vertices:
            int index = 0;
            foreach(KeyValuePair<Vector3,HEVertex> pair in vertexBuffer){
                ((HEVertex)pair.Value).index = index;
                heVertices.Add(pair.Value);
                if (index % 200 == 0)
                    yield return new CoroutineJob.ProgressInfo("Half-edge: assigning indices...",index/(float)vertices.Length);
                index++;
            }

            // build half edge structure:
            for(int i = 0; i<triangles.Length;i+=3){

                Vector3 pos1 = vertices[triangles[i]];
                Vector3 pos2 = vertices[triangles[i+1]];
                Vector3 pos3 = vertices[triangles[i+2]];

                HEVertex v1 = vertexBuffer[pos1];
                HEVertex v2 = vertexBuffer[pos2];
                HEVertex v3 = vertexBuffer[pos3];

                // create half edges:
                HEEdge e1 = new HEEdge();
                e1.index = heEdges.Count;
                e1.indexOnFace = 0;
                e1.faceIndex = heFaces.Count;
                e1.endVertex = v1.index;
                e1.startVertex = v2.index;

                HEEdge e2 = new HEEdge();
                e2.index = heEdges.Count+1;
                e2.indexOnFace = 1;
                e2.faceIndex = heFaces.Count;
                e2.endVertex = v2.index;
                e2.startVertex = v3.index;

                HEEdge e3 = new HEEdge();
                e3.index = heEdges.Count+2;
                e3.indexOnFace = 2;
                e3.faceIndex = heFaces.Count;
                e3.endVertex = v3.index;
                e3.startVertex = v1.index;

                // link half edges together:
                e1.nextEdgeIndex = e3.index;
                e2.nextEdgeIndex = e1.index;
                e3.nextEdgeIndex = e2.index;

                // vertex outgoing half edge indices:
                v1.halfEdgeIndex = e3.index;
                v2.halfEdgeIndex = e1.index;
                v3.halfEdgeIndex = e2.index;

                // add edges:
                heEdges.Add(e1);
                heEdges.Add(e2);
                heEdges.Add(e3);

                // populate and add face:
                HEFace face = new HEFace();
                face.edges[0] = e1.index;
                face.edges[1] = e2.index;
                face.edges[2] = e3.index;
                face.area = ObiUtils.TriangleArea(pos1,pos2,pos3);
                _area += face.area;
                _volume += Vector3.Dot(Vector3.Cross(pos1,pos2),pos3)/6f;
                face.index = heFaces.Count;
                heFaces.Add(face);

                try{
                    edgeBuffer.Add(new KeyValuePair<int,int>(v1.index,v2.index),e1);
                    edgeBuffer.Add(new KeyValuePair<int,int>(v2.index,v3.index),e2);
                    edgeBuffer.Add(new KeyValuePair<int,int>(v3.index,v1.index),e3);
                }catch{
                    Debug.LogError("Your mesh is non manifold, and thus cannot be processed by Obi: more than 1 edge joining the same pair of vertices.");
                    heFaces.Clear();
                    heVertices.Clear();
                    heEdges.Clear();
                    _area = 0;
                    yield break;
                }

                if (i % 500 == 0)
                    yield return new CoroutineJob.ProgressInfo("Half-edge: generating edges and faces...",i/(float)triangles.Length);

            }

            List<HEEdge> borderEdges = new List<HEEdge>();		//edges belonging to a mesh border.

            // stitch half edge pairs together:
            index = 0;
            foreach(KeyValuePair<KeyValuePair<int,int>,HEEdge> pair in edgeBuffer){

                KeyValuePair<int,int> edgeKey = new KeyValuePair<int,int>(pair.Key.Value,pair.Key.Key);

                HEEdge edge = null;
                if (edgeBuffer.TryGetValue(edgeKey, out edge)){
                    ((HEEdge)pair.Value).pair = edge.index;
                }else{

                    //create border edge:
                    HEEdge e = new HEEdge();
                    e.index = heEdges.Count;
                    e.endVertex = ((HEEdge)pair.Value).startVertex;
                    e.startVertex = ((HEEdge)pair.Value).endVertex;
                    heVertices[e.startVertex].halfEdgeIndex = e.index;
                    e.pair = ((HEEdge)pair.Value).index;
                    ((HEEdge)pair.Value).pair = e.index;
                    heEdges.Add(e);

                    borderEdges.Add(e);
                }

                if (index % 1000 == 0)
                    yield return new CoroutineJob.ProgressInfo("Half-edge: stitching half-edges...",index/(float)edgeBuffer.Count);

                index++;

            }

            _closed = borderEdges.Count == 0;

            // link together border edges:
            foreach(HEEdge edge in borderEdges){
                edge.nextEdgeIndex = heVertices[edge.endVertex].halfEdgeIndex;
            }

            }else{
            Debug.LogWarning("Tried to generate adjacency info for an empty mesh.");
            }
        }
Exemplo n.º 9
0
        public bool AreLinked(HEVertex v1, HEVertex v2)
        {
            HEEdge startEdge = heEdges[v1.halfEdgeIndex];
            HEEdge edge = startEdge;

            do{
            edge = heEdges[edge.pair];
            if (edge.startVertex == v2.index)
                return true;
            edge = heEdges[edge.nextEdgeIndex];

            } while (edge != startEdge);

            return false;
        }