예제 #1
0
        public Vector3 CalculateFaceNormal(int faceIndex)
        {
            int  i;
            Face face      = faces[faceIndex];
            int  vertCount = face.cornerCount;

            int[]     vindex = face.v;
            Vector3[] vec    = new Vector3[vertCount + 1];

            for (i = 0; i < vertCount - 1; ++i)
            {
                vec[i] = vertices[vindex[i + 1]].coords - vertices[vindex[i]].coords;
            }
            vec[i] = vertices[vindex[0]].coords - vertices[vindex[i]].coords;
            Vector3 normal = Vector3.zero;

            if (vertCount == 3)
            {
                normal = Vector3.Cross(vec[0], vec[1]);
            }
            else
            {
                // Sum normals based on consequtive pairs of edges
                vec[vertCount] = vec[0];
                for (i = 0; i < vertCount; ++i)
                {
                    normal += Vector3.Cross(vec[i], vec[i + 1]);
                }
            }
            UnityUtils.NormalizeSmallVector(ref normal);
            face.normal = normal;
            return(face.normal);
        }
예제 #2
0
        void _determinePdeToConstrainEdge(Edge edge, float weight, ref PlaneDistanceError pde)
        {
            int vi0 = edge.v[0];
            int vi1 = edge.v[1];

            Vector3 v0    = mesh.vertices[vi0].coords;
            Vector3 vEdge = mesh.vertices[vi1].coords - v0;
            Vector3 edgeNormal;

            pde.Clear();
            float mag = vEdge.sqrMagnitude;

            for (int i = 0; i < edge.linkedFaces.Count; ++i)
            {
                edgeNormal = mesh.faces[edge.linkedFaces[i]].normal;

                Vector3 n = Vector3.Cross(vEdge, edgeNormal);                 // normal to edge and face
                UnityUtils.NormalizeSmallVector(ref n);

                float d = -Vector3.Dot(n, v0);
                pde2.Set(n.x, n.y, n.z, d, mag);
                // Multiply by face area (factor) for weighting
                pde2.OpMul(pde2.Factor() * weight * 0.5f);
                pde.OpAdd(pde2);
            }
        }
예제 #3
0
        public Vector3 CalculateVertexNormal(int vertexIndex)
        {
            Vertex    vert        = vertices[vertexIndex];
            Vector3   n           = Vector3.zero;
            IndexList linkedFaces = vert.linkedFaces;
            int       num         = linkedFaces.Count;

            for (int i = 0; i < num; ++i)
            {
                int faceIndex = linkedFaces[i];
                n += faces[faceIndex].normal;
            }
            UnityUtils.NormalizeSmallVector(ref n);
            vert.normal = n;
            return(n);
        }
예제 #4
0
        int _replaceCornerUV2InFaceGroup(Vector2 oldUV2, Vector2 newUV2, IndexList faceList, IndexList corners, int filterTag)
        {
            int count = 0;

            for (int i = 0; i < faceList.Count; ++i)
            {
                Face f = faces[faceList[i]];
                if (f.mark == filterTag)
                {
                    continue;
                }
                if (UnityUtils.Vector2CompareWithTolerance(f.uv2[corners[i]], oldUV2, equalityTolerance) == 0)
                {
                    f.uv2[corners[i]] = newUV2;
                    f.mark            = filterTag;
                    count++;
                }
            }
            return(count);
        }
예제 #5
0
        int _replaceCornerNormalInFaceGroup(Vector3 oldNormal, Vector3 newNormal, IndexList faceList, IndexList corners, int filterTag)
        {
            int count = 0;

            for (int i = 0; i < faceList.Count; ++i)
            {
                Face f = faces[faceList[i]];
                if (f.mark == filterTag)
                {
                    continue;
                }
                if (UnityUtils.Vector3CompareWithTolerance(f.vertexNormal[corners[i]], oldNormal, equalityTolerance) == 0)
                {
                    f.vertexNormal[corners[i]] = newNormal;
                    f.mark = filterTag;
                    count++;
                }
            }
            return(count);
        }
예제 #6
0
        public static int CompareEV(ExportVertex a, ExportVertex b)
        {
            int res = UnityUtils.Vector3Compare(a.coords, b.coords);

            if (res != 0)
            {
                return(res);
            }
            res = UnityUtils.Vector3Compare(a.normal, b.normal);
            if (res != 0)
            {
                return(res);
            }
            res = UnityUtils.Vector2Compare(a.uv1, b.uv1);
            if (res != 0)
            {
                return(res);
            }
            res = UnityUtils.Vector2Compare(a.uv2, b.uv2);
            return(res);
        }
예제 #7
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);
        }
예제 #8
0
        void _updateEdgePenalties(int edgeIndex, CollapseInfo cinfo, int movedVertexIndex = -1)
        {
            Edge   edge    = mesh.edges[edgeIndex];
            int    vindex0 = edge.v[0];
            int    vindex1 = edge.v[1];
            Vertex v0      = mesh.vertices[vindex0];
            Vertex v1      = mesh.vertices[vindex1];

            faces0.Clear();
            faces1.Clear();
            commonFaces.Clear();

            bool hadPenalty = (cinfo.cost >= kMeshPenaltyMaxEdgesPerVertex);

            cinfo.cost = cinfo.positionCost;             // reset cost
            // determine the faces involved in the collapse ..
            mesh.CollectCollapseFacesForVertexPair(mesh.edges[edgeIndex], faces0, faces1, commonFaces);

            // Penalties

            int filterTag = 0;

            if (_parameters.preventNonManifoldEdges && _producesNonManifold(mesh, cinfo))
            {
                cinfo.cost += kMeshPenaltyNonManifold;                 // largest penalty first
            }
            else
            {
                if (movedVertexIndex != -1 && hadPenalty == false)
                {
                    // For cinfos that are not new and had no penalty before, all faces besides the onces connected
                    // to the moved vertex can be skipped.
                    filterTag = mesh.GetUniqueTag();
                    IndexList linkedFaces = mesh.vertices[movedVertexIndex].linkedFaces;
                    int       count       = linkedFaces.Count;
                    for (int i = 0; i < count; ++i)
                    {
                        mesh.faces[linkedFaces[i]].mark = filterTag;
                    }
                }
                if (_parameters.checkTopology && _producesBadTopology(mesh, cinfo, filterTag))
                {
                    // Apply penalties for bad collapses
                    cinfo.cost += kMeshPenaltyBadTopology;
                }
                else if (_parameters.maxEdgesPerVertex > 0 && _vertexDegreeAfterCollapse(mesh, cinfo) > _parameters.maxEdgesPerVertex)                     // Hard coded at 18 for now.. rarely reached, but always check!
                // Avoid collapses leading to excessive stars (many verts connected to one)
                {
                    cinfo.cost += kMeshPenaltyMaxEdgesPerVertex;
                }
            }

            // Additional penalties:
            float val = 0.0f;

            if (_parameters.boneWeightProtection > 0.0f)
            {
                val += UnityUtils.BoneWeightDeltaSqr(v0.boneWeight, v1.boneWeight) * _parameters.boneWeightProtection;
            }
            if (_parameters.vertexColorProtection > 0.0f)
            {
                val += UnityUtils.ColorDeltaSqr(v0.color, v1.color) * _parameters.vertexColorProtection;
            }
            if (val != 0.0f)
            {
                cinfo.cost += 0.1f * val * mesh.EdgeLengthSqr(edgeIndex);
            }
        }
예제 #9
0
        public void CalculateFaceVertexNormalsFromEdgeCreasesForVertex(int vertexIndex, ref List <int>[] faceLinkedEdges)
        {
            int        i, j, grp;
            List <int> grpCornerIndex = new List <int>();

            Vertex    v               = vertices[vertexIndex];
            IndexList vertexFaces     = v.linkedFaces;
            int       vertexFaceCount = vertexFaces.Count;

            //	List<int> vertexEdges = linkedEdges[vertexIndex];
            // Clear face marks around vertex
            for (j = 0; j < vertexFaceCount; ++j)
            {
                faces[vertexFaces[j]].mark = -1;                 // TODO: could be faster with uniqueTag
            }
            // This will add each facemark to a groupIndex
            int groupIndex = 0;

            for (j = 0; j < vertexFaceCount; ++j)
            {
                int faceIndex = vertexFaces[j];
                if (faces[faceIndex].mark == -1)                   // face still available
                {
                    _markGroupFaceNeightbours(vertexIndex, vertexFaces[j], ref faceLinkedEdges, groupIndex);
                    groupIndex++;
                }
            }
            // Build group arrays
            List <int>[] groups = new List <int> [groupIndex];          // are these too many allocations?
            for (i = 0; i < groupIndex; ++i)
            {
                groups[i] = new List <int>();
            }
            for (i = 0; i < vertexFaceCount; ++i)
            {
                int faceIndex = vertexFaces[i];
                int mark      = faces[faceIndex].mark;
                groups[mark].Add(faceIndex);
            }

            // Calculate and set normal for each face on the vertex based on the groups
            Vector3 normal;

            for (grp = 0; grp < groupIndex; ++grp)
            {
                normal = Vector3.zero;
                List <int> grpFaces = groups[grp];
                int        cnt      = grpFaces.Count;
                grpCornerIndex.Clear();
                for (i = 0; i < cnt; ++i)
                {
                    Face f = faces[grpFaces[i]];
                    if (f.normal == Vector3.zero)
                    {
                        //	Debug.Log("face has zero normal .. valid " + f.valid);
                    }
                    // Multiply with corner angle (=SLOW?)
                    int   corner = f.CornerIndex(vertexIndex);
                    float fact   = CornerAngle(grpFaces[i], corner);
                    normal += f.normal * fact;
                    grpCornerIndex.Add(corner);
                }
                UnityUtils.NormalizeSmallVector(ref normal);
                if (normal == Vector3.zero)
                {
                    //	Debug.Log("NORMAL == ZERO facecount " + cnt);
                }
                // Now set the normal to all group faces
                for (i = 0; i < cnt; ++i)
                {
                    faces[grpFaces[i]].vertexNormal[grpCornerIndex[i]] = normal;
                }
            }
        }