/// <summary>
        /// 将游戏物体,及其子物体的 Renderer 组件添加到合并器中
        /// </summary>
        /// <param name="objs"></param>
        /// <param name="momm"></param>
        public static void AddDroppedObjects(object[] objs, MeshBakerRoot momm)
        {
            if (objs != null)
            {
                HashSet <Renderer> renderersToAdd = new HashSet <Renderer>();
                for (int i = 0; i < objs.Length; i++)
                {
                    object obj = objs[i];
                    if (obj is GameObject)
                    {
                        Renderer[] rs = ((GameObject)obj).GetComponentsInChildren <Renderer>();
                        for (int j = 0; j < rs.Length; j++)
                        {
                            if (rs[j] is MeshRenderer || rs[j] is SkinnedMeshRenderer)
                            {
                                renderersToAdd.Add(rs[j]);
                            }
                        }
                    }
                }

                int numAdded = 0;
                List <GameObject> objsToCombine = momm.GetObjectsToCombine();
                bool failedToAddAssets          = false;
                foreach (Renderer r in renderersToAdd)
                {
                    if (!objsToCombine.Contains(r.gameObject))
                    {
                        PrefabType prefabType = SceneBakerUtilityInEditor.GetPrefabType(r.gameObject);
                        if (prefabType == PrefabType.modelPrefab || prefabType == PrefabType.prefab)
                        {
                            failedToAddAssets = true;
                        }
                        else
                        {
                            objsToCombine.Add(r.gameObject);
                            numAdded++;
                        }
                    }
                }

                if (failedToAddAssets)
                {
                    Debug.LogError("Did not add some object(s) because they are not scene objects");
                }
                Debug.Log("Added " + numAdded + " renderers");
            }
        }
        /// <summary>
        /// 构建预制体
        /// </summary>
        /// <param name="mom"></param>
        /// <param name="so"></param>
        public static void RebuildPrefab(MeshBakerCommon mom, ref SerializedObject so)
        {
            GameObject prefabRoot = mom.resultPrefab;
            GameObject rootGO     = (GameObject)PrefabUtility.InstantiatePrefab(prefabRoot);

            SceneBakerUtilityInEditor.UnpackPrefabInstance(rootGO, ref so);

            //remove all renderer childeren of rootGO
            Renderer[] rs = rootGO.GetComponentsInChildren <Renderer>();
            for (int i = 0; i < rs.Length; i++)
            {
                if (rs[i] != null && rs[i].transform.parent == rootGO.transform)
                {
                    MeshBakerUtility.Destroy(rs[i].gameObject);
                }
            }

            if (mom is MeshCombinerEntrance)
            {
                MeshCombinerEntrance entrance = (MeshCombinerEntrance)mom;
                MeshCombineHandler   mbs      = (MeshCombineHandler)entrance.meshCombiner;
                MeshCombineHandler.BuildPrefabHierarchy(mbs, rootGO, mbs.GetMesh());
            }
            ////else if (mom is MB3_MultiMeshBaker)
            ////{
            ////    MB3_MultiMeshBaker mmb = (MB3_MultiMeshBaker)mom;
            ////    MB3_MultiMeshCombiner mbs = (MB3_MultiMeshCombiner)mmb.meshCombiner;
            ////    for (int i = 0; i < mbs.meshCombiners.Count; i++)
            ////    {
            ////        MB3_MeshCombinerSingle.BuildPrefabHierarchy(mbs.meshCombiners[i].combinedMesh, rootGO, mbs.meshCombiners[i].combinedMesh.GetMesh(), true);
            ////    }
            ////}
            else
            {
                Debug.LogError("MeshCombiner合并器类型错误");
            }

            //保存预制体
            string prefabPth = AssetDatabase.GetAssetPath(prefabRoot);

            SceneBakerUtilityInEditor.ReplacePrefab(rootGO, prefabPth, ReplacePrefabOption.connectToPrefab);
            if (mom.meshCombiner.renderType != RendererType.skinnedMeshRenderer)
            {
                // For Skinned meshes, leave the prefab instance in the scene so source game objects can moved into the prefab.
                UnityEditor.Editor.DestroyImmediate(rootGO);
            }
        }
 public bool CheckPrefabTypes(ObjsToCombineTypes objToCombineType, List <GameObject> objsToMesh)
 {
     for (int i = 0; i < objsToMesh.Count; i++)
     {
         PrefabType pt = SceneBakerUtilityInEditor.GetPrefabType(objsToMesh[i]);
         if (pt == PrefabType.sceneInstance)
         {
             // these are scene objects
             if (objToCombineType == ObjsToCombineTypes.prefabOnly)
             {
                 Debug.LogWarning("The list of objects to combine contains scene objects. You probably want prefabs. If using scene objects ensure position is zero, rotation is zero and scale is one. Translation, Rotation and Scale will be baked into the generated mesh." + objsToMesh[i] + " is a scene object");
                 return(false);
             }
         }
         else if (objToCombineType == ObjsToCombineTypes.sceneObjOnly)
         {
             //these are prefabs
             Debug.LogWarning("The list of objects to combine contains prefab assets. You probably want scene objects." + objsToMesh[i] + " is a prefab object");
             return(false);
         }
     }
     return(true);
 }
        //		public int GetMaximumAtlasDimension(){
        //			return MBVersionEditor.GetMaximumAtlasDimension();
        //		}

        public string GetPlatformString()
        {
            return(SceneBakerUtilityInEditor.GetPlatformString());
        }
        private bool _SetTextureFormat2017(Texture2D tx, TextureFormatInfo toThisFormat, bool addToList, bool setNormalMap, TextureImporter textureImporter)
        {
            bool is2017 = Application.unityVersion.StartsWith("20");

            if (!is2017)
            {
                Debug.LogError("Wrong texture format converter. 2017 Should not be called for Unity Version " + Application.unityVersion);
                return(false);
            }

            bool doImport = false;
            TextureFormatInfo restoreTfi = new TextureFormatInfo(textureImporter.textureCompression,
                                                                 textureImporter.crunchedCompression,
                                                                 toThisFormat.platform,
                                                                 TextureImporterFormat.RGBA32,
                                                                 textureImporter.textureType == TextureImporterType.NormalMap);
            string platform    = toThisFormat.platform;
            bool   isAutoPVRTC = false;

            if (platform != null)
            {
                TextureImporterPlatformSettings tips = textureImporter.GetPlatformTextureSettings(platform);
                if (tips.overridden)
                {
                    restoreTfi.platformFormat             = tips.format;
                    restoreTfi.platformCompressionQuality = tips.compressionQuality;
                    restoreTfi.doCrunchCompression        = tips.crunchedCompression;
                    restoreTfi.isNormalMap = textureImporter.textureType == TextureImporterType.NormalMap;
                    TextureImporterPlatformSettings tipsOverridden = new TextureImporterPlatformSettings();
                    tips.CopyTo(tipsOverridden);
                    tipsOverridden.compressionQuality  = toThisFormat.platformCompressionQuality;
                    tipsOverridden.crunchedCompression = toThisFormat.doCrunchCompression;
                    tipsOverridden.format = toThisFormat.platformFormat;
                    textureImporter.SetPlatformTextureSettings(tipsOverridden);
                    doImport = true;
                }

                isAutoPVRTC = SceneBakerUtilityInEditor.IsAutoPVRTC(tips.format, textureImporter.GetAutomaticFormat(platform));
            }


            if (isAutoPVRTC && textureImporter.textureCompression != toThisFormat.compression)
            {
                textureImporter.textureCompression = toThisFormat.compression;
                doImport = true;
            }

            if (textureImporter.crunchedCompression != toThisFormat.doCrunchCompression)
            {
                textureImporter.crunchedCompression = toThisFormat.doCrunchCompression;
                doImport = true;
            }
            if (_ChangeNormalMapTypeIfNecessary(textureImporter, setNormalMap))
            {
                doImport = true;
            }

            if (doImport)
            {
                string s;
                if (addToList)
                {
                    s = "Setting texture compression for ";
                }
                else
                {
                    s = "Restoring texture compression for ";
                }
                s += String.Format("{0}  FROM: compression={1} isNormal{2} TO: compression={3} isNormal={4} ", tx, restoreTfi.compression, restoreTfi.isNormalMap, toThisFormat.compression, setNormalMap);
                if (toThisFormat.platform != null)
                {
                    s += String.Format(" setting platform override format for platform {0} to {1} compressionQuality {2}", toThisFormat.platform, toThisFormat.platformFormat, toThisFormat.platformCompressionQuality);
                }
                Debug.Log(s);
                if (doImport && addToList && !_textureFormatMap.ContainsKey(tx))
                {
                    _textureFormatMap.Add(tx, restoreTfi);
                }
            }
            return(doImport);
        }
        public void AddTextureFormat(Texture2D tx, bool isNormalMap)
        {
            //pixel values don't copy correctly from one texture to another when isNormal is set so unset it.
            TextureFormatInfo toFormat = new TextureFormatInfo(TextureImporterCompression.Uncompressed, false, SceneBakerUtilityInEditor.GetPlatformString(), TextureImporterFormat.RGBA32, isNormalMap);

            _SetTextureFormat(tx, toFormat, true, false);
        }
Example #7
0
        //posibilities
        //  using fixOutOfBoundsUVs or not
        //
        /// <summary>
        /// 根据合并列表物体配置多材质
        /// </summary>
        /// <param name="mom"></param>
        /// <param name="resultMaterials"></param>
        /// <param name="textureBaker"></param>
        public static void ConfigureMutiMaterialsFromObjsToCombine(TextureCombineEntrance mom, SerializedProperty resultMaterials, SerializedObject textureBaker)
        {
            if (mom.GetObjectsToCombine().Count == 0)
            {
                Debug.LogError("合并列表为空");
                return;
            }
            if (resultMaterials.arraySize > 0)
            {
                Debug.LogError("多材质映射已配置,在进行当前操作前需清除旧配置");
                return;
            }
            if (mom.textureBakeResults == null)
            {
                Debug.LogError("Texture Bake Result 为空");
                return;
            }

            //validate that the objects to be combined are valid
            //验证合并列表内物体有效性
            for (int i = 0; i < mom.GetObjectsToCombine().Count; i++)
            {
                GameObject go = mom.GetObjectsToCombine()[i];
                if (go == null)
                {
                    Debug.LogError("合并列表中有空物体于 " + i);
                    return;
                }
                Renderer r = go.GetComponent <Renderer>();
                if (r == null || (!(r is MeshRenderer) && !(r is SkinnedMeshRenderer)))
                {
                    Debug.LogError("合并列表中第 " + i + " 个游戏物体没有 renderer 组件");
                    return;
                }
                if (r.sharedMaterial == null)
                {
                    Debug.LogError("合并列表中第 " + i + " 个游戏物体没有材质");
                    return;
                }
            }



            Dictionary <Material, Mesh> obUVobjectToMesh_map = new Dictionary <Material, Mesh>();

            //first pass put any meshes with obUVs on their own submesh if not fixing OB uvs
            //1.将所有带有obUV的网格置于单独的材质中,(如果不固定OB UV)
            if (mom.doMultiMaterialSplitAtlasesIfOBUVs)
            {
                for (int i = 0; i < mom.GetObjectsToCombine().Count; i++)
                {
                    GameObject         go       = mom.GetObjectsToCombine()[i];
                    Mesh               m        = MeshBakerUtility.GetMesh(go);
                    MeshAnalysisResult dummyMar = new MeshAnalysisResult();
                    Renderer           r        = go.GetComponent <Renderer>();
                    for (int j = 0; j < r.sharedMaterials.Length; j++)
                    {
                        if (MeshBakerUtility.hasOutOfBoundsUVs(m, ref dummyMar, j))
                        {
                            if (!obUVobjectToMesh_map.ContainsKey(r.sharedMaterials[j]))
                            {
                                Debug.LogWarning("Object " + go + " submesh " + j + " uses UVs outside the range 0,0..1,1 to generate tiling. " +
                                                 "This object has been mapped to its own submesh in the combined mesh. " +
                                                 "It can share a submesh with other objects that use different materials " +
                                                 "if you use the fix out of bounds UVs feature which will bake the tiling");
                                obUVobjectToMesh_map.Add(r.sharedMaterials[j], m);
                            }
                        }
                    }
                }
            }

            Dictionary <MultiMatSubmeshInfo, List <List <Material> > > shaderToMaterial_map = new Dictionary <MultiMatSubmeshInfo, List <List <Material> > >();

            //2.没有 OB uvs 的材质按 shader 添加到 shader2Material_map 中
            for (int i = 0; i < mom.GetObjectsToCombine().Count; i++)
            {
                Renderer r = mom.GetObjectsToCombine()[i].GetComponent <Renderer>();
                for (int j = 0; j < r.sharedMaterials.Length; j++)
                {
                    if (!obUVobjectToMesh_map.ContainsKey(r.sharedMaterials[j]))
                    { //if not already added
                        if (r.sharedMaterials[j] == null)
                        {
                            continue;
                        }
                        List <List <Material> > binsOfMatsThatUseShader = null;
                        MultiMatSubmeshInfo     newKey = new MultiMatSubmeshInfo(r.sharedMaterials[j].shader, r.sharedMaterials[j]);
                        if (!shaderToMaterial_map.TryGetValue(newKey, out binsOfMatsThatUseShader))
                        {
                            binsOfMatsThatUseShader = new List <List <Material> >();
                            binsOfMatsThatUseShader.Add(new List <Material>());
                            shaderToMaterial_map.Add(newKey, binsOfMatsThatUseShader);
                        }
                        if (!binsOfMatsThatUseShader[0].Contains(r.sharedMaterials[j]))
                        {
                            binsOfMatsThatUseShader[0].Add(r.sharedMaterials[j]);
                        }
                    }
                }
            }

            int ResultMatsCount = shaderToMaterial_map.Count;

            //third pass for each shader grouping check how big the atlas would be and group into bins that would fit in an atlas
            // 3.检查每个 Shader-Mat 组的最终打包的 atlas 大小,过大则分到另一个图集中
            if (mom.doMultiMaterialSplitAtlasesIfTooBig)
            {
                if (mom.packingAlgorithm == PackingAlgorithmEnum.UnitysPackTextures)
                {
                    Debug.LogWarning("Unity texture packer does not support splitting atlases if too big. Atlases will not be split.");
                }
                else
                {
                    ResultMatsCount = 0;
                    foreach (MultiMatSubmeshInfo sh in shaderToMaterial_map.Keys)
                    {
                        List <List <Material> > binsOfMatsThatUseShader = shaderToMaterial_map[sh];
                        List <Material>         allMatsThatUserShader   = binsOfMatsThatUseShader[0];//at this point everything is in the same list
                        binsOfMatsThatUseShader.RemoveAt(0);
                        TextureCombineHandler combiner = mom.CreateAndConfigureTextureCombiner();
                        combiner.saveAtlasesAsAssets = false;
                        if (allMatsThatUserShader.Count > 1)
                        {
                            combiner.fixOutOfBoundsUVs = mom.fixOutOfBoundsUVs;
                        }
                        else
                        {
                            combiner.fixOutOfBoundsUVs = false;
                        }

                        // Do the texture pack
                        List <AtlasPackingResult> packingResults = new List <AtlasPackingResult>();
                        Material tempMat = new Material(sh.shader);
                        combiner.CombineTexturesIntoAtlases(null, null, tempMat, mom.GetObjectsToCombine(), allMatsThatUserShader, null, packingResults, true, true);
                        for (int i = 0; i < packingResults.Count; i++)
                        {
                            List <MatsAndGOs> matsData = (List <MatsAndGOs>)packingResults[i].data;
                            List <Material>   mats     = new List <Material>();
                            for (int j = 0; j < matsData.Count; j++)
                            {
                                for (int kk = 0; kk < matsData[j].mats.Count; kk++)
                                {
                                    if (!mats.Contains(matsData[j].mats[kk].mat))
                                    {
                                        mats.Add(matsData[j].mats[kk].mat);
                                    }
                                }
                            }
                            binsOfMatsThatUseShader.Add(mats);
                        }
                        ResultMatsCount += binsOfMatsThatUseShader.Count;
                    }
                }
            }

            //build the result materials
            if (shaderToMaterial_map.Count == 0 && obUVobjectToMesh_map.Count == 0)
            {
                Debug.LogError("合并列表中没有材质");
            }

            mom.resultMaterials = new MultiMaterial[ResultMatsCount + obUVobjectToMesh_map.Count];
            string pth        = AssetDatabase.GetAssetPath(mom.textureBakeResults);
            string baseName   = Path.GetFileNameWithoutExtension(pth);
            string folderPath = pth.Substring(0, pth.Length - baseName.Length - 6);
            int    k          = 0;

            foreach (MultiMatSubmeshInfo sh in shaderToMaterial_map.Keys)
            {
                foreach (List <Material> sourseMatsThatUseSameShader in shaderToMaterial_map[sh])
                {
                    MultiMaterial mm = mom.resultMaterials[k] = new MultiMaterial();
                    mm.sourceMaterials = sourseMatsThatUseSameShader;
                    if (mm.sourceMaterials.Count == 1)
                    {
                        mm.considerMeshUVs = false;
                    }
                    else
                    {
                        mm.considerMeshUVs = mom.fixOutOfBoundsUVs;
                    }
                    string matName = folderPath + baseName + "-mat" + k + ".mat";

                    Material newMat = new Material(Shader.Find("Diffuse"));
                    if (sourseMatsThatUseSameShader.Count > 0 && sourseMatsThatUseSameShader[0] != null)
                    {
                        //复制参数值
                        TextureCombineEntrance.ConfigureNewMaterialToMatchOld(newMat, sourseMatsThatUseSameShader[0]);
                    }
                    AssetDatabase.CreateAsset(newMat, matName);
                    //合并材质初始值为源材质列表第一个的值
                    mm.combinedMaterial = (Material)AssetDatabase.LoadAssetAtPath(matName, typeof(Material));
                    k++;
                }
            }

            foreach (Material m in obUVobjectToMesh_map.Keys)
            {
                MultiMaterial mm = mom.resultMaterials[k] = new MultiMaterial();
                mm.sourceMaterials = new List <Material>();
                mm.sourceMaterials.Add(m);
                mm.considerMeshUVs = false;
                string   matName = folderPath + baseName + "-mat" + k + ".mat";
                Material newMat  = new Material(Shader.Find("Diffuse"));
                TextureCombineEntrance.ConfigureNewMaterialToMatchOld(newMat, m);
                AssetDatabase.CreateAsset(newMat, matName);
                mm.combinedMaterial = (Material)AssetDatabase.LoadAssetAtPath(matName, typeof(Material));
                k++;
            }
            SceneBakerUtilityInEditor.UpdateIfDirtyOrScript(textureBaker);
        }
Example #8
0
        /* tried to see if the MultiMaterialConfig could be done using the GroupBy filters. Saddly it didn't work  -_- */
        public static void ConfigureMutiMaterialsFromObjsToCombine2(TextureCombineEntrance mom, SerializedProperty resultMaterials, SerializedObject textureBaker)
        {
            if (mom.GetObjectsToCombine().Count == 0)
            {
                Debug.LogError("You need to add some objects to combine before building the multi material list.");
                return;
            }
            if (resultMaterials.arraySize > 0)
            {
                Debug.LogError("You already have some source to combined material mappings configured. You must remove these before doing this operation.");
                return;
            }
            if (mom.textureBakeResults == null)
            {
                Debug.LogError("Texture Bake Result asset must be set before using this operation.");
                return;
            }

            //validate that the objects to be combined are valid
            for (int i = 0; i < mom.GetObjectsToCombine().Count; i++)
            {
                GameObject go = mom.GetObjectsToCombine()[i];
                if (go == null)
                {
                    Debug.LogError("Null object in list of objects to combine at position " + i);
                    return;
                }
                Renderer r = go.GetComponent <Renderer>();
                if (r == null || (!(r is MeshRenderer) && !(r is SkinnedMeshRenderer)))
                {
                    Debug.LogError("GameObject at position " + i + " in list of objects to combine did not have a renderer");
                    return;
                }
                if (r.sharedMaterial == null)
                {
                    Debug.LogError("GameObject at position " + i + " in list of objects to combine has a null material");
                    return;
                }
            }

            IGroupByFilter[] filters = new IGroupByFilter[3];
            filters[0] = new GroupByOutOfBoundsUVs();
            filters[1] = new GroupByShader();
            filters[2] = new MB3_GroupByStandardShaderType();

            List <GameObjectFilterInfo> gameObjects = new List <GameObjectFilterInfo>();
            HashSet <GameObject>        objectsAlreadyIncludedInBakers = new HashSet <GameObject>();

            for (int i = 0; i < mom.GetObjectsToCombine().Count; i++)
            {
                GameObjectFilterInfo goaw = new GameObjectFilterInfo(mom.GetObjectsToCombine()[i], objectsAlreadyIncludedInBakers, filters);
                if (goaw.materials.Length > 0) //don't consider renderers with no materials
                {
                    gameObjects.Add(goaw);
                }
            }

            //analyse meshes
            Dictionary <int, MeshAnalysisResult> meshAnalysisResultCache = new Dictionary <int, MeshAnalysisResult>();
            int totalVerts = 0;

            for (int i = 0; i < gameObjects.Count; i++)
            {
                //string rpt = String.Format("Processing {0} [{1} of {2}]", gameObjects[i].go.name, i, gameObjects.Count);
                //EditorUtility.DisplayProgressBar("Analysing Scene", rpt + " A", .6f);
                Mesh mm     = MeshBakerUtility.GetMesh(gameObjects[i].go);
                int  nVerts = 0;
                if (mm != null)
                {
                    nVerts += mm.vertexCount;
                    MeshAnalysisResult mar;
                    if (!meshAnalysisResultCache.TryGetValue(mm.GetInstanceID(), out mar))
                    {
                        //EditorUtility.DisplayProgressBar("Analysing Scene", rpt + " Check Out Of Bounds UVs", .6f);
                        MeshBakerUtility.hasOutOfBoundsUVs(mm, ref mar);
                        //Rect dummy = mar.uvRect;
                        MeshBakerUtility.doSubmeshesShareVertsOrTris(mm, ref mar);
                        meshAnalysisResultCache.Add(mm.GetInstanceID(), mar);
                    }
                    if (mar.hasOutOfBoundsUVs)
                    {
                        int w = (int)mar.uvRect.width;
                        int h = (int)mar.uvRect.height;
                        gameObjects[i].outOfBoundsUVs = true;
                        gameObjects[i].warning       += " [WARNING: has uvs outside the range (0,1) tex is tiled " + w + "x" + h + " times]";
                    }
                    if (mar.hasOverlappingSubmeshVerts)
                    {
                        gameObjects[i].submeshesOverlap = true;
                        gameObjects[i].warning         += " [WARNING: Submeshes share verts or triangles. 'Multiple Combined Materials' feature may not work.]";
                    }
                }
                totalVerts += nVerts;
                //EditorUtility.DisplayProgressBar("Analysing Scene", rpt + " Validate OBuvs Multi Material", .6f);
                Renderer mr = gameObjects[i].go.GetComponent <Renderer>();
                if (!MeshBakerUtility.AreAllSharedMaterialsDistinct(mr.sharedMaterials))
                {
                    gameObjects[i].warning += " [WARNING: Object uses same material on multiple submeshes. This may produce poor results when used with multiple materials or fix out of bounds uvs.]";
                }
            }

            List <GameObjectFilterInfo> objsNotAddedToBaker = new List <GameObjectFilterInfo>();

            Dictionary <GameObjectFilterInfo, List <List <GameObjectFilterInfo> > > gs2bakeGroupMap = null;//MB3_MeshBakerEditorWindow.sortIntoBakeGroups3(gameObjects, objsNotAddedToBaker, filters, false, mom.maxAtlasSize);

            mom.resultMaterials = new MultiMaterial[gs2bakeGroupMap.Keys.Count];
            string pth        = AssetDatabase.GetAssetPath(mom.textureBakeResults);
            string baseName   = Path.GetFileNameWithoutExtension(pth);
            string folderPath = pth.Substring(0, pth.Length - baseName.Length - 6);
            int    k          = 0;

            foreach (GameObjectFilterInfo m in gs2bakeGroupMap.Keys)
            {
                MultiMaterial mm = mom.resultMaterials[k] = new MultiMaterial();
                mm.sourceMaterials = new List <Material>();
                mm.sourceMaterials.Add(m.materials[0]);
                string   matName = folderPath + baseName + "-mat" + k + ".mat";
                Material newMat  = new Material(Shader.Find("Diffuse"));
                TextureCombineEntrance.ConfigureNewMaterialToMatchOld(newMat, m.materials[0]);
                AssetDatabase.CreateAsset(newMat, matName);
                mm.combinedMaterial = (Material)AssetDatabase.LoadAssetAtPath(matName, typeof(Material));
                k++;
            }
            SceneBakerUtilityInEditor.UpdateIfDirtyOrScript(textureBaker);
        }
        /// <summary>
        ///  Bakes a combined mesh.
        ///  如果是从Inspector代码中调用的,则传入该组件的SerializedObject
        ///  对于“烘焙到预制”可能会损坏SerializedObject。这是必需的
        /// </summary>
        public static bool BakeIntoCombined(MeshBakerCommon mom, out bool createdDummyTextureBakeResults, ref SerializedObject so)
        {
            OutputOptions prefabOrSceneObject = mom.meshCombiner.outputOption;

            createdDummyTextureBakeResults = false;
            if (prefabOrSceneObject != OutputOptions.bakeIntoPrefab && prefabOrSceneObject != OutputOptions.bakeIntoSceneObject)
            {
                Debug.LogError("Paramater prefabOrSceneObject must be bakeIntoPrefab or bakeIntoSceneObject");
                return(false);
            }

            //从父物体获得 贴图合并组件及其贴图合并结果 Asset
            TextureCombineEntrance tb = mom.GetComponentInParent <TextureCombineEntrance>();

            if (mom.textureBakeResults == null && tb != null)
            {
                mom.textureBakeResults = tb.textureBakeResults;
            }
            //贴图合并结果为空时,则创建
            if (mom.textureBakeResults == null)
            {
                if (_OkToCreateDummyTextureBakeResult(mom))
                {
                    createdDummyTextureBakeResults = true;
                    List <GameObject> gos = mom.GetObjectsToCombine();
                    if (mom.GetNumObjectsInCombined() > 0)
                    {
                        if (mom.clearBuffersAfterBake)
                        {
                            mom.ClearMesh();
                        }
                        else
                        {
                            Debug.LogError("'Texture Bake Result' must be set to add more objects to a combined mesh that " +
                                           "already contains objects. Try enabling 'clear buffers after bake'");
                            return(false);
                        }
                    }
                    mom.textureBakeResults = TextureBakeResults.CreateForMaterialsOnRenderer(
                        gos.ToArray(),
                        mom.meshCombiner.GetMaterialsOnTargetRenderer());
                    Debug.Log("'Texture Bake Result' was not set. " +
                              "Creating a temporary one. Each material will be mapped to a separate submesh.");
                }
            }

            //合并检测
            ValidationLevel vl = Application.isPlaying ? ValidationLevel.quick : ValidationLevel.robust;

            if (!MeshBakerRoot.DoCombinedValidate(mom, ObjsToCombineTypes.sceneObjOnly, new EditorMethods(), vl))
            {
                return(false);
            }

            //检测空预制体资源是否已创建
            if (prefabOrSceneObject == OutputOptions.bakeIntoPrefab &&
                mom.resultPrefab == null)
            {
                Debug.LogError("Need to set the Combined Mesh Prefab field. " +
                               "Create a prefab asset, drag an empty game object into it, and drag it to the 'Combined Mesh Prefab' field.");
                return(false);
            }

            if (mom.meshCombiner.resultSceneObject != null &&
                (SceneBakerUtilityInEditor.GetPrefabType(mom.meshCombiner.resultSceneObject) == PrefabType.modelPrefab ||
                 SceneBakerUtilityInEditor.GetPrefabType(mom.meshCombiner.resultSceneObject) == PrefabType.prefab))
            {
                Debug.LogWarning("Result Game Object was a project asset not a scene object instance. Clearing this field.");
                mom.meshCombiner.resultSceneObject = null;
            }

            mom.ClearMesh();

            //合并
            if (mom.AddDeleteGameObjects(mom.GetObjectsToCombine().ToArray(), null, false))
            {
                mom.Apply(UnwrapUV2);
                if (createdDummyTextureBakeResults)
                {
                    //临时合并的贴图
                    Debug.Log(String.Format("Successfully baked {0} meshes each material is mapped to its own submesh.",
                                            mom.GetObjectsToCombine().Count));
                }
                else
                {
                    Debug.Log(String.Format("Successfully baked {0} meshes", mom.GetObjectsToCombine().Count));
                }


                if (prefabOrSceneObject == OutputOptions.bakeIntoSceneObject)
                {
                    PrefabType pt = SceneBakerUtilityInEditor.GetPrefabType(mom.meshCombiner.resultSceneObject);
                    if (pt == PrefabType.prefab || pt == PrefabType.modelPrefab)
                    {
                        Debug.LogError("Combined Mesh Object is a prefab asset. " +
                                       "If output option bakeIntoSceneObject then this must be an instance in the scene.");
                        return(false);
                    }
                }
                else if (prefabOrSceneObject == OutputOptions.bakeIntoPrefab)
                {
                    string prefabPth = AssetDatabase.GetAssetPath(mom.resultPrefab);
                    if (prefabPth == null || prefabPth.Length == 0)
                    {
                        Debug.LogError("无法保存,合并游戏物体并非磁盘上的资源。");
                        return(false);
                    }
                    string baseName    = Path.GetFileNameWithoutExtension(prefabPth);
                    string folderPath  = prefabPth.Substring(0, prefabPth.Length - baseName.Length - 7);
                    string newFilename = folderPath + baseName + "-mesh";

                    //保存网格资源
                    SaveMeshsToAssetDatabase(mom, folderPath, newFilename);

                    if (mom.meshCombiner.renderType == RendererType.skinnedMeshRenderer)
                    {
                        Debug.LogWarning("Render type is skinned mesh renderer. " +
                                         "Can't create prefab until all bones have been added to the combined mesh object " + mom.resultPrefab +
                                         " Add the bones then drag the combined mesh object to the prefab.");
                    }
                    //构建 Prefab
                    RebuildPrefab(mom, ref so);

                    MeshBakerUtility.Destroy(mom.meshCombiner.resultSceneObject);
                }
                else
                {
                    Debug.LogError("合并输出类型出错");
                    return(false);
                }
            }
            else
            {
                //加入合并失败
                if (mom.clearBuffersAfterBake)
                {
                    mom.meshCombiner.ClearBuffers();
                }
                if (createdDummyTextureBakeResults)
                {
                    MeshBakerUtility.Destroy(mom.textureBakeResults);
                }
                return(false);
            }

            //清除缓存数据
            if (mom.clearBuffersAfterBake)
            {
                mom.meshCombiner.ClearBuffers();
            }
            //临时Texture
            if (createdDummyTextureBakeResults)
            {
                MeshBakerUtility.Destroy(mom.textureBakeResults);
            }
            return(true);
        }