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(); } } }