コード例 #1
0
        /// <summary>
        /// Combines a set of meshes into the target mesh.
        /// </summary>
        /// <param name="target">Target.</param>
        /// <param name="sources">Sources.</param>
        /// <param name="blendShapeSettings">BlendShape Settings.</param>
        public static void CombineMeshes(UMAMeshData target, CombineInstance[] sources, BlendShapeSettings blendShapeSettings = null)
        {
            if (blendShapeSettings == null)
            {
                blendShapeSettings = new BlendShapeSettings();
            }

            int vertexCount             = 0;
            int bindPoseCount           = 0;
            int transformHierarchyCount = 0;
            Dictionary <string, BlendShapeVertexData> blendShapeNames = new Dictionary <string, BlendShapeVertexData>();

            MeshComponents meshComponents        = MeshComponents.none;
            int            subMeshCount          = FindTargetSubMeshCount(sources);
            var            subMeshTriangleLength = new int[subMeshCount];

            AnalyzeSources(sources, subMeshTriangleLength, ref vertexCount, ref bindPoseCount, ref transformHierarchyCount, ref meshComponents);

            if (!blendShapeSettings.ignoreBlendShapes)
            {
                AnalyzeBlendShapeSources(sources, blendShapeSettings, ref meshComponents, out blendShapeNames);
            }

            int[][] submeshTriangles = new int[subMeshCount][];
            for (int i = 0; i < subMeshTriangleLength.Length; i++)
            {
                submeshTriangles[i]      = target.GetSubmeshBuffer(subMeshTriangleLength[i], i);
                subMeshTriangleLength[i] = 0;
            }

            bool has_normals     = (meshComponents & MeshComponents.has_normals) != MeshComponents.none;
            bool has_tangents    = (meshComponents & MeshComponents.has_tangents) != MeshComponents.none;
            bool has_uv          = (meshComponents & MeshComponents.has_uv) != MeshComponents.none;
            bool has_uv2         = (meshComponents & MeshComponents.has_uv2) != MeshComponents.none;
            bool has_uv3         = (meshComponents & MeshComponents.has_uv3) != MeshComponents.none;
            bool has_uv4         = (meshComponents & MeshComponents.has_uv4) != MeshComponents.none;
            bool has_colors32    = (meshComponents & MeshComponents.has_colors32) != MeshComponents.none;
            bool has_blendShapes = (meshComponents & MeshComponents.has_blendShapes) != MeshComponents.none;

            if (blendShapeSettings.ignoreBlendShapes)
            {
                has_blendShapes = false;
            }
            bool has_clothSkinning = (meshComponents & MeshComponents.has_clothSkinning) != MeshComponents.none;

#if UNITY_2019_3_OR_NEWER
            if (nativeBoneWeights.Length < vertexCount)
            {
                if (nativeBoneWeights.IsCreated)
                {
                    nativeBoneWeights.Dispose();
                }

                nativeBoneWeights = new NativeArray <BoneWeight>(vertexCount, Allocator.Persistent);
            }
#else
            BoneWeight[] boneWeights = EnsureArrayLength(target.unityBoneWeights, vertexCount);
#endif
            Vector3[]                  vertices           = EnsureArrayLength(target.vertices, vertexCount);
            Vector3[]                  normals            = has_normals ? EnsureArrayLength(target.normals, vertexCount) : null;
            Vector4[]                  tangents           = has_tangents ? EnsureArrayLength(target.tangents, vertexCount) : null;
            Vector2[]                  uv                 = has_uv ? EnsureArrayLength(target.uv, vertexCount) : null;
            Vector2[]                  uv2                = has_uv2 ? EnsureArrayLength(target.uv2, vertexCount) : null;
            Vector2[]                  uv3                = has_uv3 ? EnsureArrayLength(target.uv3, vertexCount) : null;
            Vector2[]                  uv4                = has_uv4 ? EnsureArrayLength(target.uv4, vertexCount) : null;
            Color32[]                  colors32           = has_colors32 ? EnsureArrayLength(target.colors32, vertexCount) : null;
            UMABlendShape[]            blendShapes        = has_blendShapes ? new UMABlendShape[blendShapeNames.Keys.Count] : null;
            UMATransform[]             umaTransforms      = EnsureArrayLength(target.umaBones, transformHierarchyCount);
            ClothSkinningCoefficient[] clothSkinning      = has_clothSkinning ? EnsureArrayLength(target.clothSkinning, vertexCount) : null;
            Dictionary <Vector3, int>  clothVertices      = has_clothSkinning ? new Dictionary <Vector3, int>(vertexCount) : null;
            Dictionary <Vector3, int>  localClothVertices = has_clothSkinning ? new Dictionary <Vector3, int>(vertexCount) : null;

            InitializeBlendShapeData(ref vertexCount, blendShapeNames, blendShapes);

            int boneCount = 0;
            foreach (var source in sources)
            {
                MergeSortedTransforms(umaTransforms, ref boneCount, source.meshData.umaBones);
            }
            int vertexIndex = 0;

            if (bonesCollection == null)
            {
                bonesCollection = new Dictionary <int, BoneIndexEntry>(boneCount);
            }
            else
            {
                bonesCollection.Clear();
            }
            if (bindPoses == null)
            {
                bindPoses = new List <Matrix4x4>(bindPoseCount);
            }
            else
            {
                bindPoses.Clear();
            }
            if (bonesList == null)
            {
                bonesList = new List <int>(boneCount);
            }
            else
            {
                bonesList.Clear();
            }

            foreach (var source in sources)
            {
                int sourceVertexCount = source.meshData.vertices.Length;
#if UNITY_2019_3_OR_NEWER
                BuildBoneWeights(source.meshData.boneWeights, 0, nativeBoneWeights, vertexIndex, sourceVertexCount, source.meshData.boneNameHashes, source.meshData.bindPoses, bonesCollection, bindPoses, bonesList);
#else
                BuildBoneWeights(source.meshData.boneWeights, 0, boneWeights, vertexIndex, sourceVertexCount, source.meshData.boneNameHashes, source.meshData.bindPoses, bonesCollection, bindPoses, bonesList);
#endif
                Array.Copy(source.meshData.vertices, 0, vertices, vertexIndex, sourceVertexCount);

                if (has_normals)
                {
                    if (source.meshData.normals != null && source.meshData.normals.Length > 0)
                    {
                        Array.Copy(source.meshData.normals, 0, normals, vertexIndex, sourceVertexCount);
                    }
                    else
                    {
                        FillArray(tangents, vertexIndex, sourceVertexCount, Vector3.zero);
                    }
                }
                if (has_tangents)
                {
                    if (source.meshData.tangents != null && source.meshData.tangents.Length > 0)
                    {
                        Array.Copy(source.meshData.tangents, 0, tangents, vertexIndex, sourceVertexCount);
                    }
                    else
                    {
                        FillArray(tangents, vertexIndex, sourceVertexCount, Vector4.zero);
                    }
                }
                if (has_uv)
                {
                    if (source.meshData.uv != null && source.meshData.uv.Length >= sourceVertexCount)
                    {
                        Array.Copy(source.meshData.uv, 0, uv, vertexIndex, sourceVertexCount);
                    }
                    else
                    {
                        FillArray(uv, vertexIndex, sourceVertexCount, Vector4.zero);
                    }
                }
                if (has_uv2)
                {
                    if (source.meshData.uv2 != null && source.meshData.uv2.Length >= sourceVertexCount)
                    {
                        Array.Copy(source.meshData.uv2, 0, uv2, vertexIndex, sourceVertexCount);
                    }
                    else
                    {
                        FillArray(uv2, vertexIndex, sourceVertexCount, Vector4.zero);
                    }
                }
                if (has_uv3)
                {
                    if (source.meshData.uv3 != null && source.meshData.uv3.Length >= sourceVertexCount)
                    {
                        Array.Copy(source.meshData.uv3, 0, uv3, vertexIndex, sourceVertexCount);
                    }
                    else
                    {
                        FillArray(uv3, vertexIndex, sourceVertexCount, Vector4.zero);
                    }
                }
                if (has_uv4)
                {
                    if (source.meshData.uv4 != null && source.meshData.uv4.Length >= sourceVertexCount)
                    {
                        Array.Copy(source.meshData.uv4, 0, uv4, vertexIndex, sourceVertexCount);
                    }
                    else
                    {
                        FillArray(uv4, vertexIndex, sourceVertexCount, Vector4.zero);
                    }
                }

                if (has_colors32)
                {
                    if (source.meshData.colors32 != null && source.meshData.colors32.Length > 0)
                    {
                        Array.Copy(source.meshData.colors32, 0, colors32, vertexIndex, sourceVertexCount);
                    }
                    else
                    {
                        Color32 white32 = Color.white;
                        FillArray(colors32, vertexIndex, sourceVertexCount, white32);
                    }
                }

                if (has_blendShapes)
                {
                    if (source.meshData.blendShapes != null && source.meshData.blendShapes.Length > 0)
                    {
                        int sourceBlendShapeLength = source.meshData.blendShapes.Length;
                        for (int shapeIndex = 0; shapeIndex < sourceBlendShapeLength; shapeIndex++)
                        {
                            string shapeName = source.meshData.blendShapes[shapeIndex].shapeName;

                            //If we aren't loading all blendshapes and we don't find the blendshape name in the list of explicit blendshapes to combine, then skip to the next one.
                            if (!blendShapeSettings.loadAllBlendShapes && !blendShapeSettings.blendShapes.ContainsKey(shapeName))
                            {
                                continue;
                            }

                            #region BlendShape Baking
                            if (BakeBlendShape(blendShapeSettings.blendShapes, source.meshData.blendShapes[shapeIndex], ref vertexIndex, vertices, normals, tangents, has_normals, has_tangents))
                            {
                                continue;                                 //If we baked this blendshape, then continue to the next one and skip adding the regular blendshape.
                            }
                            #endregion

                            //If our dictionary contains the shape name, which it should
                            if (blendShapeNames.ContainsKey(shapeName))
                            {
                                UMABlendShape[] sourceBlendShapes = source.meshData.blendShapes;
                                int             i = blendShapeNames[shapeName].index;

                                if (blendShapes[i].frames.Length != sourceBlendShapes[shapeIndex].frames.Length)
                                {
                                    if (Debug.isDebugBuild)
                                    {
                                        Debug.LogError("SkinnedMeshCombiner: mesh blendShape frame counts don't match!");
                                    }
                                    break;
                                }

                                for (int frameIndex = 0; frameIndex < sourceBlendShapes[shapeIndex].frames.Length; frameIndex++)
                                {
                                    Array.Copy(sourceBlendShapes[shapeIndex].frames[frameIndex].deltaVertices, 0, blendShapes[i].frames[frameIndex].deltaVertices, vertexIndex, sourceVertexCount);

                                    Vector3[] sourceDeltaNormals  = sourceBlendShapes[shapeIndex].frames[frameIndex].deltaNormals;
                                    Vector3[] sourceDeltaTangents = sourceBlendShapes[shapeIndex].frames[frameIndex].deltaTangents;

                                    //if out dictionary says at least one source has normals or tangents and the current source has normals or tangents then copy them.
                                    if (blendShapeNames[shapeName].hasNormals && sourceDeltaNormals.Length > 0)
                                    {
                                        Array.Copy(sourceDeltaNormals, 0, blendShapes[i].frames[frameIndex].deltaNormals, vertexIndex, sourceVertexCount);
                                    }

                                    if (blendShapeNames[shapeName].hasTangents && sourceDeltaTangents.Length > 0)
                                    {
                                        Array.Copy(sourceDeltaTangents, 0, blendShapes[i].frames[frameIndex].deltaTangents, vertexIndex, sourceVertexCount);
                                    }
                                }
                            }
                            else
                            {
                                if (Debug.isDebugBuild)
                                {
                                    Debug.LogError("BlendShape " + shapeName + " not found in dictionary!");
                                }
                            }
                        }
                    }
                }
                if (has_clothSkinning)
                {
                    localClothVertices.Clear();
                    if (source.meshData.clothSkinningSerialized != null && source.meshData.clothSkinningSerialized.Length > 0)
                    {
                        for (int i = 0; i < source.meshData.vertexCount; i++)
                        {
                            var vertice = source.meshData.vertices[i];
                            if (!localClothVertices.ContainsKey(vertice))
                            {
                                int localCount = localClothVertices.Count;
                                localClothVertices.Add(vertice, localCount);
                                if (!clothVertices.ContainsKey(vertice))
                                {
                                    ConvertData(ref source.meshData.clothSkinningSerialized[localCount], ref clothSkinning[clothVertices.Count]);
                                    clothVertices.Add(vertice, clothVertices.Count);
                                }
                                else
                                {
                                    ConvertData(ref source.meshData.clothSkinningSerialized[localCount], ref clothSkinning[clothVertices[vertice]]);
                                }
                            }
                        }
                    }
                    else
                    {
                        for (int i = 0; i < source.meshData.vertexCount; i++)
                        {
                            var vertice = source.meshData.vertices[i];
                            if (!clothVertices.ContainsKey(vertice))
                            {
                                clothSkinning[clothVertices.Count].maxDistance             = 0;
                                clothSkinning[clothVertices.Count].collisionSphereDistance = float.MaxValue;
                                clothVertices.Add(vertice, clothVertices.Count);
                                localClothVertices.Add(vertice, clothVertices.Count);
                            }
                        }
                    }
                }

                for (int i = 0; i < source.meshData.subMeshCount; i++)
                {
                    if (source.targetSubmeshIndices[i] >= 0)
                    {
                        int[] subTriangles   = source.meshData.submeshes[i].triangles;
                        int   triangleLength = subTriangles.Length;
                        int   destMesh       = source.targetSubmeshIndices[i];

                        if (source.triangleMask == null)
                        {
                            CopyIntArrayAdd(subTriangles, 0, submeshTriangles[destMesh], subMeshTriangleLength[destMesh], triangleLength, vertexIndex);
                            subMeshTriangleLength[destMesh] += triangleLength;
                        }
                        else
                        {
                            MaskedCopyIntArrayAdd(subTriangles, 0, submeshTriangles[destMesh], subMeshTriangleLength[destMesh], triangleLength, vertexIndex, source.triangleMask[i]);
                            subMeshTriangleLength[destMesh] += (triangleLength - (UMAUtils.GetCardinality(source.triangleMask[i]) * 3));
                        }
                    }
                }

                vertexIndex += sourceVertexCount;
            }

            if (vertexCount != vertexIndex)
            {
                if (Debug.isDebugBuild)
                {
                    Debug.LogError("Combined vertices size didn't match precomputed value!");
                }
            }

            // fill in new values.
            target.vertexCount = vertexCount;
            target.vertices    = vertices;
#if UNITY_2019_3_OR_NEWER
            target.unityBoneWeights = nativeBoneWeights.GetSubArray(0, vertexCount).ToArray();
#else
            target.unityBoneWeights = boneWeights;
#endif
            target.bindPoses = bindPoses.ToArray();
            target.normals   = normals;
            target.tangents  = tangents;
            target.uv        = uv;
            target.uv2       = uv2;
            target.uv3       = uv3;
            target.uv4       = uv4;
            target.colors32  = colors32;

            if (has_blendShapes)
            {
                target.blendShapes = blendShapes;
            }

            if (has_clothSkinning)
            {
                Array.Resize(ref clothSkinning, clothVertices.Count);
            }
            target.clothSkinning = clothSkinning;

            target.subMeshCount = subMeshCount;
            target.submeshes    = new SubMeshTriangles[subMeshCount];
            target.umaBones     = umaTransforms;
            target.umaBoneCount = boneCount;
            for (int i = 0; i < subMeshCount; i++)
            {
                target.submeshes[i].triangles = submeshTriangles[i];
            }
            target.boneNameHashes = bonesList.ToArray();
        }
コード例 #2
0
        private static void AnalyzeBlendShapeSources(CombineInstance[] sources, BlendShapeSettings blendShapeSettings, ref MeshComponents meshComponents, out Dictionary <string, BlendShapeVertexData> blendShapeNames)
        {
            blendShapeNames = new Dictionary <string, BlendShapeVertexData>();

            if (blendShapeSettings.ignoreBlendShapes)
            {
                return;
            }

            int bakedCount = 0;

            foreach (var source in sources)
            {
                //If we find a blendshape on this mesh then lets add it to the blendShapeNames hash to get all the unique names
                if (source.meshData.blendShapes == null)
                {
                    continue;
                }

                if (source.meshData.blendShapes.Length == 0)
                {
                    continue;
                }

                for (int shapeIndex = 0; shapeIndex < source.meshData.blendShapes.Length; shapeIndex++)
                {
                    string shapeName = source.meshData.blendShapes[shapeIndex].shapeName;

                    //if we are baking this blendshape then skip and don't add to the blendshape names.
                    BlendShapeData data;
                    if (blendShapeSettings.blendShapes.TryGetValue(shapeName, out data))
                    {
                        if (data.isBaked)
                        {
                            bakedCount++;
                            continue;
                        }
                    }

                    if (!blendShapeNames.ContainsKey(shapeName))
                    {
                        BlendShapeVertexData newData = new BlendShapeVertexData();
                        blendShapeNames.Add(shapeName, newData);
                    }

                    blendShapeNames[shapeName].hasNormals  |= source.meshData.blendShapes[shapeIndex].frames[0].HasNormals();
                    blendShapeNames[shapeName].hasTangents |= source.meshData.blendShapes[shapeIndex].frames[0].HasTangents();

                    if (source.meshData.blendShapes[shapeIndex].frames.Length > blendShapeNames[shapeName].frameCount)
                    {
                        blendShapeNames[shapeName].frameCount   = source.meshData.blendShapes[shapeIndex].frames.Length;
                        blendShapeNames[shapeName].frameWeights = new float[blendShapeNames[shapeName].frameCount];

                        for (int i = 0; i < blendShapeNames[shapeName].frameCount; i++)
                        {
                            //technically two sources could have different frame weights for the same blendshape, but then thats a problem with the source.
                            blendShapeNames[shapeName].frameWeights[i] = source.meshData.blendShapes[shapeIndex].frames[i].frameWeight;
                        }
                    }
                }
            }

            //If our blendshape hash has at least 1 name, then we have a blendshape!
            if (blendShapeNames.Count > 0 || bakedCount > 0)
            {
                meshComponents |= MeshComponents.has_blendShapes;
            }
        }