Beispiel #1
0
        // What this basically does is search for common faces in the two linkedFaces lists
        // It uses & destroys face marks
        public void CollectVertexPairFaces(VertexPair pair, IndexList commonFaces)
        {
            IndexList il0 = vertices[pair.v[0]].linkedFaces;             // surrounding faces
            IndexList il1 = vertices[pair.v[1]].linkedFaces;             // surrounding faces

            int[] v0Faces = il0.array;
            int[] v1Faces = il1.array;
            int   v0Count = il0.Count;
            int   v1Count = il1.Count;
            int   tag     = GetUniqueTag();

            commonFaces.GrowToCapacity(v1Count);
            for (int i = 0; i < v0Count; ++i)
            {
                faces[v0Faces[i]].mark = tag;
            }
            for (int i = 0; i < v1Count; ++i)
            {
                int faceIndex = v1Faces[i];
                if (faces[faceIndex].mark == tag)
                {
                    commonFaces.AddUnsafe(faceIndex);
                }
            }
        }
Beispiel #2
0
        // VERTEXPAIRS //

        public bool isVertexPairValid(VertexPair vp)
        {
            if (vp.v[0] == vp.v[1])
            {
                return(false);
            }
            if (IsVertexValid(vp.v[0]) == false)
            {
                return(false);
            }
            if (IsVertexValid(vp.v[1]) == false)
            {
                return(false);
            }
            return(true);
        }
Beispiel #3
0
        public void CollectCollapseFacesForVertexPair(VertexPair pair, IndexList changeFaces0, IndexList changeFaces1, IndexList commonFaces)
        {
            IndexList il0 = vertices[pair.v[0]].linkedFaces;
            IndexList il1 = vertices[pair.v[1]].linkedFaces;

            int[] v0Faces = il0.array;
            int[] v1Faces = il1.array;
            int   v0Count = il0.Count;
            int   v1Count = il1.Count;
            int   tag     = GetUniqueTag();

            // Grow target lists to save on checks later
            changeFaces0.GrowToCapacity(v0Count);
            changeFaces1.GrowToCapacity(v1Count);
            commonFaces.GrowToCapacity(v0Count);             // could be min(v0count, v1count), but that's probably slower

            for (int i = 0; i < v1Count; ++i)
            {
                faces[v1Faces[i]].mark = tag;
            }
            for (int i = 0; i < v0Count; ++i)
            {
                int  faceIndex = v0Faces[i];
                Face f         = faces[faceIndex];
                //	if (f.valid) {
                if (f.mark == tag)
                {
                    commonFaces.AddUnsafe(faceIndex);
                    f.mark = 0;
                }
                else
                {
                    changeFaces0.AddUnsafe(faceIndex);
                }
                //	}
            }
            for (int i = 0; i < v1Count; ++i)
            {
                int  faceIndex = v1Faces[i];
                Face f         = faces[faceIndex];
                if (/*f.valid &&*/ f.mark == tag)
                {
                    changeFaces1.AddUnsafe(faceIndex);
                }
            }
        }
Beispiel #4
0
        // REQUIRES triangulated mesh!
        public int CollapseVertexPair(CollapseInfo info)
        {
            if (topology != MeshTopology.Triangles)
            {
                Debug.LogError("KrablMesh: Collapsing a vertex pair requires a triangle mesh");
                return(0);
            }

            VertexPair pair = info.vp;
            int        vindex0 = pair.v[0];
            int        vindex1 = pair.v[1];
            Vertex     vertex0 = vertices[vindex0];
            Vertex     vertex1 = vertices[vindex1];
            int        i, j;

            changeFaces0.Clear();
            changeFaces1.Clear();
            removeFaces.Clear();
            CollectCollapseFacesForVertexPair(pair, changeFaces0, changeFaces1, removeFaces);

            // Adjust parameters of vertex0 to the new position
            float ratio1 = info.Ratio(this);

            // try baricentric projection on all the removeFaces (usually 2)
            int     projFaceIndex = -1;
            Face    projFace = null;
            int     projCorner0 = 0, projCorner1 = 0;
            Vector3 bari = Vector3.zero;

            int[] v = null;
            for (i = 0; i < removeFaces.Count; ++i)
            {
                Face f = faces[removeFaces[i]];
                v    = f.v;
                bari = UnityUtils.BaricentricProjection(info.targetPosition, vertices[v[0]].coords, vertices[v[1]].coords, vertices[v[2]].coords);
                if (UnityUtils.AreBaricentricCoordsInsideTriangle(bari))
                {
                    projFaceIndex = removeFaces[i];
                    projFace      = f;
                    projCorner0   = projFace.CornerIndexTriangle(vindex0);
                    projCorner1   = projFace.CornerIndexTriangle(vindex1);
                    break;
                }
            }
            // There must not be invalid faces in changeFaces0 or changeFaces1 !!!

            /*	for (i = 0; i < changeFaces0.Count; ++i) if (faces[changeFaces0[i]].valid == false) Debug.LogError("NOOO!");
             *      for (i = 0; i < changeFaces1.Count; ++i) if (faces[changeFaces1[i]].valid == false) Debug.LogError("NOOO!");
             *      for (i = 0; i < removeFaces.Count; ++i) if (faces[removeFaces[i]].valid == false) Debug.LogError("NOOO!");
             */
            // Deal with vertex colors and boneweights. these are per vertex.
            if (projFace != null)
            {
                if (hasVertexColors)
                {
                    vertex0.color = bari.x * vertices[v[0]].color + bari.y * vertices[v[1]].color + bari.z * vertices[v[2]].color;
                }
                if (hasBoneWeights)
                {
                    vertex0.boneWeight = UnityUtils.BoneWeightBaricentricInterpolation(vertices[v[0]].boneWeight, vertices[v[1]].boneWeight, vertices[v[2]].boneWeight, bari.x, bari.y, bari.z);
                }
            }
            else
            {
                if (hasVertexColors)
                {
                    vertex0.color = Color.Lerp(vertex0.color, vertex1.color, ratio1);
                }
                if (hasBoneWeights)
                {
                    vertex0.boneWeight = UnityUtils.BoneWeightLerp(vertex0.boneWeight, vertex1.boneWeight, ratio1);
                }
            }

            // Determine corner numbers for v0 in changefaces0 and v1 in changefaces1
            IndexList corners0 = new IndexList(changeFaces0.Count);

            for (i = 0; i < changeFaces0.Count; ++i)
            {
                corners0[i] = faces[changeFaces0[i]].CornerIndexTriangle(vindex0);
            }
            IndexList corners1 = new IndexList(changeFaces1.Count);

            for (i = 0; i < changeFaces1.Count; ++i)
            {
                corners1[i] = faces[changeFaces1[i]].CornerIndexTriangle(vindex1);
            }

            #region Face-Dependent Attributes (Vertex normals, uv1, uv2)

            // NORMALS
            int     count = 0, filterTag = GetUniqueTag();
            Vector3 projNormalNew = Vector3.zero;
            if (projFace != null)
            {
                projNormalNew = bari.x * projFace.vertexNormal[0] + bari.y * projFace.vertexNormal[1] + bari.z * projFace.vertexNormal[2];
                count         = _replaceCornerNormalInFaceGroup(projFace.vertexNormal[projCorner0], projNormalNew, changeFaces0, corners0, filterTag);
            }
            if (count < changeFaces0.Count)
            {
                // there are faces which cannot use baricentric projection
                for (j = 0; j < removeFaces.Count; ++j)
                {
                    if (removeFaces[j] != projFaceIndex)
                    {
                        Face    f2 = faces[removeFaces[j]]; int c0 = f2.CornerIndexTriangle(vindex0), c1 = f2.CornerIndexTriangle(vindex1);
                        Vector3 oldNormal = f2.vertexNormal[c0];
                        _replaceCornerNormalInFaceGroup(oldNormal, Vector3.Lerp(oldNormal, f2.vertexNormal[c1], ratio1), changeFaces0, corners0, filterTag);
                    }
                }
            }

            count = 0; filterTag = GetUniqueTag();
            if (projFace != null)
            {
                count = _replaceCornerNormalInFaceGroup(projFace.vertexNormal[projCorner1], projNormalNew, changeFaces1, corners1, filterTag);
            }
            if (count < changeFaces1.Count)
            {
                // there are faces which cannot use baricentric projection
                for (j = 0; j < removeFaces.Count; ++j)
                {
                    if (removeFaces[j] != projFaceIndex)
                    {
                        Face    f2 = faces[removeFaces[j]]; int c0 = f2.CornerIndexTriangle(vindex0), c1 = f2.CornerIndexTriangle(vindex1);
                        Vector3 oldNormal = f2.vertexNormal[c1];
                        _replaceCornerNormalInFaceGroup(oldNormal, Vector3.Lerp(f2.vertexNormal[c0], oldNormal, ratio1), changeFaces1, corners1, filterTag);
                    }
                }
            }

            if (hasUV1)
            {
                count = 0; filterTag = GetUniqueTag();
                Vector2 projUV1New = Vector2.zero;
                if (projFace != null)
                {
                    projUV1New = bari.x * projFace.uv1[0] + bari.y * projFace.uv1[1] + bari.z * projFace.uv1[2];
                    count      = _replaceCornerUV1InFaceGroup(projFace.uv1[projCorner0], projUV1New, changeFaces0, corners0, filterTag);
                }
                if (count < changeFaces0.Count)
                {
                    // there are faces which cannot use baricentric projection
                    for (j = 0; j < removeFaces.Count; ++j)
                    {
                        if (removeFaces[j] != projFaceIndex)
                        {
                            Face    f2 = faces[removeFaces[j]]; int c0 = f2.CornerIndexTriangle(vindex0), c1 = f2.CornerIndexTriangle(vindex1);
                            Vector2 oldUV1 = f2.uv1[c0];
                            _replaceCornerUV1InFaceGroup(oldUV1, Vector2.Lerp(oldUV1, f2.uv1[c1], ratio1), changeFaces0, corners0, filterTag);
                        }
                    }
                }

                count = 0; filterTag = GetUniqueTag();
                if (projFace != null)
                {
                    count = _replaceCornerUV1InFaceGroup(projFace.uv1[projCorner1], projUV1New, changeFaces1, corners1, filterTag);
                }
                if (count < changeFaces1.Count)
                {
                    // there are faces which cannot use baricentric projection
                    for (j = 0; j < removeFaces.Count; ++j)
                    {
                        if (removeFaces[j] != projFaceIndex)
                        {
                            Face    f2 = faces[removeFaces[j]]; int c0 = f2.CornerIndexTriangle(vindex0), c1 = f2.CornerIndexTriangle(vindex1);
                            Vector2 oldUV1 = f2.uv1[c1];
                            _replaceCornerUV1InFaceGroup(oldUV1, Vector2.Lerp(f2.uv1[c0], oldUV1, ratio1), changeFaces1, corners1, filterTag);
                        }
                    }
                }
            }

            if (hasUV2)
            {
                count = 0; filterTag = GetUniqueTag();
                Vector2 projUV2New = Vector2.zero;
                if (projFace != null)
                {
                    projUV2New = bari.x * projFace.uv2[0] + bari.y * projFace.uv2[1] + bari.z * projFace.uv2[2];
                    count      = _replaceCornerUV2InFaceGroup(projFace.uv2[projCorner0], projUV2New, changeFaces0, corners0, filterTag);
                }
                if (count < changeFaces0.Count)
                {
                    // there are faces which cannot use baricentric projection
                    for (j = 0; j < removeFaces.Count; ++j)
                    {
                        if (removeFaces[j] != projFaceIndex)
                        {
                            Face    f2 = faces[removeFaces[j]]; int c0 = f2.CornerIndexTriangle(vindex0), c1 = f2.CornerIndexTriangle(vindex1);
                            Vector2 oldUV2 = f2.uv2[c0];
                            _replaceCornerUV2InFaceGroup(oldUV2, Vector2.Lerp(oldUV2, f2.uv2[c1], ratio1), changeFaces0, corners0, filterTag);
                        }
                    }
                }

                count = 0; filterTag = GetUniqueTag();
                if (projFace != null)
                {
                    count = _replaceCornerUV2InFaceGroup(projFace.uv2[projCorner1], projUV2New, changeFaces1, corners1, filterTag);
                }
                if (count < changeFaces1.Count)
                {
                    // there are faces which cannot use baricentric projection
                    for (j = 0; j < removeFaces.Count; ++j)
                    {
                        if (removeFaces[j] != projFaceIndex)
                        {
                            Face    f2 = faces[removeFaces[j]]; int c0 = f2.CornerIndexTriangle(vindex0), c1 = f2.CornerIndexTriangle(vindex1);
                            Vector2 oldUV2 = f2.uv2[c1];
                            _replaceCornerUV2InFaceGroup(oldUV2, Vector2.Lerp(f2.uv2[c0], oldUV2, ratio1), changeFaces1, corners1, filterTag);
                        }
                    }
                }
            }
            #endregion
            // Move vertex to goal position
            vertex0.coords = info.targetPosition;

            // remove faces
            //	Debug.Log("Change faces 1 num: " + changeFaces0.Count);
            //	Debug.Log("Change faces 2 num: " + changeFaces1.Count);
            //	Debug.Log("Remove faces num: " + removeFaces.Count);
            for (i = 0; i < removeFaces.Count; ++i)
            {
                UnlinkFace(removeFaces[i]);
            }

            // change vertex on vindex1 faces, update surrounding faces on vindex0
            for (i = 0; i < changeFaces1.Count; ++i)
            {
                int  faceIndex = changeFaces1[i];
                Face f         = faces[faceIndex];
                if (f.valid)
                {
                    f.ReplaceVertex(vindex1, vindex0);
                    vertex0.linkedFaces.Add(faceIndex);
                }
            }

            // mark vindex1 as invalid
            vertex1.linkedFaces.Clear();
            if (vertex1.valid == true)
            {
                numValidVerts--;
                vertex1.valid = false;
            }
            else
            {
                Debug.LogError("vindex1 was already invalid");
            }
            return(vindex0);
        }
Beispiel #5
0
 public Vector3 CalculateVertexPairCenter(VertexPair vp)
 {
     return(0.5f * (vertices[vp.v[0]].coords + vertices[vp.v[1]].coords));
 }
Beispiel #6
0
        public int Collapse(int numEdgesToCollapse = 1, float maxCost = 1e6f)
        {
            int collapsesDone = 0;

            while (numEdgesToCollapse > 0)
            {
                HeapNode <CollapseInfo> node;
                do
                {
                    node = heap.Extract();
                } while (node != null && mesh.isVertexPairValid(node.obj.vp) == false);
                if (node == null)
                {
                    break;
                }

                if (node.heapValue > maxCost)
                {
                    break;
                }

                CollapseInfo cinfo = node.obj;
                VertexPair   vp    = cinfo.vp;
                // Add the error terms .. v[0] is the vertex that survives the collapse
                pdePerVertex[vp.v[0]].OpAdd(pdePerVertex[vp.v[1]]);

                // DO THE COLLAPSE
                int vindex = mesh.CollapseVertexPair(cinfo);                 // vindex is the surviving vertex index

                // Need to update the cost of all edges around all linked faces of vindex
                // these are the edges connected to vindex + all the edges connected to vindex neighbours
                _edgesToUpdate.Clear();
                _surroundingVerts.Clear();

                mesh.CollectVerticesAroundVertex(vindex, ref _surroundingVerts);

                // TODO: do this better -> why?
                int mark = mesh.GetUniqueTag();
                for (int i = 0; i < _surroundingVerts.Count; ++i)
                {
                    List <int> lEdges = mesh.linkedEdgesForVert(_surroundingVerts[i]);
                    for (int j = 0; j < lEdges.Count; ++j)
                    {
                        int  edgeIndex = lEdges[j];
                        Edge e         = mesh.edges[edgeIndex];
                        if (e.mark != mark)
                        {
                            e.mark = mark;
                            if (mesh.IsEdgeValid(edgeIndex))
                            {
                                _edgesToUpdate.Add(edgeIndex);
                            }
                        }
                    }
                }

                // DO the update
                for (int i = 0; i < _edgesToUpdate.Count; ++i)
                {
                    int edgeIndex = _edgesToUpdate[i];
                    HeapNode <CollapseInfo> hnode = heapNodes[edgeIndex];
                    if (mesh.edges[edgeIndex].ContainsVertex(vindex))
                    {
                        _calculateEdgeCost(edgeIndex, hnode.obj);
                    }
                    else
                    {
                        _updateEdgePenalties(edgeIndex, hnode.obj, vindex);
                    }
                    heap.Update(hnode, hnode.obj.cost);
                }

                numEdgesToCollapse--;
                collapsesDone++;
            }
            return(collapsesDone);
        }
Beispiel #7
0
        public new int CollapseVertexPair(CollapseInfo info)
        {
            VertexPair pair    = info.vp;
            int        v0      = pair.v[0];
            int        v1      = pair.v[1];
            List <int> v0Edges = linkedEdges[v0];
            List <int> v1Edges = linkedEdges[v1];
            int        i;

            // Update edges
            // Mark the vertices that are connected by edges
            for (i = 0; i < v1Edges.Count; ++i)
            {
                int edgeIndex = v1Edges[i];
                int other     = edges[edgeIndex].OtherVertex(v1);
                vertices[other].mark = -1;
            }
            for (i = 0; i < v0Edges.Count; ++i)
            {
                int edgeIndex = v0Edges[i];
                int other     = edges[edgeIndex].OtherVertex(v0);
                vertices[other].mark = edgeIndex;
            }
            // now v1 verts that are only connected to v1 have value -1, double edge-connected verts have the edgeindex as mark
            for (i = 0; i < v1Edges.Count; ++i)
            {
                int edgeIndex = v1Edges[i];
                if (vertices[edges[edgeIndex].OtherVertex(v1)].mark == -1)
                {
                    edges[edgeIndex].ReplaceVertex(v1, v0);
                    if (IsEdgeValid(edgeIndex))
                    {
                        v0Edges.Add(edgeIndex);
                    }
                }
                else
                {
                    Edge e1     = edges[edgeIndex];
                    int  vindex = e1.OtherVertex(v1);
                    Edge e0     = edges[vertices[vindex].mark];  // vertex mark is edge index!
                    // There has to be another edge connecting v0 to vertex vindex
                    e0.crease = Mathf.Max(e1.crease, e0.crease); // keep the max crease value
                    UnlinkEdge(edgeIndex);                       // no more need for this!
                }
            }
            // Remove invalid edges from mesh
            for (i = v0Edges.Count - 1; i >= 0; --i)               // backwards should be faster and i stays valid!
            {
                int edgeIndex = v0Edges[i];
                if (IsEdgeValid(edgeIndex) == false)
                {
                    UnlinkEdge(edgeIndex);
                    //v0Edges.Remove(edgeIndex);
                }
            }

            // Deal with vertices and faces in baseclass
            info.vp = new VertexPair(v0, v1);             // the original might have been invalidated THIS IS BAD
            base.CollapseVertexPair(info);
            v1Edges.Clear();

            // rebuild linkedfaces for the remaining edges
            for (i = 0; i < v0Edges.Count; ++i)
            {
                Edge edge = edges[v0Edges[i]];
                edge.linkedFaces.Clear();
                CollectVertexPairFaces(edge, edge.linkedFaces);
            }

            return(v0);
        }