using System.Collections; using System.Collections.Generic; using UnityEngine; using System; namespace DigitalOpus.MB.Core { public partial class MB3_MeshCombinerSingle : MB3_MeshCombiner { /// /// Get the blend shapes from the source mesh /// public static MBBlendShape[] GetBlendShapes(Mesh m, int gameObjectID, GameObject gameObject, Dictionary meshID2MeshChannels) { if (MBVersion.GetMajorVersion() > 5 || (MBVersion.GetMajorVersion() == 5 && MBVersion.GetMinorVersion() >= 3)) { MeshChannels mc; if (!meshID2MeshChannels.TryGetValue(m.GetInstanceID(), out mc)) { mc = new MeshChannels(); meshID2MeshChannels.Add(m.GetInstanceID(), mc); } if (mc.blendShapes == null) { MBBlendShape[] shapes = new MBBlendShape[m.blendShapeCount]; int arrayLen = m.vertexCount; for (int shapeIdx = 0; shapeIdx < shapes.Length; shapeIdx++) { MBBlendShape shape = shapes[shapeIdx] = new MBBlendShape(); shape.frames = new MBBlendShapeFrame[MBVersion.GetBlendShapeFrameCount(m, shapeIdx)]; shape.name = m.GetBlendShapeName(shapeIdx); shape.indexInSource = shapeIdx; shape.gameObjectID = gameObjectID; shape.gameObject = gameObject; for (int frameIdx = 0; frameIdx < shape.frames.Length; frameIdx++) { MBBlendShapeFrame frame = shape.frames[frameIdx] = new MBBlendShapeFrame(); frame.frameWeight = MBVersion.GetBlendShapeFrameWeight(m, shapeIdx, frameIdx); frame.vertices = new Vector3[arrayLen]; frame.normals = new Vector3[arrayLen]; frame.tangents = new Vector3[arrayLen]; MBVersion.GetBlendShapeFrameVertices(m, shapeIdx, frameIdx, frame.vertices, frame.normals, frame.tangents); } } mc.blendShapes = shapes; return mc.blendShapes; } else { //copy cached blend shapes from same mesh assiged to a different gameObjectID MBBlendShape[] shapes = new MBBlendShape[mc.blendShapes.Length]; for (int i = 0; i < shapes.Length; i++) { shapes[i] = new MBBlendShape(); shapes[i].name = mc.blendShapes[i].name; shapes[i].indexInSource = mc.blendShapes[i].indexInSource; shapes[i].frames = mc.blendShapes[i].frames; shapes[i].gameObjectID = gameObjectID; shapes[i].gameObject = gameObject; } return shapes; } } else { return new MBBlendShape[0]; } } void ApplyBlendShapeFramesToMeshAndBuildMap() { if (MBVersion.GetMajorVersion() > 5 || (MBVersion.GetMajorVersion() == 5 && MBVersion.GetMinorVersion() >= 3)) { if (blendShapesInCombined.Length != blendShapes.Length) blendShapesInCombined = new MBBlendShape[blendShapes.Length]; Vector3[] targVerts = new UnityEngine.Vector3[verts.Length]; Vector3[] targNorms = new UnityEngine.Vector3[verts.Length]; Vector3[] targTans = new UnityEngine.Vector3[verts.Length]; ((SkinnedMeshRenderer)_targetRenderer).sharedMesh = null; MBVersion.ClearBlendShapes(_mesh); for (int bsIdx = 0; bsIdx < blendShapes.Length; bsIdx++) { MBBlendShape blendShape = blendShapes[bsIdx]; MB_DynamicGameObject dgo = instance2Combined_MapGet(blendShape.gameObject); if (dgo != null) { int destIdx = dgo.vertIdx; for (int frmIdx = 0; frmIdx < blendShape.frames.Length; frmIdx++) { MBBlendShapeFrame frame = blendShape.frames[frmIdx]; Array.Copy(frame.vertices, 0, targVerts, destIdx, frame.vertices.Length); Array.Copy(frame.normals, 0, targNorms, destIdx, frame.normals.Length); Array.Copy(frame.tangents, 0, targTans, destIdx, frame.tangents.Length); MBVersion.AddBlendShapeFrame(_mesh, ConvertBlendShapeNameToOutputName(blendShape.name) + blendShape.gameObjectID, frame.frameWeight, targVerts, targNorms, targTans); // We re-use these arrays restore them to zero _ZeroArray(targVerts, destIdx, frame.vertices.Length); _ZeroArray(targNorms, destIdx, frame.normals.Length); _ZeroArray(targTans, destIdx, frame.tangents.Length); } } else { Debug.LogError("InstanceID in blend shape that was not in instance2combinedMap"); } blendShapesInCombined[bsIdx] = blendShape; } //this is necessary to get the renderer to refresh its data about the blendshapes. ((SkinnedMeshRenderer)_targetRenderer).sharedMesh = null; ((SkinnedMeshRenderer)_targetRenderer).sharedMesh = _mesh; // Add the map to the target renderer. if (settings.doBlendShapes) { MB_BlendShape2CombinedMap mapComponent = _targetRenderer.GetComponent(); if (mapComponent == null) mapComponent = _targetRenderer.gameObject.AddComponent(); SerializableSourceBlendShape2Combined map = mapComponent.GetMap(); BuildSrcShape2CombinedMap(map, blendShapes); } } } /// /// The source blend shape may have parts that should be stripped away. /// Use this method to strip away the unused parts. /// string ConvertBlendShapeNameToOutputName(string bs) { // remove everything before the final '.' string[] nameParts = bs.Split('.'); string lastPart = nameParts[nameParts.Length - 1]; return lastPart; } void ApplyBlendShapeFramesToMeshAndBuildMap_MergeBlendShapesWithTheSameName() { if (MBVersion.GetMajorVersion() > 5 || (MBVersion.GetMajorVersion() == 5 && MBVersion.GetMinorVersion() >= 3)) { Vector3[] targVerts = new UnityEngine.Vector3[verts.Length]; Vector3[] targNorms = new UnityEngine.Vector3[verts.Length]; Vector3[] targTans = new UnityEngine.Vector3[verts.Length]; MBVersion.ClearBlendShapes(_mesh); // Group source that share the same blendShapeName bool numFramesError = false; Dictionary> shapeName2objs = new Dictionary>(); { for (int i = 0; i < blendShapes.Length; i++) { MBBlendShape blendShape = blendShapes[i]; string blendShapeName = ConvertBlendShapeNameToOutputName(blendShape.name); List dgosUsingBlendShape; if (!shapeName2objs.TryGetValue(blendShapeName, out dgosUsingBlendShape)) { dgosUsingBlendShape = new List(); shapeName2objs.Add(blendShapeName, dgosUsingBlendShape); } dgosUsingBlendShape.Add(blendShape); if (dgosUsingBlendShape.Count > 1) { if (dgosUsingBlendShape[0].frames.Length != blendShape.frames.Length) { Debug.LogError("BlendShapes with the same name must have the same number of frames."); numFramesError = true; } } } } if (numFramesError) return; if (blendShapesInCombined.Length != blendShapes.Length) blendShapesInCombined = new MBBlendShape[shapeName2objs.Keys.Count]; int bsInCombinedIdx = 0; foreach (string shapeName in shapeName2objs.Keys) { List groupOfSrcObjs = shapeName2objs[shapeName]; MBBlendShape firstBlendShape = groupOfSrcObjs[0]; int numFrames = firstBlendShape.frames.Length; int db_numVertsAdded = 0; int db_numObjsAdded = 0; string db_vIdx = ""; for (int frmIdx = 0; frmIdx < numFrames; frmIdx++) { float firstFrameWeight = firstBlendShape.frames[frmIdx].frameWeight; for (int dgoIdx = 0; dgoIdx < groupOfSrcObjs.Count; dgoIdx++) { MBBlendShape blendShape = groupOfSrcObjs[dgoIdx]; MB_DynamicGameObject dgo = instance2Combined_MapGet(blendShape.gameObject); int destIdx = dgo.vertIdx; Debug.Assert(blendShape.frames.Length == numFrames); MBBlendShapeFrame frame = blendShape.frames[frmIdx]; Debug.Assert(frame.frameWeight == firstFrameWeight); Array.Copy(frame.vertices, 0, targVerts, destIdx, frame.vertices.Length); Array.Copy(frame.normals, 0, targNorms, destIdx, frame.normals.Length); Array.Copy(frame.tangents, 0, targTans, destIdx, frame.tangents.Length); if (frmIdx == 0) { db_numVertsAdded += frame.vertices.Length; db_vIdx += blendShape.gameObject.name + " " + destIdx + ":" +(destIdx + frame.vertices.Length) + ", "; } } db_numObjsAdded += groupOfSrcObjs.Count; MBVersion.AddBlendShapeFrame(_mesh, shapeName, firstFrameWeight, targVerts, targNorms, targTans); // We re-use these arrays restore them to zero _ZeroArray(targVerts, 0, targVerts.Length); _ZeroArray(targNorms, 0, targNorms.Length); _ZeroArray(targTans, 0, targTans.Length); } blendShapesInCombined[bsInCombinedIdx] = firstBlendShape; bsInCombinedIdx++; } //this is necessary to get the renderer to refresh its data about the blendshapes. ((SkinnedMeshRenderer)_targetRenderer).sharedMesh = null; ((SkinnedMeshRenderer)_targetRenderer).sharedMesh = _mesh; // Add the map to the target renderer. if (settings.doBlendShapes) { MB_BlendShape2CombinedMap mapComponent = _targetRenderer.GetComponent(); if (mapComponent == null) mapComponent = _targetRenderer.gameObject.AddComponent(); SerializableSourceBlendShape2Combined map = mapComponent.GetMap(); BuildSrcShape2CombinedMap(map, blendShapesInCombined); } } } void BuildSrcShape2CombinedMap(SerializableSourceBlendShape2Combined map, MBBlendShape[] bs) { Debug.Assert(_targetRenderer.gameObject != null, "Target Renderer was null."); GameObject[] srcGameObjects = new GameObject[bs.Length]; int[] srcBlendShapeIdxs = new int[bs.Length]; GameObject[] targGameObjects = new GameObject[bs.Length]; int[] targBlendShapeIdxs = new int[bs.Length]; for (int i = 0; i < blendShapesInCombined.Length; i++) { srcGameObjects[i] = blendShapesInCombined[i].gameObject; srcBlendShapeIdxs[i] = blendShapesInCombined[i].indexInSource; targGameObjects[i] = _targetRenderer.gameObject; targBlendShapeIdxs[i] = i; } map.SetBuffers(srcGameObjects, srcBlendShapeIdxs, targGameObjects, targBlendShapeIdxs); } [System.Obsolete("BuildSourceBlendShapeToCombinedIndexMap is deprecated. The map will be now be attached to the combined SkinnedMeshRenderer object as the MB_BlendShape2CombinedMap Component.")] public override Dictionary BuildSourceBlendShapeToCombinedIndexMap() { if (_targetRenderer == null) return new Dictionary(); MB_BlendShape2CombinedMap mapComponent = _targetRenderer.GetComponent(); if (mapComponent == null) return new Dictionary(); return mapComponent.srcToCombinedMap.GenerateMapFromSerializedData(); } void _ZeroArray(Vector3[] arr, int idx, int length) { int bound = idx + length; for (int i = idx; i < bound; i++) { arr[i] = Vector3.zero; } } } }