Ejemplo n.º 1
0
        public static int[] ComputeLinearlyIndependentBlendShapeIndices(UnityEngine.Mesh mesh, int[] blendShapeIndices)
        {
            var numShapes = blendShapeIndices.Length;
            var outShapes = new int[numShapes];

            var numVertices  = mesh.vertexCount;
            var numEquations = 3 * numVertices;
            var numVariables = 0;

            var tmpPositions = new UnityEngine.Vector3[numVertices];
            var tmpTangents  = new UnityEngine.Vector3[numVertices];
            var tmpNormals   = new UnityEngine.Vector3[numVertices];

            var A = new double[numEquations, 1];            // start with an empty column
            var _ = new double[numEquations];

            {
                for (int j = 0; j != numShapes; j++)
                {
                    int k = blendShapeIndices[j];

                    if (EditorUtilityProxy.DisplayCancelableProgressBar("Filter linearly independent blend shapes", "Processing shape " + k + " (" + mesh.GetBlendShapeName(k) + ")", j / (float)numShapes))
                    {
                        outShapes = null;
                        break;                        // user cancelled
                    }
                    mesh.GetBlendShapeFrameVertices(k, 0, tmpPositions, tmpNormals, tmpTangents);

                    for (int i = 0; i != numVertices; i++)
                    {
                        _[i * 3 + 0] = tmpPositions[i].x;
                        _[i * 3 + 1] = tmpPositions[i].y;
                        _[i * 3 + 2] = tmpPositions[i].z;
                    }

                    A.SetColumn(numVariables, _);                    // write to empty column

                    var rank = Matrix.Rank(A.TransposeAndDot(A));
                    if (rank == numVariables + 1)
                    {
                        outShapes[numVariables++] = k;
                        A = A.Concatenate(_);                        // grow by one column
                    }
                    else
                    {
                        UnityEngine.Debug.LogWarning("shape " + k + " (" + mesh.GetBlendShapeName(k) + ") did NOT increase rank => skip");
                    }
                }

                EditorUtilityProxy.ClearProgressBar();
            }

            if (outShapes != null)
            {
                Array.Resize(ref outShapes, numVariables);
            }

            return(outShapes);
        }
        public void BuildFrom(MeshAdjacency meshAdjacency, int[] constraintIndices)
        {
            vertexCount = meshAdjacency.vertexCount;

            this.constraintIndices = constraintIndices.Clone() as int[];
            this.constraintWeight  = 1.0;

            // count unconstrained laplacian non-zero fields
            int nzmax = vertexCount;

            for (int i = 0; i != vertexCount; i++)
            {
                nzmax += meshAdjacency.vertexVertices.lists[i].size;
            }

            // build Ls
            EditorUtilityProxy.DisplayProgressBar("MeshLaplacian", "build Ls", 0.0f);
            var Ls_storage = new CoordinateStorage <double>(vertexCount, vertexCount, nzmax);

            for (int i = 0; i != vertexCount; i++)            // D
            {
                //TODO proper fix
                //Ls_storage.At(i, i, meshAdjacency.vertexVertices.lists[i].size);
                Ls_storage.At(i, i, Mathf.Max(1, meshAdjacency.vertexVertices.lists[i].size));
            }
            for (int i = 0; i != vertexCount; i++)            // A
            {
                foreach (var j in meshAdjacency.vertexVertices[i])
                {
                    Ls_storage.At(i, j, -1.0);
                }
            }
            Ls = Converter.ToCompressedColumnStorage(Ls_storage) as SparseMatrix;

            // build Lc
            EditorUtilityProxy.DisplayProgressBar("MeshLaplacian", "build Lc", 0.0f);
            var Lc_storage = new CoordinateStorage <double>(vertexCount + constraintIndices.Length, vertexCount, nzmax + constraintIndices.Length);

            for (int i = 0; i != vertexCount; i++)
            {
                //TODO proper fix
                //Lc_storage.At(i, i, meshAdjacency.vertexVertices.lists[i].size);
                Lc_storage.At(i, i, Mathf.Max(1, meshAdjacency.vertexVertices.lists[i].size));
            }
            for (int i = 0; i != vertexCount; i++)
            {
                foreach (var j in meshAdjacency.vertexVertices[i])
                {
                    Lc_storage.At(i, j, -1.0);
                }
            }
            for (int i = 0; i != constraintIndices.Length; i++)
            {
                Lc_storage.At(vertexCount + i, constraintIndices[i], constraintWeight);
            }
            Lc = Converter.ToCompressedColumnStorage(Lc_storage) as SparseMatrix;

            // build LcT
            EditorUtilityProxy.DisplayProgressBar("MeshLaplacian", "build LcT", 0.0f);
            LcT = Lc.Transpose() as SparseMatrix;

            // build LcT_Lc
            EditorUtilityProxy.DisplayProgressBar("MeshLaplacian", "build LcT_Lc", 0.0f);
            LcT_Lc = LcT.Multiply(Lc) as SparseMatrix;

            // build LcT_Lc_chol
            EditorUtilityProxy.DisplayProgressBar("MeshLaplacian", "build LcT_Lc_chol", 0.0f);
            LcT_Lc_chol = SparseCholesky.Create(LcT_Lc, ColumnOrdering.MinimumDegreeAtPlusA);

            // done
            EditorUtilityProxy.ClearProgressBar();
        }
        public void BuildFrom(MeshAdjacency meshAdjacency, int[] roiIndices, int roiBoundaryLevels, int[] roiConstraintIndices = null)
        {
            unsafe
            {
                using (var visited = new UnsafeArrayBool(meshAdjacency.vertexCount))
                    using (var visitedBoundary = new UnsafeArrayBool(meshAdjacency.vertexCount))
                        using (var visitor = new UnsafeBFS(meshAdjacency.vertexCount))
                        {
                            // find boundary
                            visited.Clear(false);
                            visitedBoundary.Clear(false);
                            visitor.Clear();

                            int visitedCount         = 0;
                            int visitedBoundaryCount = 0;

                            foreach (int i in roiIndices)
                            {
                                visited.val[i] = true;
                                visitedCount++;
                                visitor.Ignore(i);
                            }

                            foreach (int i in roiIndices)
                            {
                                foreach (var j in meshAdjacency.vertexVertices[i])
                                {
                                    visitor.Insert(j);
                                }
                            }

                            // step boundary
                            while (visitor.MoveNext())
                            {
                                int i = visitor.position;

                                visited.val[i] = true;
                                visitedCount++;
                                visitedBoundary.val[i] = true;
                                visitedBoundaryCount++;

                                if (visitor.depth < roiBoundaryLevels)
                                {
                                    foreach (var j in meshAdjacency.vertexVertices[i])
                                    {
                                        visitor.Insert(j);
                                    }
                                }
                            }

                            // add constraints
                            if (roiConstraintIndices != null)
                            {
                                foreach (int i in roiConstraintIndices)
                                {
                                    if (visited.val[i])
                                    {
                                        if (visitedBoundary.val[i] == false)
                                        {
                                            visitedBoundary.val[i] = true;
                                            visitedBoundaryCount++;
                                        }
                                    }
                                    else
                                    {
                                        Debug.LogWarning("ignoring user constraint outside ROI: vertex " + i);
                                    }
                                }
                            }

                            // build translations
                            internalCount = 0;
                            externalCount = meshAdjacency.vertexCount;

                            internalFromExternal = new int[externalCount];
                            externalFromInternal = new int[visitedCount];

                            for (int i = 0; i != meshAdjacency.vertexCount; i++)
                            {
                                if (visited.val[i])
                                {
                                    int internalIndex = internalCount++;
                                    externalFromInternal[internalIndex] = i;
                                    internalFromExternal[i]             = internalIndex;
                                }
                                else
                                {
                                    internalFromExternal[i] = -1;
                                }
                            }

                            // find constraint indices
                            constraintIndices = new int[visitedBoundaryCount];
                            constraintWeight  = 1.0;

                            int constraintCount = 0;
                            for (int i = 0; i != internalCount; i++)
                            {
                                if (visitedBoundary.val[externalFromInternal[i]])
                                {
                                    constraintIndices[constraintCount++] = i;
                                }
                            }

                            // count unconstrained laplacian non-zero fields
                            int nzmax = internalCount;
                            for (int i = 0; i != internalCount; i++)
                            {
                                nzmax += InternalValence(meshAdjacency, i);
                            }

                            // build Ls
                            EditorUtilityProxy.DisplayProgressBar("MeshLaplacian", "build Ls", 0.0f);
                            var Ls_storage = new CoordinateStorage <double>(internalCount, internalCount, nzmax);
                            for (int i = 0; i != internalCount; i++)            // D
                            {
                                //TODO proper fix
                                //Ls_storage.At(i, i, InternalValence(meshAdjacency, i));
                                Ls_storage.At(i, i, Mathf.Max(1, InternalValence(meshAdjacency, i)));
                            }
                            for (int i = 0; i != internalCount; i++)            // A
                            {
                                foreach (var k in meshAdjacency.vertexVertices[externalFromInternal[i]])
                                {
                                    int j = internalFromExternal[k];
                                    if (j != -1)
                                    {
                                        Ls_storage.At(i, j, -1.0);
                                    }
                                }
                            }
                            Ls = Converter.ToCompressedColumnStorage(Ls_storage) as SparseMatrix;

                            // build Lc
                            EditorUtilityProxy.DisplayProgressBar("MeshLaplacian", "build Lc", 0.0f);
                            var Lc_storage = new CoordinateStorage <double>(internalCount + constraintCount, internalCount, nzmax + constraintCount);
                            for (int i = 0; i != internalCount; i++)
                            {
                                //TODO proper fix
                                //Lc_storage.At(i, i, InternalValence(meshAdjacency, i));
                                Lc_storage.At(i, i, Mathf.Max(1, InternalValence(meshAdjacency, i)));
                            }
                            for (int i = 0; i != internalCount; i++)
                            {
                                foreach (var k in meshAdjacency.vertexVertices[externalFromInternal[i]])
                                {
                                    int j = internalFromExternal[k];
                                    if (j != -1)
                                    {
                                        Lc_storage.At(i, j, -1.0);
                                    }
                                }
                            }
                            for (int i = 0; i != constraintIndices.Length; i++)
                            {
                                Lc_storage.At(internalCount + i, constraintIndices[i], constraintWeight);
                            }
                            Lc = Converter.ToCompressedColumnStorage(Lc_storage) as SparseMatrix;

                            // build LcT
                            EditorUtilityProxy.DisplayProgressBar("MeshLaplacian", "build LcT", 0.0f);
                            LcT = Lc.Transpose() as SparseMatrix;

                            // build LcT_Lc
                            EditorUtilityProxy.DisplayProgressBar("MeshLaplacian", "build LcT_Lc", 0.0f);
                            LcT_Lc = LcT.Multiply(Lc) as SparseMatrix;

                            // build LcT_Lc_chol
                            EditorUtilityProxy.DisplayProgressBar("MeshLaplacian", "build LcT_Lc_chol", 0.0f);
                            LcT_Lc_chol = SparseCholesky.Create(LcT_Lc, ColumnOrdering.MinimumDegreeAtPlusA);

                            // done
                            EditorUtilityProxy.ClearProgressBar();
                        }
            }
        }