Ejemplo n.º 1
0
        public UnsafeDFS(int nodeCount, Allocator allocator = Allocator.Temp)
        {
            this.position = -1;
            this.depth    = -1;

            this.pending     = new UnsafeArrayULong(nodeCount, allocator);
            this.pendingHead = 0;

            this.visited = new UnsafeArrayBool(nodeCount, allocator);
            this.visited.Clear(false);
        }
Ejemplo n.º 2
0
        static void ImportClip(SkinDeformationClip clip)
        {
            try
            {
                var progressTitle = "Importing '" + clip.name + "'";
                var progressIndex = 0;
                var progressCount = 4.0f;

                EditorUtility.DisplayProgressBar(progressTitle, "Loading assets", progressIndex++ / progressCount);

                var sourceObjPaths     = null as string[];
                var sourceMeshAssets   = null as Mesh[];
                var sourceAlbedoAssets = null as Texture2D[];

                int frameCount       = 0;
                int frameVertexCount = 0;

                var useExternalLoader = (clip.importSettings.readFrom == SkinDeformationClip.InputType.ExternalObj);
                if (useExternalLoader)
                {
                    sourceObjPaths = GetFilesAtPath(clip.importSettings.externalObjPath, clip.importSettings.externalObjPattern);
                    Debug.Assert(sourceObjPaths.Length > 0, "source .obj count == 0 (check import settings)");

                    using (var nativeMesh = NativeMeshObjLoader.Parse(sourceObjPaths[0]))
                    {
                        frameCount       = sourceObjPaths.Length;
                        frameVertexCount = nativeMesh.vertexCount;
                    }
                }
                else
                {
                    sourceMeshAssets = GetAssetsAtPath <Mesh>(clip.importSettings.meshAssetPath, clip.importSettings.meshAssetPrefix);
                    Debug.Assert(sourceMeshAssets.Length > 0, "mesh count == 0 (check import settings)");

                    sourceAlbedoAssets = GetAssetsAtPath <Texture2D>(clip.importSettings.albedoAssetPath, clip.importSettings.albedoAssetPrefix);
                    if (sourceAlbedoAssets.Length != sourceMeshAssets.Length)
                    {
                        sourceAlbedoAssets = null;
                        Debug.LogWarning("mesh asset count != albedo asset count: skipping albedos");
                    }

                    frameCount       = sourceMeshAssets.Length;
                    frameVertexCount = sourceMeshAssets[0].vertexCount;
                }

                int frameFittedWeightsCount = 0;                // modified later
                var frames = new SkinDeformation[frameCount];

                int subframeCount = frameCount - 1;
                var subframes     = new SkinDeformationClip.Subframe[subframeCount];

                MeshBuffers buffersFrame0 = new MeshBuffers(frameVertexCount);
                MeshBuffers buffersFrameX = new MeshBuffers(frameVertexCount);
                MeshBuffers buffersTarget = buffersFrame0;

                if (clip.importSettings.transferTarget != null)
                {
                    buffersTarget = new MeshBuffers(clip.importSettings.transferTarget);
                }

                MeshAdjacency weldedAdjacency = new MeshAdjacency(buffersTarget, clip.importSettings.solveWelded);

                EditorUtility.DisplayProgressBar(progressTitle, "Importing frames", progressIndex++ / progressCount);
                {
                    var sourceRotation = Quaternion.Euler(clip.importSettings.applyRotation);
                    var sourceScale    = clip.importSettings.applyScale;

                    if (useExternalLoader)
                    {
                        using (var nativeMesh = NativeMeshObjLoader.Parse(sourceObjPaths[0]))
                        {
                            buffersFrame0.LoadFrom(nativeMesh);
                            buffersFrame0.ApplyRotation(sourceRotation);
                            buffersFrame0.ApplyScale(sourceScale);
                        }
                    }
                    else
                    {
                        buffersFrame0.LoadFrom(sourceMeshAssets[0]);
                        buffersFrame0.ApplyRotation(sourceRotation);
                        buffersFrame0.ApplyScale(sourceScale);
                    }

                    var denoiseIndices = ResolveIndexArrayFromVertexSelectionArray(clip.importSettings.denoiseRegions, weldedAdjacency);
                    var denoiseFactor  = clip.importSettings.denoiseStrength;

                    if (denoiseFactor < float.Epsilon)
                    {
                        denoiseIndices = new int[0];
                    }

                    var transplantIndices = ResolveIndexArrayFromVertexSelectionArray(clip.importSettings.transplantRegions, weldedAdjacency);
                    var transplantFactor  = clip.importSettings.transplantStrength;
                    var transplantSource  = clip.importSettings.transferTarget;

                    if (transplantFactor < float.Epsilon || transplantSource == null)
                    {
                        transplantIndices = new int[0];
                    }

#if SOLVE_FULL_LAPLACIAN
                    var laplacianConstraintCount   = frameVertexCount;
                    var laplacianConstraintIndices = null as int[];

                    unsafe
                    {
                        using (var laplacianFreeVertexMap = new UnsafeArrayBool(frameVertexCount))
                        {
                            laplacianFreeVertexMap.Clear(false);

                            for (int k = 0; k != denoiseIndices.Length; k++)
                            {
                                if (laplacianFreeVertexMap.val[denoiseIndices[k]] == false)
                                {
                                    laplacianFreeVertexMap.val[denoiseIndices[k]] = true;
                                    laplacianConstraintCount--;
                                }
                            }

                            for (int k = 0; k != transplantIndices.Length; k++)
                            {
                                if (laplacianFreeVertexMap.val[transplantIndices[k]] == false)
                                {
                                    laplacianFreeVertexMap.val[transplantIndices[k]] = true;
                                    laplacianConstraintCount--;
                                }
                            }

                            laplacianConstraintIndices = new int[laplacianConstraintCount];

                            for (int i = 0, k = 0; i != frameVertexCount; i++)
                            {
                                if (laplacianFreeVertexMap.val[i] == false)
                                {
                                    laplacianConstraintIndices[k++] = i;
                                }
                            }
                        }
                    }
#else
                    var laplacianROIIndices      = denoiseIndices.Union(transplantIndices).ToArray();
                    var laplacianConstraintCount = frameVertexCount - laplacianROIIndices.Length;
#endif

#if SOLVE_FULL_LAPLACIAN
                    var meshLaplacianTransform = null as MeshLaplacianTransform;
#else
                    var meshLaplacianTransform = null as MeshLaplacianTransformROI;
#endif
                    var meshLaplacian         = new MeshLaplacian();
                    var meshLaplacianDenoised = new MeshLaplacian();

                    var transplantBuffers   = new MeshBuffers(frameVertexCount);
                    var transplantLaplacian = new MeshLaplacian();

                    var laplacianResolve = (laplacianConstraintCount < frameVertexCount);
                    if (laplacianResolve)
                    {
#if SOLVE_FULL_LAPLACIAN
                        meshLaplacianTransform = new MeshLaplacianTransform(weldedAdjacency, laplacianConstraintIndices);
#else
                        meshLaplacianTransform = new MeshLaplacianTransformROI(weldedAdjacency, laplacianROIIndices, 0);
                        {
                            for (int i = 0; i != denoiseIndices.Length; i++)
                            {
                                denoiseIndices[i] = meshLaplacianTransform.internalFromExternal[denoiseIndices[i]];
                            }
                            for (int i = 0; i != transplantIndices.Length; i++)
                            {
                                transplantIndices[i] = meshLaplacianTransform.internalFromExternal[transplantIndices[i]];
                            }
                        }
#endif
                        meshLaplacianTransform.ComputeMeshLaplacian(meshLaplacianDenoised, buffersFrame0);

                        if (transplantIndices.Length > 0 && transplantSource != null)
                        {
                            transplantBuffers.LoadFrom(transplantSource);
                            meshLaplacianTransform.ComputeMeshLaplacian(transplantLaplacian, transplantBuffers);
                        }
                    }

                    for (int i = 0; i != frameCount; i++)
                    {
                        EditorUtility.DisplayProgressBar(progressTitle, "Importing frames", (progressIndex - 1 + ((float)i / frameCount)) / progressCount);

                        if (useExternalLoader)
                        {
                            using (var nativeMesh = NativeMeshObjLoader.Parse(sourceObjPaths[i]))
                            {
                                buffersFrameX.LoadFrom(nativeMesh);
                                buffersFrameX.ApplyRotation(sourceRotation);
                                buffersFrameX.ApplyScale(sourceScale);
                            }
                        }
                        else
                        {
                            buffersFrameX.LoadFrom(sourceMeshAssets[i]);
                            buffersFrameX.ApplyRotation(sourceRotation);
                            buffersFrameX.ApplyScale(sourceScale);
                        }

                        if (laplacianResolve)
                        {
                            meshLaplacianTransform.ComputeMeshLaplacian(meshLaplacian, buffersFrameX);

                            double historyFactor = denoiseFactor;
                            foreach (int j in denoiseIndices)
                            {
                                double dx = denoiseFactor * meshLaplacianDenoised.vertexDifferentialX[j] + (1.0 - denoiseFactor) * meshLaplacian.vertexDifferentialX[j];
                                double dy = denoiseFactor * meshLaplacianDenoised.vertexDifferentialY[j] + (1.0 - denoiseFactor) * meshLaplacian.vertexDifferentialY[j];
                                double dz = denoiseFactor * meshLaplacianDenoised.vertexDifferentialZ[j] + (1.0 - denoiseFactor) * meshLaplacian.vertexDifferentialZ[j];
                                meshLaplacian.vertexDifferentialX[j]         = dx;
                                meshLaplacian.vertexDifferentialY[j]         = dy;
                                meshLaplacian.vertexDifferentialZ[j]         = dz;
                                meshLaplacianDenoised.vertexDifferentialX[j] = dx;
                                meshLaplacianDenoised.vertexDifferentialY[j] = dy;
                                meshLaplacianDenoised.vertexDifferentialZ[j] = dz;
                            }

                            foreach (int j in transplantIndices)
                            {
                                meshLaplacian.vertexDifferentialX[j] = transplantFactor * transplantLaplacian.vertexDifferentialX[j] + (1.0 - transplantFactor) * meshLaplacian.vertexDifferentialX[j];
                                meshLaplacian.vertexDifferentialY[j] = transplantFactor * transplantLaplacian.vertexDifferentialY[j] + (1.0 - transplantFactor) * meshLaplacian.vertexDifferentialY[j];
                                meshLaplacian.vertexDifferentialZ[j] = transplantFactor * transplantLaplacian.vertexDifferentialZ[j] + (1.0 - transplantFactor) * meshLaplacian.vertexDifferentialZ[j];
                            }

                            meshLaplacianTransform.ResolveMeshBuffers(buffersFrameX, meshLaplacian);

                            buffersFrameX.RecalculateNormals(weldedAdjacency);
                            buffersFrameX.ApplyWeldedChanges(weldedAdjacency);
                        }

                        frames[i].SetAlbedo((sourceAlbedoAssets != null) ? sourceAlbedoAssets[i] : null);
                        frames[i].SetDeltas(buffersFrame0, buffersFrameX);

                        var targetVertexCount = buffersFrame0.vertexCount;
                        if (targetVertexCount != buffersFrameX.vertexCount)
                        {
                            Debug.LogWarning("frame " + i + " has different vertexCount (" + buffersFrameX.vertexCount + " vs " + targetVertexCount + " in frame 0)");
                        }
                    }

                    for (int i = 0; i != subframeCount; i++)
                    {
                        subframes[i].frameIndexLo = i;
                        subframes[i].frameIndexHi = i + 1;
                        subframes[i].fractionLo   = 0.0f;
                        subframes[i].fractionHi   = 1.0f;
                    }

                    if (clip.importSettings.keyframes)
                    {
                        ImportFrameIntervalsFromCSV(clip.importSettings.keyframesCSV, frameCount - 1, ref subframeCount, ref subframes);
                    }
                }

                EditorUtility.DisplayProgressBar(progressTitle, "Retargeting frames", progressIndex++ / progressCount);
                {
                    switch (clip.importSettings.transferMode)
                    {
                    case SkinDeformationClip.TransferMode.PassThrough:
                    {
                        // clean copy
                    }
                    break;

                    case SkinDeformationClip.TransferMode.PassThroughWithFirstFrameDelta:
                    {
                        buffersFrameX.LoadFrom(clip.importSettings.transferTarget);

                        Vector3 anchorOrigin = buffersFrame0.CalcMeshCenter();
                        Vector3 anchorTarget = buffersFrameX.CalcMeshCenter();
                        Vector3 offsetTarget = anchorOrigin - anchorTarget;
                        for (int j = 0; j != frameVertexCount; j++)
                        {
                            buffersFrameX.vertexPositions[j] += offsetTarget;
                        }

                        SkinDeformation firstFrameDelta;
                        firstFrameDelta = new SkinDeformation();
                        firstFrameDelta.SetDeltas(buffersFrameX, buffersFrame0);

                        for (int i = 0; i != frameCount; i++)
                        {
                            EditorUtility.DisplayProgressBar(progressTitle, "Retargeting frames", (progressIndex - 1 + ((float)i / frameCount)) / progressCount);

                            for (int j = 0; j != frameVertexCount; j++)
                            {
                                frames[i].deltaPositions[j] += firstFrameDelta.deltaPositions[j];
                                frames[i].deltaNormals[j]   += firstFrameDelta.deltaNormals[j];
                            }
                        }
                    }
                    break;
                    }
                }

                EditorUtility.DisplayProgressBar(progressTitle, "Fitting frames to blend shapes", progressIndex++ / progressCount);
                {
                    if (clip.importSettings.fitToBlendShapes)
                    {
                        frameFittedWeightsCount = clip.importSettings.transferTarget.blendShapeCount;
                    }
                    else
                    {
                        frameFittedWeightsCount = 0;
                    }

                    for (int i = 0; i != frameCount; i++)
                    {
                        frames[i].fittedWeights = new float[frameFittedWeightsCount];
                    }

                    if (frameFittedWeightsCount > 0)
                    {
                        var blendShapeIndicesCommaSep = clip.importSettings.fittedIndices;
                        var blendShapeIndices         = Array.ConvertAll <string, int>(blendShapeIndicesCommaSep.Split(','), int.Parse);

                        SkinDeformationFitting.FitFramesToBlendShapes(frames, clip.importSettings.transferTarget, blendShapeIndices, clip.importSettings.fittingMethod, clip.importSettings.fittingParam);
                    }
                }

                EditorUtility.DisplayProgressBar(progressTitle, "Saving binary", progressIndex++ / progressCount);
                {
                    clip.lastImport              = clip.importSettings.Clone();
                    clip.frameCount              = frameCount;
                    clip.frameVertexCount        = frameVertexCount;
                    clip.frameFittedWeightsCount = frameFittedWeightsCount;
                    clip.frames = frames;
                    clip.framesContainAlbedo        = (frames[0].albedo != null);
                    clip.framesContainDeltas        = (frames[0].deltaPositions.Length > 0);
                    clip.framesContainFittedWeights = (frames[0].fittedWeights.Length > 0);
                    clip.subframeCount = subframeCount;
                    clip.subframes     = subframes;
                    clip.version++;

                    EditorUtility.SetDirty(clip);
                    AssetDatabase.SaveAssets();

                    clip.SaveFrameData();
                }
            }
            catch (Exception ex)
            {
                Debug.LogError(ex);
            }
            finally
            {
                EditorUtility.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();
                        }
            }
        }
Ejemplo n.º 4
0
        public void LoadFrom(MeshBuffers meshBuffers, bool welded = false)
        {
            vertexCount = meshBuffers.vertexCount;
            vertexTriangles.Allocate(vertexCount, vertexCount * 8);
            vertexVertices.Allocate(vertexCount, vertexCount * 8);
            vertexWelded.Allocate(vertexCount, vertexCount);

            ArrayUtils.ResizeCheckedIfLessThan(ref vertexResolve, vertexCount);

            triangleCount = meshBuffers.triangleCount / 3;
            triangleTriangles.Allocate(triangleCount, triangleCount * 8);
            triangleVertices.Allocate(triangleCount, triangleCount * 3);

            int[] triangles = meshBuffers.triangles;

            // build vertex-triangle
            {
                for (int i = 0; i != triangleCount; i++)
                {
                    int _0 = i * 3;
                    int v0 = triangles[_0 + 0];
                    int v1 = triangles[_0 + 1];
                    int v2 = triangles[_0 + 2];

                    vertexTriangles.Append(v0, i);
                    vertexTriangles.Append(v1, i);
                    vertexTriangles.Append(v2, i);
                }
            }

            // build vertex-welded
            unsafe
            {
                if (welded)
                {
                    // for each vertex
                    //   if vertex != closest vertex
                    //     replace references to vertex with closest vertex
                    triangles = triangles.Clone() as int[];

                    using (var vertexWeldedMap = new UnsafeArrayBool(meshBuffers.vertexCount))
                    {
                        vertexWeldedMap.Clear(false);

                        var vertexBSP = new KdTree3(meshBuffers.vertexPositions, meshBuffers.vertexCount);

                        for (int i = 0; i != vertexCount; i++)
                        {
                            int j = vertexBSP.FindNearest(ref meshBuffers.vertexPositions[i]);
                            if (j != i)
                            {
                                //Debug.Assert(vertexWeldedMap.val[j] == false);

                                // replace references to i with j, keeping j
                                foreach (var triangle in vertexTriangles[i])
                                {
                                    int _0 = triangle * 3;
                                    int v0 = triangles[_0 + 0];
                                    int v1 = triangles[_0 + 1];
                                    //..v2 = triangles[_0 + 2];

                                    if (v0 == i)
                                    {
                                        triangles[_0 + 0] = j;
                                    }
                                    else if (v1 == i)
                                    {
                                        triangles[_0 + 1] = j;
                                    }
                                    else                                     // (v2 == i)
                                    {
                                        triangles[_0 + 2] = j;
                                    }

                                    // store i under j, so we can recover i at a later time
                                    if (vertexWeldedMap.val[i] == false)
                                    {
                                        vertexWeldedMap.val[i] = true;
                                        vertexWelded.Append(j, i);
                                    }
                                }
                            }
                        }
                    }

                    // rebuild vertex-triangle
                    vertexTriangles.Clear();

                    for (int i = 0; i != triangleCount; i++)
                    {
                        int _0 = i * 3;
                        int v0 = triangles[_0 + 0];
                        int v1 = triangles[_0 + 1];
                        int v2 = triangles[_0 + 2];

                        vertexTriangles.Append(v0, i);
                        vertexTriangles.Append(v1, i);
                        vertexTriangles.Append(v2, i);
                    }
                }
            }

            // build vertex-resolve
            {
                for (int i = 0; i != vertexCount; i++)
                {
                    vertexResolve[i] = i;
                }

                for (int i = 0; i != vertexCount; i++)
                {
                    foreach (var j in vertexWelded[i])
                    {
                        vertexResolve[j] = i;
                    }
                }
            }

            // build vertex-vertex
            unsafe
            {
                using (var vertexAdded = new UnsafeArrayBool(vertexCount))
                {
                    vertexAdded.Clear(false);

                    for (int i = 0; i != vertexCount; i++)
                    {
                        foreach (int triangle in vertexTriangles[i])
                        {
                            int _0 = triangle * 3;
                            int v0 = triangles[_0 + 0];
                            int v1 = triangles[_0 + 1];
                            int v2 = triangles[_0 + 2];

                            int vA, vB;
                            if (i == v0)
                            {
                                vA = v1;
                                vB = v2;
                            }
                            else if (i == v1)
                            {
                                vA = v2;
                                vB = v0;
                            }
                            else                             // (i == v2)
                            {
                                vA = v0;
                                vB = v1;
                            }

                            if (vertexAdded.val[vA] == false && (vertexAdded.val[vA] = true))
                            {
                                vertexVertices.Append(i, vA);
                            }

                            if (vertexAdded.val[vB] == false && (vertexAdded.val[vB] = true))
                            {
                                vertexVertices.Append(i, vB);
                            }
                        }

                        foreach (int j in vertexVertices[i])
                        {
                            vertexAdded.val[j] = false;
                        }
                    }
                }
            }

            // build triangle-triangle
            unsafe
            {
                using (var triangleAdded = new UnsafeArrayBool(triangleCount))
                {
                    triangleAdded.Clear(false);

                    for (int i = 0; i != triangleCount; i++)
                    {
                        int _0 = i * 3;
                        int v0 = triangles[_0 + 0];
                        int v1 = triangles[_0 + 1];
                        int v2 = triangles[_0 + 2];

                        triangleAdded.val[i] = true;

                        foreach (int j in vertexTriangles[v0])
                        {
                            if (triangleAdded.val[j] == false && (triangleAdded.val[j] = true))
                            {
                                triangleTriangles.Append(i, j);
                            }
                        }

                        foreach (int j in vertexTriangles[v1])
                        {
                            if (triangleAdded.val[j] == false && (triangleAdded.val[j] = true))
                            {
                                triangleTriangles.Append(i, j);
                            }
                        }

                        foreach (int j in vertexTriangles[v2])
                        {
                            if (triangleAdded.val[j] == false && (triangleAdded.val[j] = true))
                            {
                                triangleTriangles.Append(i, j);
                            }
                        }

                        triangleAdded.val[i] = false;

                        foreach (int j in triangleTriangles[i])
                        {
                            triangleAdded.val[j] = false;
                        }
                    }
                }
            }

            // build triangle-vertex
            {
                for (int i = 0; i != triangleCount; i++)
                {
                    int _0 = i * 3;
                    int v0 = triangles[_0 + 0];
                    int v1 = triangles[_0 + 1];
                    int v2 = triangles[_0 + 2];

                    triangleVertices.Append(i, v0);
                    triangleVertices.Append(i, v1);
                    triangleVertices.Append(i, v2);
                }
            }
        }
Ejemplo n.º 5
0
        static void ImportClip(SkinDeformationClip clip)
        {
            var sourceObjsPreloaded = null as NativeMeshSOA[];

            try
            {
                var progressTitle = "Importing '" + clip.name + "'";
                var progressIndex = 0;
                var progressCount = 4.0f;

                EditorUtility.DisplayProgressBar(progressTitle, "Loading assets", progressIndex++ / progressCount);

                var sourceObjPaths     = null as string[];
                var sourceMeshAssets   = null as Mesh[];
                var sourceAlbedoAssets = null as Texture2D[];

                var referenceObjPath      = clip.settings.referenceObjPath;
                var referenceMeshAsset    = clip.settings.referenceMeshAsset;
                var referenceIsFirstFrame = clip.settings.referenceIsFirstFrame;

                int frameCount            = 0;
                int frameVertexCount      = 0;
                int frameFaceIndicesCount = 0;

                var useExternalLoader = (clip.settings.sourceFrom == SkinDeformationClip.SourceType.ExternalObj);
                if (useExternalLoader)
                {
                    sourceObjPaths = GetFilesAtPath(clip.settings.externalObjPath, clip.settings.externalObjPattern);
                    Debug.Assert(sourceObjPaths.Length > 0, "source obj count == 0 (check import settings)");

                    if (referenceIsFirstFrame)
                    {
                        referenceObjPath = sourceObjPaths[0];
                        sourceObjPaths   = sourceObjPaths.Skip(1).ToArray();
                    }

                    using (var nativeMesh = NativeMeshObjLoader.Parse(referenceObjPath))
                    {
                        frameCount            = sourceObjPaths.Length;
                        frameVertexCount      = nativeMesh.vertexCount;
                        frameFaceIndicesCount = nativeMesh.faceIndicesCount;
                    }

                    if (clip.settings.externalObjPreloadThreaded)
                    {
                        sharedJobData.paths         = sourceObjPaths;
                        sharedJobData.vertexAttribs = NativeMeshObjLoader.VertexAttribs.Position;                        // ignored for now
                        sharedJobData.vertexOrder   = NativeMeshObjLoader.VertexOrder.ByDefinition;
                        sharedJobData.result        = new NativeMeshSOA[sourceObjPaths.Length];
                        sharedJobData.resultTouched = new bool[sourceObjPaths.Length];

                        for (int i = 0; i != sharedJobData.result.Length; i++)
                        {
                            sharedJobData.result[i].Allocate(frameVertexCount, frameFaceIndicesCount, Allocator.Persistent);
                        }

                        unsafe
                        {
                            fixed(bool *resultTouched = sharedJobData.resultTouched)
                            {
                                var jobDef = new ObjLoaderJob();
                                var job    = jobDef.Schedule(sourceObjPaths.Length, 1);

                                JobHandle.ScheduleBatchedJobs();

                                while (true)
                                {
                                    int numTotal   = sourceObjPaths.Length;
                                    int numTouched = 0;

                                    for (int i = 0; i != numTotal; i++)
                                    {
                                        if (resultTouched[i])
                                        {
                                            numTouched++;
                                        }
                                    }

                                    EditorUtility.DisplayProgressBar(progressTitle, "Loading assets (" + numTouched + " / " + numTotal + ")", (progressIndex - 1 + ((float)numTouched / numTotal)) / progressCount);

                                    if (job.IsCompleted)
                                    {
                                        break;
                                    }
                                }

                                job.Complete();
                            }
                        }

                        sourceObjsPreloaded = sharedJobData.result;
                    }
                }
                else
                {
                    sourceMeshAssets = GetAssetsAtPath <Mesh>(clip.settings.meshAssetFolder, clip.settings.meshAssetPrefix);
                    Debug.Assert(sourceMeshAssets.Length > 0, "source mesh count == 0 (check import settings)");

                    sourceAlbedoAssets = GetAssetsAtPath <Texture2D>(clip.settings.albedoAssetFolder, clip.settings.albedoAssetPrefix);
                    if (sourceAlbedoAssets.Length != sourceMeshAssets.Length)
                    {
                        sourceAlbedoAssets = null;
                        Debug.LogWarning("source albedo count != mesh count (SKIPPING albedo assets)");
                    }

                    if (referenceIsFirstFrame)
                    {
                        referenceMeshAsset = sourceMeshAssets[0];
                        sourceMeshAssets   = sourceMeshAssets.Skip(1).ToArray();

                        if (sourceAlbedoAssets != null)
                        {
                            sourceAlbedoAssets = sourceAlbedoAssets.Skip(1).ToArray();
                        }
                    }

                    Debug.Assert(referenceMeshAsset != null);

                    frameCount       = sourceMeshAssets.Length;
                    frameVertexCount = referenceMeshAsset.vertexCount;
                }

                Debug.Log("frameCount: " + frameCount);
                Debug.Log("frameVertexCount: " + frameVertexCount);

                int frameFittedWeightsCount = 0;                // modified later
                var frames = new SkinDeformation[frameCount];

                int subframeCount = frameCount - 1;
                var subframes     = new SkinDeformationClip.Subframe[subframeCount];

                MeshBuffers meshBuffers          = new MeshBuffers(frameVertexCount);
                MeshBuffers meshBuffersReference = new MeshBuffers(frameVertexCount);

                MeshAdjacency weldedAdjacency = new MeshAdjacency(meshBuffersReference, clip.settings.solveWelded);

                EditorUtility.DisplayProgressBar(progressTitle, "Importing frames", progressIndex++ / progressCount);
                {
                    var sourceRotation = Quaternion.Euler(clip.settings.applyRotation);
                    var sourceScale    = clip.settings.applyScaling;

                    if (useExternalLoader)
                    {
                        using (var referenceObj = NativeMeshObjLoader.Parse(referenceObjPath))
                        {
                            meshBuffersReference.LoadFrom(referenceObj);
                            meshBuffersReference.ApplyRotation(sourceRotation);
                            meshBuffersReference.ApplyScale(sourceScale);
                        }
                    }
                    else
                    {
                        meshBuffersReference.LoadFrom(referenceMeshAsset);
                        meshBuffersReference.ApplyRotation(sourceRotation);
                        meshBuffersReference.ApplyScale(sourceScale);
                    }

                    var denoiseIndices = ResolveIndexArrayFromVertexSelectionArray(clip.settings.denoiseRegions, weldedAdjacency);
                    var denoiseFactor  = clip.settings.denoiseStrength;
                    if (denoiseFactor < float.Epsilon)
                    {
                        denoiseIndices = new int[0];
                    }

                    var transplantIndices = ResolveIndexArrayFromVertexSelectionArray(clip.settings.transplantRegions, weldedAdjacency);
                    var transplantFactor  = clip.settings.transplantStrength;
                    if (transplantFactor < float.Epsilon)
                    {
                        transplantIndices = new int[0];
                    }

#if SOLVE_FULL_LAPLACIAN
                    var laplacianConstraintCount   = frameVertexCount;
                    var laplacianConstraintIndices = null as int[];

                    unsafe
                    {
                        using (var laplacianFreeVertexMap = new UnsafeArrayBool(frameVertexCount))
                        {
                            laplacianFreeVertexMap.Clear(false);

                            for (int k = 0; k != denoiseIndices.Length; k++)
                            {
                                if (laplacianFreeVertexMap.val[denoiseIndices[k]] == false)
                                {
                                    laplacianFreeVertexMap.val[denoiseIndices[k]] = true;
                                    laplacianConstraintCount--;
                                }
                            }

                            for (int k = 0; k != transplantIndices.Length; k++)
                            {
                                if (laplacianFreeVertexMap.val[transplantIndices[k]] == false)
                                {
                                    laplacianFreeVertexMap.val[transplantIndices[k]] = true;
                                    laplacianConstraintCount--;
                                }
                            }

                            laplacianConstraintIndices = new int[laplacianConstraintCount];

                            for (int i = 0, k = 0; i != frameVertexCount; i++)
                            {
                                if (laplacianFreeVertexMap.val[i] == false)
                                {
                                    laplacianConstraintIndices[k++] = i;
                                }
                            }
                        }
                    }
#else
                    var laplacianROIIndices      = denoiseIndices.Union(transplantIndices).ToArray();
                    var laplacianConstraintCount = frameVertexCount - laplacianROIIndices.Length;
#endif

#if SOLVE_FULL_LAPLACIAN
                    var laplacianTransform = null as MeshLaplacianTransform;
#else
                    var laplacianTransform = null as MeshLaplacianTransformROI;
#endif
                    var meshLaplacian          = new MeshLaplacian();
                    var meshLaplacianDenoised  = new MeshLaplacian();
                    var meshLaplacianReference = new MeshLaplacian();

                    var laplacianResolve = (laplacianConstraintCount < frameVertexCount);
                    if (laplacianResolve)
                    {
#if SOLVE_FULL_LAPLACIAN
                        laplacianTransform = new MeshLaplacianTransform(weldedAdjacency, laplacianConstraintIndices);
#else
                        laplacianTransform = new MeshLaplacianTransformROI(weldedAdjacency, laplacianROIIndices, 0);
                        {
                            for (int i = 0; i != denoiseIndices.Length; i++)
                            {
                                denoiseIndices[i] = laplacianTransform.internalFromExternal[denoiseIndices[i]];
                            }
                            for (int i = 0; i != transplantIndices.Length; i++)
                            {
                                transplantIndices[i] = laplacianTransform.internalFromExternal[transplantIndices[i]];
                            }
                        }
#endif
                        laplacianTransform.ComputeMeshLaplacian(meshLaplacianDenoised, meshBuffersReference);
                        laplacianTransform.ComputeMeshLaplacian(meshLaplacianReference, meshBuffersReference);
                    }

                    for (int i = 0; i != frameCount; i++)
                    {
                        EditorUtility.DisplayProgressBar(progressTitle, "Importing frames (" + (i + 1) + " / " + frameCount + ")", (progressIndex - 1 + ((float)i / frameCount)) / progressCount);

                        if (useExternalLoader)
                        {
                            if (clip.settings.externalObjPreloadThreaded)
                            {
                                meshBuffers.LoadFrom(sourceObjsPreloaded[i]);
                            }
                            else
                            {
                                using (var sourceObj_i = NativeMeshObjLoader.Parse(sourceObjPaths[i]))
                                {
                                    meshBuffers.LoadFrom(sourceObj_i);
                                }
                            }

                            meshBuffers.ApplyRotation(sourceRotation);
                            meshBuffers.ApplyScale(sourceScale);
                        }
                        else
                        {
                            meshBuffers.LoadFrom(sourceMeshAssets[i]);
                            meshBuffers.ApplyRotation(sourceRotation);
                            meshBuffers.ApplyScale(sourceScale);
                        }

                        if (meshBuffers.vertexCount != frameVertexCount)
                        {
                            Debug.LogWarning("frame " + i + " has " + meshBuffers.vertexCount + " vertices (expected " + frameVertexCount + ")");
                        }

                        if (laplacianResolve)
                        {
                            laplacianTransform.ComputeMeshLaplacian(meshLaplacian, meshBuffers);

                            double historyFactor = denoiseFactor;
                            foreach (int j in denoiseIndices)
                            {
                                double dx = denoiseFactor * meshLaplacianDenoised.vertexDifferentialX[j] + (1.0 - denoiseFactor) * meshLaplacian.vertexDifferentialX[j];
                                double dy = denoiseFactor * meshLaplacianDenoised.vertexDifferentialY[j] + (1.0 - denoiseFactor) * meshLaplacian.vertexDifferentialY[j];
                                double dz = denoiseFactor * meshLaplacianDenoised.vertexDifferentialZ[j] + (1.0 - denoiseFactor) * meshLaplacian.vertexDifferentialZ[j];
                                meshLaplacian.vertexDifferentialX[j]         = dx;
                                meshLaplacian.vertexDifferentialY[j]         = dy;
                                meshLaplacian.vertexDifferentialZ[j]         = dz;
                                meshLaplacianDenoised.vertexDifferentialX[j] = dx;
                                meshLaplacianDenoised.vertexDifferentialY[j] = dy;
                                meshLaplacianDenoised.vertexDifferentialZ[j] = dz;
                            }

                            foreach (int j in transplantIndices)
                            {
                                meshLaplacian.vertexDifferentialX[j] = transplantFactor * meshLaplacianReference.vertexDifferentialX[j] + (1.0 - transplantFactor) * meshLaplacian.vertexDifferentialX[j];
                                meshLaplacian.vertexDifferentialY[j] = transplantFactor * meshLaplacianReference.vertexDifferentialY[j] + (1.0 - transplantFactor) * meshLaplacian.vertexDifferentialY[j];
                                meshLaplacian.vertexDifferentialZ[j] = transplantFactor * meshLaplacianReference.vertexDifferentialZ[j] + (1.0 - transplantFactor) * meshLaplacian.vertexDifferentialZ[j];
                            }

                            laplacianTransform.ResolveMeshBuffers(meshBuffers, meshLaplacian);

                            meshBuffers.RecalculateNormals(weldedAdjacency);
                            meshBuffers.ApplyWeldedChanges(weldedAdjacency);
                        }

                        frames[i].SetAlbedo(sourceAlbedoAssets != null ? sourceAlbedoAssets[i] : null);
                        frames[i].SetDeltas(meshBuffersReference, meshBuffers);
                    }

                    for (int i = 0; i != subframeCount; i++)
                    {
                        subframes[i].frameIndexLo = i;
                        subframes[i].frameIndexHi = i + 1;
                        subframes[i].fractionLo   = 0.0f;
                        subframes[i].fractionHi   = 1.0f;
                    }

                    if (clip.settings.keyframes)
                    {
                        ImportFrameIntervalsFromCSV(clip.settings.keyframesCSV, frameCount - 1, ref subframeCount, ref subframes);
                    }
                }

                EditorUtility.DisplayProgressBar(progressTitle, "Transferring frames", progressIndex++ / progressCount);
                if (clip.settings.transferTarget != null)
                {
                    var targetBuffers       = new MeshBuffers(clip.settings.transferTarget);
                    var targetVertexCount   = targetBuffers.vertexCount;
                    var targetVertexResolve = new int[targetVertexCount];

                    Debug.LogFormat("transferMode: {0}", clip.settings.transferMode);
                    Debug.LogFormat("targetVertexCount: {0}", targetVertexCount);

                    switch (clip.settings.transferMode)
                    {
                    case SkinDeformationClip.ImportSettings.TransferMode.ByVertexIndex:
                    {
                        Debug.Assert(frameVertexCount == targetVertexCount, "target vertex count does not match reference vertex count");
                        for (int i = 0; i != targetVertexCount; i++)
                        {
                            targetVertexResolve[i] = i;
                        }
                    }
                    break;

                    case SkinDeformationClip.ImportSettings.TransferMode.ByVertexPosition:
                    {
                        var referenceBSP             = new KdTree3(meshBuffersReference.vertexPositions, meshBuffersReference.vertexCount);
                        var referenceDelta2Max       = 0.0f;
                        var referenceDelta2Count     = 0;
                        var referenceDelta2Threshold = 1e-10f;

                        for (int i = 0; i != targetVertexCount; i++)
                        {
                            targetVertexResolve[i] = referenceBSP.FindNearest(ref targetBuffers.vertexPositions[i]);
                        }

                        for (int i = 0; i != targetVertexCount; i++)
                        {
                            Vector3 posTarget    = targetBuffers.vertexPositions[i];
                            Vector3 posReference = meshBuffersReference.vertexPositions[targetVertexResolve[i]];

                            var delta2 = Vector3.SqrMagnitude(posTarget - posReference);
                            if (delta2 > referenceDelta2Threshold)
                            {
                                referenceDelta2Max = Mathf.Max(delta2, referenceDelta2Max);
                                referenceDelta2Count++;
                            }
                        }

                        if (referenceDelta2Count > 0)
                        {
                            Debug.LogWarning("some (" + referenceDelta2Count + ") target vertices were far from reference (max delta: " + referenceDelta2Max + ")");
                        }
                    }
                    break;
                    }

                    var targetDeltaPositions = new Vector3[targetVertexCount];
                    var targetDeltaNormals   = new Vector3[targetVertexCount];

                    for (int frameIndex = 0; frameIndex != frameCount; frameIndex++)
                    {
                        EditorUtility.DisplayProgressBar(progressTitle, "Transferring frames (" + (frameIndex + 1) + " / " + frameCount + ")", (progressIndex - 1 + ((float)frameIndex / frameCount)) / progressCount);

                        for (int i = 0; i != targetVertexCount; i++)
                        {
                            int j = targetVertexResolve[i];                            // reference index

                            targetDeltaPositions[i] = frames[frameIndex].deltaPositions[j];
                            targetDeltaNormals[i]   = frames[frameIndex].deltaNormals[j];
                        }

                        ArrayUtils.ResizeChecked(ref frames[frameIndex].deltaPositions, targetVertexCount);
                        ArrayUtils.ResizeChecked(ref frames[frameIndex].deltaNormals, targetVertexCount);

                        ArrayUtils.CopyChecked(targetDeltaPositions, ref frames[frameIndex].deltaPositions, targetVertexCount);
                        ArrayUtils.CopyChecked(targetDeltaNormals, ref frames[frameIndex].deltaNormals, targetVertexCount);
                    }

                    frameVertexCount = targetVertexCount;

                    /*
                     * switch (clip.importSettings.transferMode)
                     * {
                     *      case SkinDeformationClip.TransferMode.PassThrough:
                     *              {
                     *                      // clean copy
                     *              }
                     *              break;
                     *
                     *      case SkinDeformationClip.TransferMode.PassThroughWithFirstFrameDelta:
                     *              {
                     *                      buffersFrameX.LoadFrom(clip.importSettings.transferTarget);
                     *
                     *                      Vector3 anchorOrigin = buffersFrame0.CalcMeshCenter();
                     *                      Vector3 anchorTarget = buffersFrameX.CalcMeshCenter();
                     *                      Vector3 offsetTarget = anchorOrigin - anchorTarget;
                     *                      for (int j = 0; j != frameVertexCount; j++)
                     *                      {
                     *                              buffersFrameX.vertexPositions[j] += offsetTarget;
                     *                      }
                     *
                     *                      SkinDeformation firstFrameDelta;
                     *                      firstFrameDelta = new SkinDeformation();
                     *                      firstFrameDelta.SetDeltas(buffersFrameX, buffersFrame0);
                     *
                     *                      for (int i = 0; i != frameCount; i++)
                     *                      {
                     *                              EditorUtility.DisplayProgressBar(progressTitle, "Retargeting frames", (progressIndex - 1 + ((float)i / frameCount)) / progressCount);
                     *
                     *                              for (int j = 0; j != frameVertexCount; j++)
                     *                              {
                     *                                      frames[i].deltaPositions[j] += firstFrameDelta.deltaPositions[j];
                     *                                      frames[i].deltaNormals[j] += firstFrameDelta.deltaNormals[j];
                     *                              }
                     *                      }
                     *              }
                     *              break;
                     * }
                     */
                }

                EditorUtility.DisplayProgressBar(progressTitle, "Fitting frames to blend shapes", progressIndex++ / progressCount);
                if (clip.settings.transferTarget != null)
                {
                    if (clip.settings.fitToBlendShapes)
                    {
                        frameFittedWeightsCount = clip.settings.transferTarget.blendShapeCount;
                    }
                    else
                    {
                        frameFittedWeightsCount = 0;
                    }

                    for (int i = 0; i != frameCount; i++)
                    {
                        frames[i].fittedWeights = new float[frameFittedWeightsCount];
                    }

                    if (frameFittedWeightsCount > 0)
                    {
                        var blendShapeIndicesCommaSep = clip.settings.fittedIndices;
                        var blendShapeIndices         = Array.ConvertAll <string, int>(blendShapeIndicesCommaSep.Split(','), int.Parse);

                        SkinDeformationFitting.FitFramesToBlendShapes(frames, clip.settings.transferTarget, blendShapeIndices, clip.settings.fittingMethod, clip.settings.fittingParam);
                    }
                }
                else
                {
                    for (int i = 0; i != frameCount; i++)
                    {
                        frames[i].fittedWeights = new float[0];
                    }
                }

                EditorUtility.DisplayProgressBar(progressTitle, "Saving binary", progressIndex++ / progressCount);
                {
                    clip.settingsLastImported    = clip.settings.Clone();
                    clip.frameCount              = frameCount;
                    clip.frameVertexCount        = frameVertexCount;
                    clip.frameFittedWeightsCount = frameFittedWeightsCount;
                    clip.frames = frames;
                    clip.framesContainAlbedo        = (frames[0].albedo != null);
                    clip.framesContainDeltas        = (frames[0].deltaPositions.Length > 0);
                    clip.framesContainFittedWeights = (frames[0].fittedWeights.Length > 0);
                    clip.subframeCount = subframeCount;
                    clip.subframes     = subframes;
                    clip.version++;

                    EditorUtility.SetDirty(clip);
                    AssetDatabase.SaveAssets();

                    clip.SaveFrameData();
                }
            }
            catch (Exception ex)
            {
                Debug.LogError(ex);
            }
            finally
            {
                if (sourceObjsPreloaded != null)
                {
                    for (int i = 0; i != sourceObjsPreloaded.Length; i++)
                    {
                        sourceObjsPreloaded[i].Dispose();
                    }

                    sourceObjsPreloaded = null;
                }

                EditorUtility.ClearProgressBar();
            }
        }