/// <summary> /// Releases the static buffers. /// </summary> public void ReleaseSharedBuffers() { if (OwnSharedBuffers()) { gVertices.SetActiveSize(0); vertices = null; gNormals.SetActiveSize(0); normals = null; gTangents.SetActiveSize(0); tangents = null; gUV.SetActiveSize(0); uv = null; gUV2.SetActiveSize(0); uv2 = null; gUV3.SetActiveSize(0); uv3 = null; gUV4.SetActiveSize(0); uv4 = null; gColors32.SetActiveSize(0); colors32 = null; for (int i = 0; i < gSubmeshTris.Length; i++) { gSubmeshTriIndices[i] = UNUSED_SUBMESH; gSubmeshTris[i].SetActiveSize(0); } boneWeights = null; unityBoneWeights = null; bufferLockOwner = null; } }
public void InitializeFromMeshData(UMAMeshData meshData) { if (meshData == null) { if (Debug.isDebugBuild) { Debug.LogError("InitializeFromMeshData: meshData is null!"); } return; } _sharedMesh = new Mesh(); #if UMA_32BITBUFFERS _sharedMesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; #endif _sharedMesh.subMeshCount = meshData.subMeshCount; _sharedMesh.vertices = meshData.vertices; _sharedMesh.normals = meshData.normals; _sharedMesh.tangents = meshData.tangents; _sharedMesh.uv = meshData.uv; _sharedMesh.uv2 = meshData.uv2; _sharedMesh.uv3 = meshData.uv3; _sharedMesh.uv4 = meshData.uv4; _sharedMesh.colors32 = meshData.colors32; for (int i = 0; i < meshData.subMeshCount; i++) { _sharedMesh.SetTriangles(meshData.submeshes[i].triangles, i); } Initialize(); }
public void UpdateOcclusionMesh(UMAMeshData meshData, float offset, Vector3 pos, Vector3 rot, Vector3 s) { //Let's call CreateOcclusionMesh to reset it. CreateOcclusionMesh(meshData); UpdateOcclusionMesh(offset, pos, rot, s); }
protected void RecalculateUV(UMAMeshData umaMesh) { int idx = 0; //Handle Atlassed Verts for (int materialIndex = 0; materialIndex < umaData.generatedMaterials.materials.Count; materialIndex++) { var generatedMaterial = umaData.generatedMaterials.materials[materialIndex]; if (generatedMaterial.umaMaterial.materialType != UMAMaterial.MaterialType.Atlas) { continue; } for (int materialDefinitionIndex = 0; materialDefinitionIndex < generatedMaterial.materialFragments.Count; materialDefinitionIndex++) { var fragment = generatedMaterial.materialFragments[materialDefinitionIndex]; var tempAtlasRect = fragment.atlasRegion; int vertexCount = fragment.slotData.asset.meshData.vertices.Length; float atlasXMin = tempAtlasRect.xMin / atlasResolution; float atlasXMax = tempAtlasRect.xMax / atlasResolution; float atlasXRange = atlasXMax - atlasXMin; float atlasYMin = tempAtlasRect.yMin / atlasResolution; float atlasYMax = tempAtlasRect.yMax / atlasResolution; float atlasYRange = atlasYMax - atlasYMin; while (vertexCount-- > 0) { umaMesh.uv[idx].x = atlasXMin + atlasXRange * umaMesh.uv[idx].x; umaMesh.uv[idx].y = atlasYMin + atlasYRange * umaMesh.uv[idx].y; idx++; } } } }
public void InitializeFromMeshData(UMAMeshData meshData) { if (meshData == null) { if (Debug.isDebugBuild) { Debug.LogError("InitializeFromMeshData: meshData is null!"); } return; } _sharedMesh = new Mesh(); #if UMA_32BITBUFFERS _sharedMesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; #endif _sharedMesh.subMeshCount = 1; // we're only copying the current submesh _sharedMesh.vertices = meshData.vertices; _sharedMesh.normals = meshData.normals; _sharedMesh.tangents = meshData.tangents; _sharedMesh.uv = meshData.uv; _sharedMesh.uv2 = meshData.uv2; _sharedMesh.uv3 = meshData.uv3; _sharedMesh.uv4 = meshData.uv4; _sharedMesh.colors32 = meshData.colors32; _sharedMesh.SetTriangles(meshData.submeshes[meshAsset.asset.subMeshIndex].triangles, 0); Initialize(); }
public void InitializeFromMeshData(UMAMeshData meshData) { if (meshData == null) { Debug.LogError("InitializeFromMeshData: meshData is null!"); return; } _sharedMesh = new Mesh(); _sharedMesh.subMeshCount = meshData.subMeshCount; _sharedMesh.vertices = meshData.vertices; _sharedMesh.normals = meshData.normals; _sharedMesh.tangents = meshData.tangents; _sharedMesh.uv = meshData.uv; _sharedMesh.uv2 = meshData.uv2; _sharedMesh.uv3 = meshData.uv3; _sharedMesh.uv4 = meshData.uv4; _sharedMesh.colors32 = meshData.colors32; for (int i = 0; i < meshData.subMeshCount; i++) { _sharedMesh.SetTriangles(meshData.submeshes[i].triangles, i); } Initialize(); }
public void CreateOcclusionMesh(UMAMeshData meshData) { if (meshData == null) { return; } ; if (_occlusionMesh == null) { _occlusionMesh = new Mesh(); } else { _occlusionMesh.Clear(); } _occlusionMesh.subMeshCount = meshData.subMeshCount; _occlusionMesh.vertices = meshData.vertices; _occlusionMesh.normals = meshData.normals; _occlusionMesh.tangents = meshData.tangents; _occlusionMesh.uv = meshData.uv; _occlusionMesh.uv2 = meshData.uv2; _occlusionMesh.uv3 = meshData.uv3; _occlusionMesh.uv4 = meshData.uv4; _occlusionMesh.colors32 = meshData.colors32; _occlusionMesh.triangles = new int[0]; _occlusionMesh.subMeshCount = meshData.subMeshCount; for (int i = 0; i < meshData.subMeshCount; i++) { occlusionMesh.SetTriangles(meshData.submeshes[i].triangles, i); } }
public void UpdateMeshData(SkinnedMeshRenderer meshRenderer) { meshData = new UMAMeshData(); meshData.RetrieveDataFromUnityMesh(meshRenderer); #if UNITY_EDITOR UnityEditor.EditorUtility.SetDirty(this); #endif }
public static UMAMeshData ShallowInstanceMesh(UMAMeshData source, BitArray[] triangleMask = null) { var target = new UMAMeshData(); target.bindPoses = source.bindPoses; target.boneNameHashes = source.boneNameHashes; target.unityBoneWeights = UMABoneWeight.Convert(source.boneWeights); target.colors32 = source.colors32; target.normals = source.normals; target.rootBoneHash = source.rootBoneHash; target.subMeshCount = source.subMeshCount; target.tangents = source.tangents; target.umaBoneCount = source.umaBoneCount; target.umaBones = source.umaBones; target.uv = source.uv; target.uv2 = source.uv2; target.uv3 = source.uv3; target.uv4 = source.uv4; target.vertexCount = source.vertexCount; target.vertices = source.vertices; target.blendShapes = source.blendShapes; if (triangleMask != null) { target.submeshes = new SubMeshTriangles[source.subMeshCount]; for (int i = 0; i < source.subMeshCount; i++) { int sourceLength = source.submeshes[i].triangles.Length; int triangleLength = sourceLength - (UMAUtils.GetCardinality(triangleMask[i]) * 3); int[] destTriangles = new int[triangleLength]; MaskedCopyIntArrayAdd(source.submeshes[i].triangles, 0, destTriangles, 0, sourceLength, 0, triangleMask[i]); target.submeshes[i].triangles = destTriangles; } } else { target.submeshes = source.submeshes; } if (source.clothSkinningSerialized != null && source.clothSkinningSerialized.Length != 0) { target.clothSkinning = new ClothSkinningCoefficient[source.clothSkinningSerialized.Length]; for (int i = 0; i < source.clothSkinningSerialized.Length; i++) { ConvertData(ref source.clothSkinningSerialized[i], ref target.clothSkinning[i]); } } else { target.clothSkinning = null; } return(target); }
public void Assign(SlotDataAsset source) { slotName = source.slotName; nameHash = source.nameHash; material = source.material; overlayScale = source.overlayScale; animatedBoneNames = source.animatedBoneNames; animatedBoneHashes = source.animatedBoneHashes; meshData = source.meshData; subMeshIndex = source.subMeshIndex; slotGroup = source.slotGroup; tags = source.tags; }
/// <summary> /// Updates the UMA mesh and skeleton to match current slots. /// </summary> /// <param name="updatedAtlas">If set to <c>true</c> atlas has changed.</param> /// <param name="umaData">UMA data.</param> /// <param name="atlasResolution">Atlas resolution.</param> public override void UpdateUMAMesh(bool updatedAtlas, UMAData umaData, int atlasResolution) { this.umaData = umaData; this.atlasResolution = atlasResolution; combinedMeshList = new List <SkinnedMeshCombiner.CombineInstance>(umaData.umaRecipe.slotDataList.Length); combinedMaterialList = new List <Material>(); BuildCombineInstances(); EnsureUMADataSetup(umaData); umaData.skeleton.BeginSkeletonUpdate(); UMAMeshData umaMesh = new UMAMeshData(); umaMesh.ClaimSharedBuffers(); SkinnedMeshCombiner.CombineMeshes(umaMesh, combinedMeshList.ToArray(), umaData.ignoreBlendShapes); if (updatedAtlas) { RecalculateUV(umaMesh); } umaMesh.ApplyDataToUnityMesh(umaData.myRenderer, umaData.skeleton); umaMesh.ReleaseSharedBuffers(); umaData.umaRecipe.ClearDNAConverters(); for (int i = 0; i < umaData.umaRecipe.slotDataList.Length; i++) { SlotData slotData = umaData.umaRecipe.slotDataList[i]; if (slotData != null) { // umaData.EnsureBoneData(slotData.umaBoneData, slotData.animatedBones, boneMap); umaData.umaRecipe.AddDNAUpdater(slotData.asset.slotDNA); } } umaData.myRenderer.quality = SkinQuality.Bone4; //umaData.myRenderer.useLightProbes = true; var materials = combinedMaterialList.ToArray(); umaData.myRenderer.sharedMaterials = materials; //umaData.myRenderer.sharedMesh.RecalculateBounds(); umaData.myRenderer.sharedMesh.name = "UMAMesh"; umaData.firstBake = false; //FireSlotAtlasNotification(umaData, materials); }
/*private static void BuildBoneWeights(NativeArray<BoneWeight1> source, NativeArray<BoneWeight1> dest, int destIndex, int destBoneweightIndex, int count, int[] bones, Matrix4x4[] bindPoses, Dictionary<int, BoneIndexEntry> bonesCollection, List<Matrix4x4> bindPosesList, List<int> bonesList) * { * int[] boneMapping = new int[bones.Length]; * * for (int i = 0; i < boneMapping.Length; i++) * { * boneMapping[i] = TranslateBoneIndex(i, bones, bindPoses, bonesCollection, bindPosesList, bonesList); * } * * NativeArray<BoneWeight1>.Copy(source, 0, dest, destBoneweightIndex, source.Length); * BoneWeight1 b = new BoneWeight1(); * for (int i=0;i<source.Length;i++) * { * b.boneIndex = boneMapping[source[i].boneIndex]; * b.weight = source[i].weight; * * dest[i + destBoneweightIndex] = b; * } * } */ private static void BuildBoneWeights(UMAMeshData data, NativeArray <BoneWeight1> dest, NativeArray <byte> destBonesPerVertex, int destIndex, int destBoneweightIndex, int count, int[] bones, Matrix4x4[] bindPoses, Dictionary <int, BoneIndexEntry> bonesCollection, List <Matrix4x4> bindPosesList, List <int> bonesList) { int[] boneMapping = new int[bones.Length]; for (int i = 0; i < boneMapping.Length; i++) { boneMapping[i] = TranslateBoneIndex(i, bones, bindPoses, bonesCollection, bindPosesList, bonesList); } #if USE_NATIVE_ARRAYS NativeArray <byte> sourceBonesPerIndex = data.unityBonesPerVertex; int sourcecount = sourceBonesPerIndex.Length; int destcount = destBonesPerVertex.Length; // should be 0. NativeArray <byte> .Copy(sourceBonesPerIndex, 0, destBonesPerVertex, destIndex, sourceBonesPerIndex.Length); NativeArray <BoneWeight1> .Copy(data.unityBoneWeights, 0, dest, destBoneweightIndex, data.unityBoneWeights.Length); BoneWeight1 b = new BoneWeight1(); for (int i = 0; i < data.unityBoneWeights.Length; i++) { b.boneIndex = boneMapping[data.unityBoneWeights[i].boneIndex]; b.weight = data.unityBoneWeights[i].weight; dest[i + destBoneweightIndex] = b; } #else NativeArray <byte> .Copy(data.ManagedBonesPerVertex, 0, destBonesPerVertex, destIndex, data.ManagedBonesPerVertex.Length); NativeArray <BoneWeight1> .Copy(data.ManagedBoneWeights, 0, dest, destBoneweightIndex, data.ManagedBoneWeights.Length); BoneWeight1 b = new BoneWeight1(); for (int i = 0; i < data.ManagedBoneWeights.Length; i++) { b.boneIndex = boneMapping[data.ManagedBoneWeights[i].boneIndex]; b.weight = data.ManagedBoneWeights[i].weight; dest[i + destBoneweightIndex] = b; } #endif }
public void CreateOcclusionMesh(UMAMeshData meshData) { if (meshData == null) { return; } ; if (_occlusionMesh == null) { _occlusionMesh = new Mesh(); #if UMA_32BITBUFFERS _occlusionMesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; #endif } else { _occlusionMesh.Clear(); } _occlusionMesh.subMeshCount = meshData.subMeshCount; _occlusionMesh.vertices = meshData.vertices; _occlusionMesh.normals = meshData.normals; _occlusionMesh.tangents = meshData.tangents; _occlusionMesh.uv = meshData.uv; _occlusionMesh.uv2 = meshData.uv2; _occlusionMesh.uv3 = meshData.uv3; _occlusionMesh.uv4 = meshData.uv4; _occlusionMesh.colors32 = meshData.colors32; _occlusionMesh.triangles = new int[0]; _occlusionMesh.subMeshCount = meshData.subMeshCount; for (int i = 0; i < meshData.subMeshCount; i++) { occlusionMesh.SetTriangles(meshData.submeshes[i].triangles, i); } }
public static UMAMeshData ShallowInstanceMesh(UMAMeshData source) { var target = new UMAMeshData(); target.bindPoses = source.bindPoses; target.boneNameHashes = source.boneNameHashes; target.unityBoneWeights = UMABoneWeight.Convert(source.boneWeights); target.colors32 = source.colors32; target.normals = source.normals; target.rootBoneHash = source.rootBoneHash; target.subMeshCount = source.subMeshCount; target.submeshes = source.submeshes; target.tangents = source.tangents; target.umaBoneCount = source.umaBoneCount; target.umaBones = source.umaBones; target.uv = source.uv; target.uv2 = source.uv2; target.uv3 = source.uv3; target.uv4 = source.uv4; target.vertexCount = source.vertexCount; target.vertices = source.vertices; target.blendShapes = source.blendShapes; if (source.clothSkinningSerialized != null && source.clothSkinningSerialized.Length != 0) { target.clothSkinning = new ClothSkinningCoefficient[source.clothSkinningSerialized.Length]; for (int i = 0; i < source.clothSkinningSerialized.Length; i++) { ConvertData(ref source.clothSkinningSerialized[i], ref target.clothSkinning[i]); } } else { target.clothSkinning = null; } return(target); }
/// <summary> /// Creates a deep copy of an UMAMeshData object. /// </summary> /// <returns>The new copy of the UMAMeshData</returns> public UMAMeshData DeepCopy() { UMAMeshData newMeshData = new UMAMeshData(); if (bindPoses != null) { newMeshData.bindPoses = new Matrix4x4[bindPoses.Length]; Array.Copy(bindPoses, newMeshData.bindPoses, bindPoses.Length); } if (boneWeights != null) { newMeshData.boneWeights = new UMABoneWeight[boneWeights.Length]; Array.Copy(boneWeights, newMeshData.boneWeights, boneWeights.Length); } if (unityBoneWeights != null) { newMeshData.unityBoneWeights = new BoneWeight[unityBoneWeights.Length]; Array.Copy(unityBoneWeights, newMeshData.unityBoneWeights, unityBoneWeights.Length); } if (vertices != null) { newMeshData.vertices = new Vector3[vertices.Length]; Array.Copy(vertices, newMeshData.vertices, vertices.Length); } if (normals != null) { newMeshData.normals = new Vector3[normals.Length]; Array.Copy(normals, newMeshData.normals, normals.Length); } if (tangents != null) { newMeshData.tangents = new Vector4[tangents.Length]; Array.Copy(tangents, newMeshData.tangents, tangents.Length); } if (colors32 != null) { newMeshData.colors32 = new Color32[colors32.Length]; Array.Copy(colors32, newMeshData.colors32, colors32.Length); } if (uv != null) { newMeshData.uv = new Vector2[uv.Length]; Array.Copy(uv, newMeshData.uv, uv.Length); } if (uv2 != null) { newMeshData.uv2 = new Vector2[uv2.Length]; Array.Copy(uv2, newMeshData.uv2, uv2.Length); } if (uv3 != null) { newMeshData.uv3 = new Vector2[uv3.Length]; Array.Copy(uv3, newMeshData.uv3, uv3.Length); } if (uv4 != null) { newMeshData.uv4 = new Vector2[uv4.Length]; Array.Copy(uv4, newMeshData.uv4, uv4.Length); } if (blendShapes != null) { newMeshData.blendShapes = new UMABlendShape[blendShapes.Length]; Array.Copy(blendShapes, newMeshData.blendShapes, blendShapes.Length); } if (clothSkinning != null) { newMeshData.clothSkinning = new ClothSkinningCoefficient[clothSkinning.Length]; Array.Copy(clothSkinning, newMeshData.clothSkinning, clothSkinning.Length); } if (clothSkinningSerialized != null) { newMeshData.clothSkinningSerialized = new Vector2[clothSkinningSerialized.Length]; Array.Copy(clothSkinningSerialized, newMeshData.clothSkinningSerialized, clothSkinningSerialized.Length); } if (submeshes != null) { newMeshData.submeshes = new SubMeshTriangles[submeshes.Length]; Array.Copy(submeshes, newMeshData.submeshes, submeshes.Length); } if (bones != null) { newMeshData.bones = bones.Clone() as Transform[]; } if (rootBone != null) { newMeshData.rootBone = rootBone; } if (umaBones != null) { newMeshData.umaBones = new UMATransform[umaBones.Length]; Array.Copy(umaBones, newMeshData.umaBones, umaBones.Length); } newMeshData.umaBoneCount = umaBoneCount; newMeshData.rootBoneHash = rootBoneHash; if (boneNameHashes != null) { newMeshData.boneNameHashes = new int[boneNameHashes.Length]; Array.Copy(boneNameHashes, newMeshData.boneNameHashes, boneNameHashes.Length); } newMeshData.subMeshCount = subMeshCount; newMeshData.vertexCount = vertexCount; newMeshData.RootBoneName = RootBoneName; return(newMeshData); }
public bool Equals(UMAMeshData other) { return(this == other); }
protected void RecalculateUV(UMAMeshData umaMesh) { int idx = 0; //Handle Atlassed Verts for (int materialIndex = 0; materialIndex < umaData.generatedMaterials.materials.Count; materialIndex++) { var generatedMaterial = umaData.generatedMaterials.materials[materialIndex]; if (generatedMaterial.rendererAsset != umaData.GetRendererAsset(currentRendererIndex)) { continue; } if (generatedMaterial.umaMaterial.materialType != UMAMaterial.MaterialType.Atlas) { var fragment = generatedMaterial.materialFragments[0]; int vertexCount = fragment.slotData.asset.meshData.vertices.Length; idx += vertexCount; continue; } for (int materialDefinitionIndex = 0; materialDefinitionIndex < generatedMaterial.materialFragments.Count; materialDefinitionIndex++) { var fragment = generatedMaterial.materialFragments[materialDefinitionIndex]; var tempAtlasRect = fragment.atlasRegion; int vertexCount = fragment.slotData.asset.meshData.vertices.Length; float atlasXMin = tempAtlasRect.xMin / atlasResolution; float atlasXMax = tempAtlasRect.xMax / atlasResolution; float atlasXRange = atlasXMax - atlasXMin; float atlasYMin = tempAtlasRect.yMin / atlasResolution; float atlasYMax = tempAtlasRect.yMax / atlasResolution; float atlasYRange = atlasYMax - atlasYMin; // code below is for UVs remap based on rel pos in the atlas if (fragment.isRectShared && fragment.slotData.useAtlasOverlay) { var foundRect = fragment.overlayList.FirstOrDefault(szname => fragment.slotData.slotName != null && szname.overlayName.Contains(fragment.slotData.slotName)); if (null != foundRect && foundRect.rect != Rect.zero) { var size = foundRect.rect.size * generatedMaterial.resolutionScale; var offsetX = foundRect.rect.x * generatedMaterial.resolutionScale.x; var offsetY = foundRect.rect.y * generatedMaterial.resolutionScale.y; atlasXMin += (offsetX / generatedMaterial.cropResolution.x); atlasXRange = size.x / generatedMaterial.cropResolution.x; atlasYMin += (offsetY / generatedMaterial.cropResolution.y); atlasYRange = size.y / generatedMaterial.cropResolution.y; } } while (vertexCount-- > 0) { umaMesh.uv[idx].x = atlasXMin + atlasXRange * umaMesh.uv[idx].x; umaMesh.uv[idx].y = atlasYMin + atlasYRange * umaMesh.uv[idx].y; idx++; } } } }
/// <summary> /// Combines a set of meshes into the target mesh. /// </summary> /// <param name="target">Target.</param> /// <param name="sources">Sources.</param> public static void CombineMeshes(UMAMeshData target, CombineInstance[] sources, bool ignoreBlendShapes = false) { int vertexCount = 0; int bindPoseCount = 0; int transformHierarchyCount = 0; int blendShapeCount = 0; MeshComponents meshComponents = MeshComponents.none; int subMeshCount = FindTargetSubMeshCount(sources); var subMeshTriangleLength = new int[subMeshCount]; AnalyzeSources(sources, subMeshTriangleLength, ref vertexCount, ref bindPoseCount, ref transformHierarchyCount, ref meshComponents, ref blendShapeCount); int[][] submeshTriangles = new int[subMeshCount][]; for (int i = 0; i < subMeshTriangleLength.Length; i++) { submeshTriangles[i] = new int[subMeshTriangleLength[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 (ignoreBlendShapes) { has_blendShapes = false; } Vector3[] vertices = EnsureArrayLength(target.vertices, vertexCount); BoneWeight[] boneWeights = EnsureArrayLength(target.unityBoneWeights, 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[blendShapeCount] : null; UMATransform[] umaTransforms = EnsureArrayLength(target.umaBones, transformHierarchyCount); 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(); } int blendShapeIndex = 0; foreach (var source in sources) { vertexCount = source.meshData.vertices.Length; BuildBoneWeights(source.meshData.boneWeights, 0, boneWeights, vertexIndex, vertexCount, source.meshData.boneNameHashes, source.meshData.bindPoses, bonesCollection, bindPoses, bonesList); Array.Copy(source.meshData.vertices, 0, vertices, vertexIndex, vertexCount); if (has_normals) { if (source.meshData.normals != null && source.meshData.normals.Length > 0) { Array.Copy(source.meshData.normals, 0, normals, vertexIndex, vertexCount); } else { FillArray(tangents, vertexIndex, vertexCount, Vector3.zero); } } if (has_tangents) { if (source.meshData.tangents != null && source.meshData.tangents.Length > 0) { Array.Copy(source.meshData.tangents, 0, tangents, vertexIndex, vertexCount); } else { FillArray(tangents, vertexIndex, vertexCount, Vector4.zero); } } if (has_uv) { if (source.meshData.uv != null && source.meshData.uv.Length >= vertexCount) { Array.Copy(source.meshData.uv, 0, uv, vertexIndex, vertexCount); } else { FillArray(uv, vertexIndex, vertexCount, Vector4.zero); } } if (has_uv2) { if (source.meshData.uv2 != null && source.meshData.uv2.Length >= vertexCount) { Array.Copy(source.meshData.uv2, 0, uv2, vertexIndex, vertexCount); } else { FillArray(uv2, vertexIndex, vertexCount, Vector4.zero); } } if (has_uv3) { if (source.meshData.uv3 != null && source.meshData.uv3.Length >= vertexCount) { Array.Copy(source.meshData.uv3, 0, uv3, vertexIndex, vertexCount); } else { FillArray(uv3, vertexIndex, vertexCount, Vector4.zero); } } if (has_uv4) { if (source.meshData.uv4 != null && source.meshData.uv4.Length >= vertexCount) { Array.Copy(source.meshData.uv4, 0, uv4, vertexIndex, vertexCount); } else { FillArray(uv4, vertexIndex, vertexCount, Vector4.zero); } } if (has_colors32) { if (source.meshData.colors32 != null && source.meshData.colors32.Length > 0) { Array.Copy(source.meshData.colors32, 0, colors32, vertexIndex, vertexCount); } else { Color32 white32 = Color.white; FillArray(colors32, vertexIndex, vertexCount, white32); } } if (has_blendShapes) { if (source.meshData.blendShapes != null && source.meshData.blendShapes.Length > 0) { for (int shapeIndex = 0; shapeIndex < source.meshData.blendShapes.Length; shapeIndex++) { bool nameAlreadyExists = false; int i = 0; //Probably this would be better with a dictionary for (i = 0; i < blendShapeIndex; i++) { if (blendShapes [i].shapeName == source.meshData.blendShapes [shapeIndex].shapeName) { nameAlreadyExists = true; break; } } if (nameAlreadyExists) //Lets add the vertices data to the existing blendShape { if (blendShapes [i].frames.Length != source.meshData.blendShapes [shapeIndex].frames.Length) { Debug.LogError("SkinnedMeshCombiner: mesh blendShape frame counts don't match!"); break; } for (int frameIndex = 0; frameIndex < source.meshData.blendShapes [shapeIndex].frames.Length; frameIndex++) { Array.Copy(source.meshData.blendShapes [shapeIndex].frames [frameIndex].deltaVertices, 0, blendShapes [i].frames [frameIndex].deltaVertices, vertexIndex, vertexCount); Array.Copy(source.meshData.blendShapes [shapeIndex].frames [frameIndex].deltaNormals, 0, blendShapes [i].frames [frameIndex].deltaNormals, vertexIndex, vertexCount); Array.Copy(source.meshData.blendShapes [shapeIndex].frames [frameIndex].deltaTangents, 0, blendShapes [i].frames [frameIndex].deltaTangents, vertexIndex, vertexCount); } } else { blendShapes [blendShapeIndex] = new UMABlendShape(); blendShapes [blendShapeIndex].shapeName = source.meshData.blendShapes [shapeIndex].shapeName; blendShapes [blendShapeIndex].frames = new UMABlendFrame[source.meshData.blendShapes [shapeIndex].frames.Length]; for (int frameIndex = 0; frameIndex < source.meshData.blendShapes [shapeIndex].frames.Length; frameIndex++) { blendShapes [blendShapeIndex].frames [frameIndex] = new UMABlendFrame(vertices.Length); blendShapes [blendShapeIndex].frames [frameIndex].frameWeight = source.meshData.blendShapes [shapeIndex].frames [frameIndex].frameWeight; Array.Copy(source.meshData.blendShapes [shapeIndex].frames [frameIndex].deltaVertices, 0, blendShapes [blendShapeIndex].frames [frameIndex].deltaVertices, vertexIndex, vertexCount); Array.Copy(source.meshData.blendShapes [shapeIndex].frames [frameIndex].deltaNormals, 0, blendShapes [blendShapeIndex].frames [frameIndex].deltaNormals, vertexIndex, vertexCount); Array.Copy(source.meshData.blendShapes [shapeIndex].frames [frameIndex].deltaTangents, 0, blendShapes [blendShapeIndex].frames [frameIndex].deltaTangents, vertexIndex, vertexCount); } blendShapeIndex++; } } } } 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]; CopyIntArrayAdd(subTriangles, 0, submeshTriangles[destMesh], subMeshTriangleLength[destMesh], triangleLength, vertexIndex); subMeshTriangleLength[destMesh] += triangleLength; } } vertexIndex += vertexCount; } vertexCount = vertexIndex; // fill in new values. target.vertexCount = vertexCount; target.vertices = vertices; target.unityBoneWeights = boneWeights; 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; } 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(); }
/// <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, UMAData.BlendShapeSettings blendShapeSettings = null) { if (blendShapeSettings == null) { blendShapeSettings = new UMAData.BlendShapeSettings(); } int vertexCount = 0; int bindPoseCount = 0; int transformHierarchyCount = 0; int blendShapeCount = 0; MeshComponents meshComponents = MeshComponents.none; int subMeshCount = FindTargetSubMeshCount(sources); var subMeshTriangleLength = new int[subMeshCount]; AnalyzeSources(sources, subMeshTriangleLength, ref vertexCount, ref bindPoseCount, ref transformHierarchyCount, ref meshComponents, ref blendShapeCount); 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; Vector3[] vertices = EnsureArrayLength(target.vertices, vertexCount); BoneWeight[] boneWeights = EnsureArrayLength(target.unityBoneWeights, 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[blendShapeCount] : 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; 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(); } int blendShapeIndex = 0; foreach (var source in sources) { int sourceVertexCount = source.meshData.vertices.Length; BuildBoneWeights(source.meshData.boneWeights, 0, boneWeights, vertexIndex, sourceVertexCount, source.meshData.boneNameHashes, source.meshData.bindPoses, bonesCollection, bindPoses, bonesList); 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) { for (int shapeIndex = 0; shapeIndex < source.meshData.blendShapes.Length; shapeIndex++) { #region BlendShape Baking if (blendShapeSettings.bakeBlendShapes != null && blendShapeSettings.bakeBlendShapes.Count > 0) { // If there are names in the bakeBlendShape dictionary and we find them in the meshData blendshape list, then lets bake them instead of adding them. UMABlendShape currentShape = source.meshData.blendShapes[shapeIndex]; if (blendShapeSettings.bakeBlendShapes.ContainsKey(currentShape.shapeName)) { float weight = blendShapeSettings.bakeBlendShapes[currentShape.shapeName] * 100.0f; if (weight <= 0f) { continue; // Baking in nothing, so skip it entirely } // Let's find the frame this weight is in int frameIndex; int prevIndex; for (frameIndex = 0; frameIndex < currentShape.frames.Length; frameIndex++) { if (currentShape.frames[frameIndex].frameWeight >= weight) { break; } } // Let's calculate the weight for the frame we're in float frameWeight = 1f; float prevWeight = 0f; bool doLerp = false; // Weight is higher than the last frame, shape is over 100% if (frameIndex >= currentShape.frames.Length) { frameIndex = currentShape.frames.Length - 1; frameWeight = (weight / currentShape.frames[frameIndex].frameWeight); } else if (frameIndex > 0) { doLerp = true; prevWeight = currentShape.frames[frameIndex - 1].frameWeight; frameWeight = ((weight - prevWeight) / (currentShape.frames[frameIndex].frameWeight - prevWeight)); prevWeight = 1f - frameWeight; } else { frameWeight = (weight / currentShape.frames[frameIndex].frameWeight); } prevIndex = frameIndex - 1; // The blend shape frames lerp between the deltas of two adjacent frames. int vertIndex = vertexIndex; for (int bakeIndex = 0; bakeIndex < currentShape.frames[frameIndex].deltaVertices.Length; bakeIndex++, vertIndex++) { // Add the current frame's deltas vertices[vertIndex] += currentShape.frames[frameIndex].deltaVertices[bakeIndex] * frameWeight; // Add in the previous frame's deltas if (doLerp) { vertices[vertIndex] += currentShape.frames[prevIndex].deltaVertices[bakeIndex] * prevWeight; } } if (has_normals) { vertIndex = vertexIndex; for (int bakeIndex = 0; bakeIndex < currentShape.frames[frameIndex].deltaNormals.Length; bakeIndex++, vertIndex++) { normals[vertIndex] += currentShape.frames[frameIndex].deltaNormals[bakeIndex] * frameWeight; if (doLerp) { normals[vertIndex] += currentShape.frames[prevIndex].deltaNormals[bakeIndex] * prevWeight; } } } if (has_tangents) { vertIndex = vertexIndex; for (int bakeIndex = 0; bakeIndex < currentShape.frames[frameIndex].deltaTangents.Length; bakeIndex++, vertIndex++) { tangents[vertIndex] += (Vector4)currentShape.frames[frameIndex].deltaTangents[bakeIndex] * frameWeight; if (doLerp) { tangents[vertIndex] += (Vector4)currentShape.frames[prevIndex].deltaTangents[bakeIndex] * prevWeight; } } } continue; // If we bake then don't perform the rest of this interation of the loop. } } #endregion bool nameAlreadyExists = false; int i = 0; //Probably this would be better with a dictionary for (i = 0; i < blendShapeIndex; i++) { if (blendShapes[i].shapeName == source.meshData.blendShapes[shapeIndex].shapeName) { nameAlreadyExists = true; break; } } if (nameAlreadyExists) //Lets add the vertices data to the existing blendShape { if (blendShapes[i].frames.Length != source.meshData.blendShapes[shapeIndex].frames.Length) { Debug.LogError("SkinnedMeshCombiner: mesh blendShape frame counts don't match!"); break; } for (int frameIndex = 0; frameIndex < source.meshData.blendShapes[shapeIndex].frames.Length; frameIndex++) { Array.Copy(source.meshData.blendShapes[shapeIndex].frames[frameIndex].deltaVertices, 0, blendShapes[i].frames[frameIndex].deltaVertices, vertexIndex, sourceVertexCount); Array.Copy(source.meshData.blendShapes[shapeIndex].frames[frameIndex].deltaNormals, 0, blendShapes[i].frames[frameIndex].deltaNormals, vertexIndex, sourceVertexCount); Array.Copy(source.meshData.blendShapes[shapeIndex].frames[frameIndex].deltaTangents, 0, blendShapes[i].frames[frameIndex].deltaTangents, vertexIndex, sourceVertexCount); } } else { blendShapes[blendShapeIndex] = new UMABlendShape(); blendShapes[blendShapeIndex].shapeName = source.meshData.blendShapes[shapeIndex].shapeName; blendShapes[blendShapeIndex].frames = new UMABlendFrame[source.meshData.blendShapes[shapeIndex].frames.Length]; for (int frameIndex = 0; frameIndex < source.meshData.blendShapes[shapeIndex].frames.Length; frameIndex++) { blendShapes[blendShapeIndex].frames[frameIndex] = new UMABlendFrame(vertexCount); blendShapes[blendShapeIndex].frames[frameIndex].frameWeight = source.meshData.blendShapes[shapeIndex].frames[frameIndex].frameWeight; Array.Copy(source.meshData.blendShapes[shapeIndex].frames[frameIndex].deltaVertices, 0, blendShapes[blendShapeIndex].frames[frameIndex].deltaVertices, vertexIndex, sourceVertexCount); Array.Copy(source.meshData.blendShapes[shapeIndex].frames[frameIndex].deltaNormals, 0, blendShapes[blendShapeIndex].frames[frameIndex].deltaNormals, vertexIndex, sourceVertexCount); Array.Copy(source.meshData.blendShapes[shapeIndex].frames[frameIndex].deltaTangents, 0, blendShapes[blendShapeIndex].frames[frameIndex].deltaTangents, vertexIndex, sourceVertexCount); } blendShapeIndex++; } } } } 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) { Debug.LogError("Combined vertices size didn't match precomputed value!"); } // fill in new values. target.vertexCount = vertexCount; target.vertices = vertices; target.unityBoneWeights = boneWeights; 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(); }
public void Initialize() { gameObject.name = "GeometrySelector"; if (_sharedMesh == null) { if (Debug.isDebugBuild) { Debug.LogWarning("GeometrySelector: Initializing with no mesh!"); } return; } if (meshAsset != null) { UMAMeshData meshData = meshAsset.asset.meshData; /* Todo: figure out how to get the races root bone orientation * Transform root = meshData.rootBone; * if (root == null) * { * SkeletonTools.RecursiveFindBone(meshData.bones[0],"Global"); * } */ if (meshData.rootBoneHash == UMAUtils.StringToHash("Global")) { gameObject.transform.localRotation = Quaternion.Euler(-90f, 0f, 0f); } } gameObject.transform.hideFlags = HideFlags.NotEditable | HideFlags.HideInInspector; if (selectedTriangles == null) { selectedTriangles = new BitArray(_sharedMesh.triangles.Length / 3); } if (!gameObject.GetComponent <MeshFilter>()) { MeshFilter meshFilter = gameObject.AddComponent <MeshFilter>(); meshFilter.mesh = _sharedMesh; meshFilter.hideFlags = HideFlags.HideInInspector; } if (!gameObject.GetComponent <MeshRenderer>()) { _meshRenderer = gameObject.AddComponent <MeshRenderer>(); _meshRenderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; _meshRenderer.receiveShadows = false; _meshRenderer.hideFlags = HideFlags.HideInInspector; } if (!gameObject.GetComponent <MeshCollider>()) { _meshCollider = gameObject.AddComponent <MeshCollider>(); _meshCollider.convex = false; _meshCollider.sharedMesh = _sharedMesh; _meshCollider.hideFlags = HideFlags.HideInInspector; } if (GraphicsSettings.renderPipelineAsset == null) { _Shader = Shader.Find("Standard"); } else { //Expand this to find shaders that work with other SRPs in the future. _Shader = Shader.Find("Unlit/Color"); } if (_Materials == null && _Shader != null) { _Materials = new Material[2]; //Selected _Materials[1] = new Material(_Shader); _Materials[1].name = "Selected"; _Materials[1].color = Color.red; //UnSelected _Materials[0] = new Material(_Shader); _Materials[0].name = "UnSelected"; _Materials[0].color = Color.gray; _sharedMesh.subMeshCount = 2; _meshRenderer.sharedMaterials = _Materials; _meshRenderer.sharedMaterials[0].hideFlags = HideFlags.HideInInspector; _meshRenderer.sharedMaterials[1].hideFlags = HideFlags.HideInInspector; } }
/// <summary> /// Updates the UMA mesh and skeleton to match current slots. /// </summary> /// <param name="updatedAtlas">If set to <c>true</c> atlas has changed.</param> /// <param name="umaData">UMA data.</param> /// <param name="atlasResolution">Atlas resolution.</param> public override void UpdateUMAMesh(bool updatedAtlas, UMAData umaData, int atlasResolution) { this.umaData = umaData; this.atlasResolution = atlasResolution; combinedMeshList = new List <SkinnedMeshCombiner.CombineInstance>(umaData.umaRecipe.slotDataList.Length); combinedMaterialList = new List <Material>(); EnsureUMADataSetup(umaData); umaData.skeleton.BeginSkeletonUpdate(); for (currentRendererIndex = 0; currentRendererIndex < umaData.generatedMaterials.rendererCount; currentRendererIndex++) { //Move umaMesh creation to with in the renderer loops //May want to make sure to set all it's buffers to null instead of creating a new UMAMeshData UMAMeshData umaMesh = new UMAMeshData(); umaMesh.ClaimSharedBuffers(); umaMesh.subMeshCount = 0; umaMesh.vertexCount = 0; combinedMeshList.Clear(); combinedMaterialList.Clear(); clothProperties = null; BuildCombineInstances(); if (combinedMeshList.Count == 1) { // fast track var tempMesh = SkinnedMeshCombiner.ShallowInstanceMesh(combinedMeshList[0].meshData); tempMesh.ApplyDataToUnityMesh(renderers[currentRendererIndex], umaData.skeleton); } else { SkinnedMeshCombiner.CombineMeshes(umaMesh, combinedMeshList.ToArray(), umaData.blendShapeSettings); if (updatedAtlas) { RecalculateUV(umaMesh); } umaMesh.ApplyDataToUnityMesh(renderers[currentRendererIndex], umaData.skeleton); } var cloth = renderers[currentRendererIndex].GetComponent <Cloth>(); if (clothProperties != null) { if (cloth != null) { clothProperties.ApplyValues(cloth); } } else { Destroy(cloth); } var materials = combinedMaterialList.ToArray(); renderers[currentRendererIndex].sharedMaterials = materials; umaMesh.ReleaseSharedBuffers(); } umaData.umaRecipe.ClearDNAConverters(); for (int i = 0; i < umaData.umaRecipe.slotDataList.Length; i++) { SlotData slotData = umaData.umaRecipe.slotDataList[i]; if (slotData != null) { umaData.umaRecipe.AddDNAUpdater(slotData.asset.slotDNA); } } umaData.firstBake = false; }
/// <summary> /// Claims the static buffers. /// </summary> /// <returns><c>true</c>, if shared buffers were claimed, <c>false</c> otherwise.</returns> public bool ClaimSharedBuffers() { if (!buffersInitialized) { buffersInitialized = true; haveBackingArrays = true; gVerticesArray = gVertices.GetBackingArray(); if (gVerticesArray == null) { haveBackingArrays = false; } gNormalsArray = gNormals.GetBackingArray(); if (gNormalsArray == null) { haveBackingArrays = false; } gTangentsArray = gTangents.GetBackingArray(); if (gTangentsArray == null) { haveBackingArrays = false; } gUVArray = gUV.GetBackingArray(); if (gUVArray == null) { haveBackingArrays = false; } gUV2Array = gUV2.GetBackingArray(); if (gUV2Array == null) { haveBackingArrays = false; } gUV3Array = gUV3.GetBackingArray(); if (gUV3Array == null) { haveBackingArrays = false; } gUV4Array = gUV4.GetBackingArray(); if (gUV4Array == null) { haveBackingArrays = false; } gColors32Array = gColors32.GetBackingArray(); if (gColors32Array == null) { haveBackingArrays = false; } gSubmeshTriIndices = new int[gSubmeshTris.Length]; gSubmeshTriArrays = new int[gSubmeshTris.Length][]; for (int i = 0; i < gSubmeshTris.Length; i++) { gSubmeshTriIndices[i] = UNUSED_SUBMESH; gSubmeshTriArrays[i] = gSubmeshTris[i].GetBackingArray(); if (gSubmeshTriArrays[i] == null) { haveBackingArrays = false; } } if (haveBackingArrays == false) { if (Debug.isDebugBuild) { Debug.LogError("Unable to access backing arrays for shared UMAMeshData!"); } } } if (!haveBackingArrays) { return(false); } if (bufferLockOwner == null) { bufferLockOwner = this; vertices = gVerticesArray; normals = gNormalsArray; tangents = gTangentsArray; uv = gUVArray; uv2 = gUV2Array; uv3 = gUV3Array; uv4 = gUV4Array; colors32 = gColors32Array; boneWeights = null; #if USE_UNSAFE_CODE unityBoneWeights = gBoneWeightsArray; #endif return(true); } if (Debug.isDebugBuild) { Debug.LogWarning("Unable to claim UMAMeshData global buffers!"); } return(false); }
/// <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(); }
/// <summary> /// Combines a set of meshes into the target mesh. /// </summary> /// <param name="target">Target.</param> /// <param name="sources">Sources.</param> public static void CombineMeshes(UMAMeshData target, CombineInstance[] sources) { int vertexCount = 0; int bindPoseCount = 0; int transformHierarchyCount = 0; MeshComponents meshComponents = MeshComponents.none; int subMeshCount = FindTargetSubMeshCount(sources); var subMeshTriangleLength = new int[subMeshCount]; AnalyzeSources(sources, subMeshTriangleLength, ref vertexCount, ref bindPoseCount, ref transformHierarchyCount, ref meshComponents); int[][] submeshTriangles = new int[subMeshCount][]; for (int i = 0; i < subMeshTriangleLength.Length; i++) { submeshTriangles[i] = new int[subMeshTriangleLength[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; #if !UNITY_4_6 bool has_uv3 = (meshComponents & MeshComponents.has_uv3) != MeshComponents.none; bool has_uv4 = (meshComponents & MeshComponents.has_uv4) != MeshComponents.none; #endif bool has_colors32 = (meshComponents & MeshComponents.has_colors32) != MeshComponents.none; Vector3[] vertices = EnsureArrayLength(target.vertices, vertexCount); BoneWeight[] boneWeights = EnsureArrayLength(target.unityBoneWeights, 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; #if !UNITY_4_6 Vector2[] uv3 = has_uv3 ? EnsureArrayLength(target.uv3, vertexCount) : null; Vector2[] uv4 = has_uv4 ? EnsureArrayLength(target.uv4, vertexCount) : null; #endif Color32[] colors32 = has_colors32 ? EnsureArrayLength(target.colors32, vertexCount) : null; UMATransform[] umaTransforms = EnsureArrayLength(target.umaBones, transformHierarchyCount); 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) { vertexCount = source.meshData.vertices.Length; BuildBoneWeights(source.meshData.boneWeights, 0, boneWeights, vertexIndex, vertexCount, source.meshData.boneNameHashes, source.meshData.bindPoses, bonesCollection, bindPoses, bonesList); Array.Copy(source.meshData.vertices, 0, vertices, vertexIndex, vertexCount); if (has_normals) { if (source.meshData.normals != null && source.meshData.normals.Length > 0) { Array.Copy(source.meshData.normals, 0, normals, vertexIndex, vertexCount); } else { FillArray(tangents, vertexIndex, vertexCount, Vector3.zero); } } if (has_tangents) { if (source.meshData.tangents != null && source.meshData.tangents.Length > 0) { Array.Copy(source.meshData.tangents, 0, tangents, vertexIndex, vertexCount); } else { FillArray(tangents, vertexIndex, vertexCount, Vector4.zero); } } if (has_uv) { if (source.meshData.uv != null && source.meshData.uv.Length >= vertexCount) { Array.Copy(source.meshData.uv, 0, uv, vertexIndex, vertexCount); } else { FillArray(uv, vertexIndex, vertexCount, Vector4.zero); } } if (has_uv2) { if (source.meshData.uv2 != null && source.meshData.uv2.Length >= vertexCount) { Array.Copy(source.meshData.uv2, 0, uv2, vertexIndex, vertexCount); } else { FillArray(uv2, vertexIndex, vertexCount, Vector4.zero); } } #if !UNITY_4_6 if (has_uv3) { if (source.meshData.uv3 != null && source.meshData.uv3.Length >= vertexCount) { Array.Copy(source.meshData.uv3, 0, uv3, vertexIndex, vertexCount); } else { FillArray(uv3, vertexIndex, vertexCount, Vector4.zero); } } if (has_uv4) { if (source.meshData.uv4 != null && source.meshData.uv4.Length >= vertexCount) { Array.Copy(source.meshData.uv4, 0, uv4, vertexIndex, vertexCount); } else { FillArray(uv4, vertexIndex, vertexCount, Vector4.zero); } } #endif if (has_colors32) { if (source.meshData.colors32 != null && source.meshData.colors32.Length > 0) { Array.Copy(source.meshData.colors32, 0, colors32, vertexIndex, vertexCount); } else { Color32 white32 = Color.white; FillArray(colors32, vertexIndex, vertexCount, white32); } } 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]; CopyIntArrayAdd(subTriangles, 0, submeshTriangles[destMesh], subMeshTriangleLength[destMesh], triangleLength, vertexIndex); subMeshTriangleLength[destMesh] += triangleLength; } } vertexIndex += vertexCount; } vertexCount = vertexIndex; // fill in new values. target.vertexCount = vertexCount; target.vertices = vertices; target.unityBoneWeights = boneWeights; target.bindPoses = bindPoses.ToArray(); target.normals = normals; target.tangents = tangents; target.uv = uv; target.uv2 = uv2; #if !UNITY_4_6 target.uv3 = uv3; target.uv4 = uv4; #endif target.colors32 = colors32; 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(); }