Example #1
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 <MB_BlendShape2CombinedMap>();
                    if (mapComponent == null)
                    {
                        mapComponent = _targetRenderer.gameObject.AddComponent <MB_BlendShape2CombinedMap>();
                    }
                    SerializableSourceBlendShape2Combined map = mapComponent.GetMap();
                    BuildSrcShape2CombinedMap(map, blendShapes);
                }
            }
        }
 internal MBBlendShape[] GetBlendShapes(Mesh m, int gameObjectID, GameObject gameObject)
 {
     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 i = 0; i < shapes.Length; i++)
             {
                 MBBlendShape shape = shapes[i] = new MBBlendShape();
                 shape.frames        = new MBBlendShapeFrame[MBVersion.GetBlendShapeFrameCount(m, i)];
                 shape.name          = m.GetBlendShapeName(i);
                 shape.indexInSource = i;
                 shape.gameObjectID  = gameObjectID;
                 shape.gameObject    = gameObject;
                 for (int j = 0; j < shape.frames.Length; j++)
                 {
                     MBBlendShapeFrame frame = shape.frames[j] = new MBBlendShapeFrame();
                     frame.frameWeight = MBVersion.GetBlendShapeFrameWeight(m, i, j);
                     frame.vertices    = new Vector3[arrayLen];
                     frame.normals     = new Vector3[arrayLen];
                     frame.tangents    = new Vector3[arrayLen];
                     MBVersion.GetBlendShapeFrameVertices(m, i, j, frame.vertices, frame.normals, frame.tangents);
                 }
             }
             mc.blendShapes = shapes;
             return(mc.blendShapes);
         }
         else
         { //copy cached blend shapes assigning 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]);
     }
 }
Example #3
0
 /// <summary>
 /// Get the blend shapes from the source mesh
 /// </summary>
 public static MBBlendShape[] GetBlendShapes(Mesh m, int gameObjectID, GameObject gameObject, Dictionary <int, MeshChannels> 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]);
     }
 }
        public void DrawGUI(MB_IMeshBakerSettings momm, bool settingsEnabled)
        {
            EditorGUILayout.BeginVertical(editorStyles.editorBoxBackgroundStyle);
            GUI.enabled = settingsEnabled;
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.PropertyField(doNorm, gc_doNormGUIContent);
            EditorGUILayout.PropertyField(doTan, gc_doTanGUIContent);
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.PropertyField(doUV, gc_doUVGUIContent);
            EditorGUILayout.PropertyField(doUV3, gc_doUV3GUIContent);
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.PropertyField(doUV4, gc_doUV4GUIContent);
            EditorGUILayout.PropertyField(doCol, gc_doColGUIContent);
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.PropertyField(doBlendShapes, gc_doBlendShapeGUIContent);

            if (momm.lightmapOption == MB2_LightmapOptions.preserve_current_lightmapping)
            {
                if (MBVersion.GetMajorVersion() == 5)
                {
                    EditorGUILayout.HelpBox("The best choice for Unity 5 is to Ignore_UV2 or Generate_New_UV2 layout. Unity's baked GI will create the UV2 layout it wants. See manual for more information.", MessageType.Warning);
                }
            }

            if (momm.lightmapOption == MB2_LightmapOptions.generate_new_UV2_layout)
            {
                EditorGUILayout.HelpBox("Generating new lightmap UVs can split vertices which can push the number of vertices over the 64k limit.", MessageType.Warning);
            }

            EditorGUILayout.PropertyField(lightmappingOption, gc_lightmappingOptionGUIContent);
            if (momm.lightmapOption == MB2_LightmapOptions.generate_new_UV2_layout)
            {
                EditorGUILayout.PropertyField(uv2OutputParamsHardAngle, gc_uv2HardAngleGUIContent);
                EditorGUILayout.PropertyField(uv2OutputParamsPackingMargin, gc_uv2PackingMarginUV3GUIContent);
                EditorGUILayout.Separator();
            }

            EditorGUILayout.PropertyField(renderType, gc_renderTypeGUIContent);
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.PropertyField(clearBuffersAfterBake, gc_clearBuffersAfterBakeGUIContent);
            EditorGUILayout.PropertyField(centerMeshToBoundsCenter, gc_CenterMeshToBoundsCenter);
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.PropertyField(optimizeAfterBake, gc_OptimizeAfterBake);
            GUI.enabled = true;
            EditorGUILayout.EndVertical();
        }
Example #5
0
        //float _maxTimePerFrameForCoroutine;
        public IEnumerator CombineTexturesIntoAtlasesCoroutine(ProgressUpdateDelegate progressInfo, MB_AtlasesAndRects resultAtlasesAndRects, Material resultMaterial, List <GameObject> objsToMesh, List <Material> allowedMaterialsFilter, MB2_EditorMethodsInterface textureEditorMethods = null, CombineTexturesIntoAtlasesCoroutineResult coroutineResult = null, float maxTimePerFrame = .01f, List <AtlasPackingResult> packingResults = null, bool onlyPackRects = false, bool splitAtlasWhenPackingIfTooBig = false)
        {
            if (!_RunCorutineWithoutPauseIsRunning && (MBVersion.GetMajorVersion() < 5 || (MBVersion.GetMajorVersion() == 5 && MBVersion.GetMinorVersion() < 3)))
            {
                Debug.LogError("Running the texture combiner as a coroutine only works in Unity 5.3 and higher");
                yield return(null);
            }
            coroutineResult.success    = true;
            coroutineResult.isFinished = false;
            if (maxTimePerFrame <= 0f)
            {
                Debug.LogError("maxTimePerFrame must be a value greater than zero");
                coroutineResult.isFinished = true;
                yield break;
            }
            //_maxTimePerFrameForCoroutine = maxTimePerFrame;
            yield return(_CombineTexturesIntoAtlases(progressInfo, coroutineResult, resultAtlasesAndRects, resultMaterial, objsToMesh, allowedMaterialsFilter, textureEditorMethods, packingResults, onlyPackRects, splitAtlasWhenPackingIfTooBig));

            coroutineResult.isFinished = true;
            yield break;
        }
        public void DrawGUI(SerializedObject meshBaker, MB3_MeshBakerCommon target, System.Type editorWindowType)
        {
            if (meshBaker == null)
            {
                return;
            }
            meshBaker.Update();

            showInstructions = EditorGUILayout.Foldout(showInstructions, "Instructions:");
            if (showInstructions)
            {
                EditorGUILayout.HelpBox("1. Bake combined material(s).\n\n" +
                                        "2. If necessary set the 'Texture Bake Results' field.\n\n" +
                                        "3. Add scene objects or prefabs to combine or check 'Same As Texture Baker'. For best results these should use the same shader as result material.\n\n" +
                                        "4. Select options and 'Bake'.\n\n" +
                                        "6. Look at warnings/errors in console. Decide if action needs to be taken.\n\n" +
                                        "7. (optional) Disable renderers in source objects.", UnityEditor.MessageType.None);

                EditorGUILayout.Separator();
            }

            MB3_MeshBakerCommon momm = (MB3_MeshBakerCommon)target;

            //mom.meshCombiner.LOG_LEVEL = (MB2_LogLevel) EditorGUILayout.EnumPopup("Log Level", mom.meshCombiner.LOG_LEVEL);
            EditorGUILayout.PropertyField(logLevel, gc_logLevelContent);

            EditorGUILayout.PropertyField(textureBakeResults, gc_textureBakeResultsGUIContent);
            if (textureBakeResults.objectReferenceValue != null)
            {
                showContainsReport = EditorGUILayout.Foldout(showContainsReport, "Shaders & Materials Contained");
                if (showContainsReport)
                {
                    EditorGUILayout.HelpBox(((MB2_TextureBakeResults)textureBakeResults.objectReferenceValue).GetDescription(), MessageType.Info);
                }
            }

            EditorGUILayout.BeginVertical(editorBoxBackgroundStyle);
            EditorGUILayout.LabelField("Objects To Be Combined", EditorStyles.boldLabel);
            if (momm.GetTextureBaker() != null)
            {
                EditorGUILayout.PropertyField(useObjsToMeshFromTexBaker, gc_useTextureBakerObjsGUIContent);
            }
            else
            {
                useObjsToMeshFromTexBaker.boolValue = false;
                momm.useObjsToMeshFromTexBaker      = false;
                GUI.enabled = false;
                EditorGUILayout.PropertyField(useObjsToMeshFromTexBaker, gc_useTextureBakerObjsGUIContent);
                GUI.enabled = true;
            }

            if (!momm.useObjsToMeshFromTexBaker)
            {
                if (GUILayout.Button(gc_openToolsWindowLabelContent))
                {
                    MB3_MeshBakerEditorWindowInterface mmWin = (MB3_MeshBakerEditorWindowInterface)EditorWindow.GetWindow(editorWindowType);
                    mmWin.target = (MB3_MeshBakerRoot)target;
                }
                EditorGUILayout.PropertyField(objsToMesh, gc_objectsToCombineGUIContent, true);
                EditorGUILayout.Separator();
                EditorGUILayout.BeginHorizontal();
                if (GUILayout.Button("Select Objects In Scene"))
                {
                    Selection.objects = momm.GetObjectsToCombine().ToArray();
                    if (momm.GetObjectsToCombine().Count > 0)
                    {
                        SceneView.lastActiveSceneView.pivot = momm.GetObjectsToCombine()[0].transform.position;
                    }
                }
                if (GUILayout.Button(gc_SortAlongAxis))
                {
                    MB3_MeshBakerRoot.ZSortObjects sorter = new MB3_MeshBakerRoot.ZSortObjects();
                    sorter.sortAxis = sortOrderAxis.vector3Value;
                    sorter.SortByDistanceAlongAxis(momm.GetObjectsToCombine());
                }
                EditorGUILayout.PropertyField(sortOrderAxis, GUIContent.none);
                EditorGUILayout.EndHorizontal();
            }
            else
            {
                GUI.enabled = false;
                EditorGUILayout.PropertyField(objsToMesh, gc_objectsToCombineGUIContent, true);
                GUI.enabled = true;
            }
            EditorGUILayout.EndVertical();

            EditorGUILayout.LabelField("Output", EditorStyles.boldLabel);
            if (momm is MB3_MultiMeshBaker)
            {
                MB3_MultiMeshCombiner mmc = (MB3_MultiMeshCombiner)momm.meshCombiner;
                mmc.maxVertsInMesh = EditorGUILayout.IntField("Max Verts In Mesh", mmc.maxVertsInMesh);
            }

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.PropertyField(doNorm, gc_doNormGUIContent);
            EditorGUILayout.PropertyField(doTan, gc_doTanGUIContent);
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.PropertyField(doUV, gc_doUVGUIContent);
            EditorGUILayout.PropertyField(doUV3, gc_doUV3GUIContent);
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.PropertyField(doUV4, gc_doUV4GUIContent);
            EditorGUILayout.PropertyField(doCol, gc_doColGUIContent);
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.PropertyField(doBlendShapes, gc_doBlendShapeGUIContent);

            if (momm.meshCombiner.lightmapOption == MB2_LightmapOptions.preserve_current_lightmapping)
            {
                if (MBVersion.GetMajorVersion() == 5)
                {
                    EditorGUILayout.HelpBox("The best choice for Unity 5 is to Ignore_UV2 or Generate_New_UV2 layout. Unity's baked GI will create the UV2 layout it wants. See manual for more information.", MessageType.Warning);
                }
            }
            if (momm.meshCombiner.lightmapOption == MB2_LightmapOptions.generate_new_UV2_layout)
            {
                EditorGUILayout.HelpBox("Generating new lightmap UVs can split vertices which can push the number of vertices over the 64k limit.", MessageType.Warning);
            }
            EditorGUILayout.PropertyField(lightmappingOption, gc_lightmappingOptionGUIContent);
            if (momm.meshCombiner.lightmapOption == MB2_LightmapOptions.generate_new_UV2_layout)
            {
                EditorGUILayout.PropertyField(uv2OutputParamsHardAngle, gc_uv2HardAngleGUIContent);
                EditorGUILayout.PropertyField(uv2OutputParamsPackingMargin, gc_uv2PackingMarginUV3GUIContent);
                EditorGUILayout.Separator();
            }

            EditorGUILayout.PropertyField(outputOptions, gc_outputOptoinsGUIContent);
            EditorGUILayout.PropertyField(renderType, gc_renderTypeGUIContent);
            if (momm.meshCombiner.outputOption == MB2_OutputOptions.bakeIntoSceneObject)
            {
                //todo switch to renderer
                momm.meshCombiner.resultSceneObject = (GameObject)EditorGUILayout.ObjectField("Combined Mesh Object", momm.meshCombiner.resultSceneObject, typeof(GameObject), true);
                if (momm is MB3_MeshBaker)
                {
                    string l = "Mesh";
                    if (mesh.objectReferenceValue != null)
                    {
                        l += " (" + mesh.objectReferenceValue.GetInstanceID() + ")";
                    }
                    EditorGUILayout.PropertyField(mesh, new GUIContent(l));
                }
            }
            else if (momm.meshCombiner.outputOption == MB2_OutputOptions.bakeIntoPrefab)
            {
                momm.resultPrefab = (GameObject)EditorGUILayout.ObjectField(gc_combinedMeshPrefabGUIContent, momm.resultPrefab, typeof(GameObject), true);
                if (momm is MB3_MeshBaker)
                {
                    string l = "Mesh";
                    if (mesh.objectReferenceValue != null)
                    {
                        l += " (" + mesh.objectReferenceValue.GetInstanceID() + ")";
                    }
                    EditorGUILayout.PropertyField(mesh, new GUIContent(l));
                }
            }
            else if (momm.meshCombiner.outputOption == MB2_OutputOptions.bakeMeshAssetsInPlace)
            {
                EditorGUILayout.HelpBox("NEW! Try the BatchPrefabBaker component. It makes preparing a batch of prefabs for static/ dynamic batching much easier.", MessageType.Info);
                if (GUILayout.Button("Choose Folder For Bake In Place Meshes"))
                {
                    string newFolder = EditorUtility.SaveFolderPanel("Folder For Bake In Place Meshes", Application.dataPath, "");
                    if (!newFolder.Contains(Application.dataPath))
                    {
                        Debug.LogWarning("The chosen folder must be in your assets folder.");
                    }
                    momm.bakeAssetsInPlaceFolderPath = "Assets" + newFolder.Replace(Application.dataPath, "");
                }
                EditorGUILayout.LabelField("Folder For Meshes: " + momm.bakeAssetsInPlaceFolderPath);
            }

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.PropertyField(clearBuffersAfterBake, gc_clearBuffersAfterBakeGUIContent);
            EditorGUILayout.PropertyField(centerMeshToBoundsCenter, gc_CenterMeshToBoundsCenter);
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.PropertyField(optimizeAfterBake, gc_OptimizeAfterBake);
            Color oldColor = GUI.backgroundColor;

            GUI.backgroundColor = buttonColor;
            if (GUILayout.Button("Bake"))
            {
                bake(momm);
            }
            GUI.backgroundColor = oldColor;

            string enableRenderersLabel;
            bool   disableRendererInSource = false;

            if (momm.GetObjectsToCombine().Count > 0)
            {
                Renderer r = MB_Utility.GetRenderer(momm.GetObjectsToCombine()[0]);
                if (r != null && r.enabled)
                {
                    disableRendererInSource = true;
                }
            }
            if (disableRendererInSource)
            {
                enableRenderersLabel = "Disable Renderers On Source Objects";
            }
            else
            {
                enableRenderersLabel = "Enable Renderers On Source Objects";
            }
            if (GUILayout.Button(enableRenderersLabel))
            {
                momm.EnableDisableSourceObjectRenderers(!disableRendererInSource);
            }

            meshBaker.ApplyModifiedProperties();
            meshBaker.SetIsDifferentCacheDirty();
        }
Example #7
0
        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 <string, List <MBBlendShape> > shapeName2objs = new Dictionary <string, List <MBBlendShape> >();
                {
                    for (int i = 0; i < blendShapes.Length; i++)
                    {
                        MBBlendShape        blendShape     = blendShapes[i];
                        string              blendShapeName = ConvertBlendShapeNameToOutputName(blendShape.name);
                        List <MBBlendShape> dgosUsingBlendShape;
                        if (!shapeName2objs.TryGetValue(blendShapeName, out dgosUsingBlendShape))
                        {
                            dgosUsingBlendShape = new List <MBBlendShape>();
                            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 <MBBlendShape> 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 <MB_BlendShape2CombinedMap>();
                    if (mapComponent == null)
                    {
                        mapComponent = _targetRenderer.gameObject.AddComponent <MB_BlendShape2CombinedMap>();
                    }
                    SerializableSourceBlendShape2Combined map = mapComponent.GetMap();
                    BuildSrcShape2CombinedMap(map, blendShapesInCombined);
                }
            }
        }