/// <summary>
        /// 合并游戏物体列表,空物体,重复物体,空材质,网格验证
        /// </summary>
        /// <param name="gameObjectsToMesh"></param>
        /// <returns></returns>
        private static bool ValidateCombineGameObject(List <GameObject> gameObjectsToMesh)
        {
            //网格分析结果缓存
            Dictionary <int, MeshAnalysisResult> meshAnalysisResultCache =
                new Dictionary <int, MeshAnalysisResult>();;
            //获取将合并网格的游戏物体
            List <GameObject> objsToMesh = gameObjectsToMesh;

            for (int i = 0; i < objsToMesh.Count; i++)
            {
                GameObject go = objsToMesh[i];
                if (go == null)
                {
                    Debug.LogError("合并网格游戏物体列表中包含 null 物体,在位置" + i);
                    return(false);
                }
                for (int j = i + 1; j < objsToMesh.Count; j++)
                {
                    if (objsToMesh[i] == objsToMesh[j])
                    {
                        Debug.LogError("合并网格游戏物体列表中包含重复游戏物体 " + i + " 和 " + j);
                        return(false);
                    }
                }
                if (MeshBakerUtility.GetGOMaterials(go).Length == 0)
                {
                    Debug.LogError("游戏物体 " + go + " 没有材质");
                    return(false);
                }
                Mesh m = MeshBakerUtility.GetMesh(go);
                if (m == null)
                {
                    Debug.LogError("合并网格游戏物体列表中, " + go + " 没有网格 ");
                    return(false);
                }
                if (m != null)
                {
                    //This check can be very expensive and it only warns so only do this if we are in the editor.
                    if (!Application.isEditor && Application.isPlaying && combineData.DoMultiMaterial)
                    {
                        MeshAnalysisResult mar;
                        if (!meshAnalysisResultCache.TryGetValue(m.GetInstanceID(), out mar))
                        {
                            MeshBakerUtility.doSubmeshesShareVertsOrTris(m, ref mar);
                            meshAnalysisResultCache.Add(m.GetInstanceID(), mar);
                        }
                        //检查重叠的子网格顶点
                        if (mar.hasOverlappingSubmeshVerts)
                        {
                            Debug.LogWarning("游戏物体 " + objsToMesh[i] + " has overlapping submeshes (submeshes share vertices)." +
                                             "If the UVs associated with the shared vertices are important then this bake may not work. " +
                                             "If you are using multiple materials then this object can only be combined with objects that use the exact same set of textures " +
                                             "(each atlas contains one texture). There may be other undesirable side affects as well. Mesh Master, " +
                                             "available in the asset store can fix overlapping submeshes.");
                        }
                    }
                }
            }
            return(true);
        }
Exemple #2
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);
        }
Exemple #3
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);
        }
Exemple #4
0
        public GameObjectFilterInfo(GameObject g, HashSet <GameObject> objsAlreadyInBakers, IGroupByFilter[] filts)
        {
            go = g;
            Renderer           r         = MeshBakerUtility.GetRenderer(g);
            HashSet <Material> matsSet   = new HashSet <Material>();
            HashSet <Shader>   shaderSet = new HashSet <Shader>();

            if (r is SkinnedMeshRenderer)
            {
                isMeshRenderer = false;
            }
            else
            {
                isMeshRenderer = true;
            }
            materials = r.sharedMaterials;
            for (int i = 0; i < materials.Length; i++)
            {
                if (materials[i] != null)
                {
                    matsSet.Add(materials[i]);
                    shaderSet.Add(materials[i].shader);
                }
            }
            materials = new Material[matsSet.Count];
            matsSet.CopyTo(materials);
            shaders = new Shader[shaderSet.Count];
            standardShaderBlendModes = new StandardShaderBlendMode[matsSet.Count];

            shaderSet.CopyTo(shaders);

            Array.Sort(materials, new NameComparer());
            Array.Sort(shaders, new NameComparer());

            List <string> standardShaderBlendModesNameSet = new List <string>();

            for (int i = 0; i < materials.Length; i++)
            {
                if (materials[i].shader.name.StartsWith("Standard") && materials[i].HasProperty("_Mode"))
                {
                    standardShaderBlendModes[i] = (StandardShaderBlendMode)materials[i].GetFloat("_Mode");
                }
                else
                {
                    standardShaderBlendModes[i] = StandardShaderBlendMode.NotApplicable;
                }
                if (!standardShaderBlendModesNameSet.Contains(standardShaderBlendModes[i].ToString()))
                {
                    standardShaderBlendModesNameSet.Add(standardShaderBlendModes[i].ToString());
                }
                materialName += (materials[i] == null ? "null" : materials[i].name);
                if (i < materials.Length - 1)
                {
                    materialName += ",";
                }
            }
            standardShaderBlendModesName = "";
            standardShaderBlendModesNameSet.Sort();
            foreach (string modeName in standardShaderBlendModesNameSet)
            {
                standardShaderBlendModesName += modeName + ",";
            }
            for (int i = 0; i < shaders.Length; i++)
            {
                shaderName += (shaders[i] == null ? "null" : shaders[i].name);
                if (i < shaders.Length - 1)
                {
                    shaderName += ",";
                }
            }

            lightmapIndex = r.lightmapIndex;
            Mesh mesh = MeshBakerUtility.GetMesh(g);

            numVerts = 0;
            if (mesh != null)
            {
                numVerts = mesh.vertexCount;
            }
            isStatic           = go.isStatic;
            numMaterials       = materials.Length;
            warning            = "";
            alreadyInBakerList = objsAlreadyInBakers.Contains(g);
            outOfBoundsUVs     = false;
            submeshesOverlap   = false;
            filters            = filts;
        }
Exemple #5
0
        public static bool DoCombinedValidate(MeshBakerRoot mom, MB_ObjsToCombineTypes objToCombineType, MBValidationLevel validationLevel)
        {
            if (mom.textureBakeResults == null)
            {
                Debug.LogError("Need to set Material Bake Result on " + mom);
                return(false);
            }
            if (mom is MeshBakerCommon)
            {
                MeshBakerCommon momMB = (MeshBakerCommon)mom;
                TextureBaker    tb    = momMB.GetTextureBaker();
                if (tb != null && tb.textureBakeResults != mom.textureBakeResults)
                {
                    Debug.LogWarning("Material Bake Result on this component is not the same as the Material Bake Result on the MB3_TextureBaker.");
                }
            }

            Dictionary <int, MeshBakerUtility.MeshAnalysisResult> meshAnalysisResultCache = null;

            if (validationLevel == MBValidationLevel.robust)
            {
                meshAnalysisResultCache = new Dictionary <int, MeshBakerUtility.MeshAnalysisResult>();
            }
            List <GameObject> objsToMesh = mom.GetObjectsToCombine();

            for (int i = 0; i < objsToMesh.Count; i++)
            {
                GameObject go = objsToMesh[i];
                if (go == null)
                {
                    Debug.LogError("The list of objects to combine contains a null at position." + i + " Select and use [shift] delete to remove");
                    return(false);
                }
                for (int j = i + 1; j < objsToMesh.Count; j++)
                {
                    if (objsToMesh[i] == objsToMesh[j])
                    {
                        Debug.LogError("The list of objects to combine contains duplicates at " + i + " and " + j);
                        return(false);
                    }
                }
                if (MeshBakerUtility.GetGOMaterials(go) == null)
                {
                    Debug.LogError("Object " + go + " in the list of objects to be combined does not have a material");
                    return(false);
                }
                Mesh m = MeshBakerUtility.GetMesh(go);
                if (m == null)
                {
                    Debug.LogError("Object " + go + " in the list of objects to be combined does not have a mesh");
                    return(false);
                }
                if (m != null)              //This check can be very expensive and it only warns so only do this if we are in the editor.
                {
                    if (!Application.isEditor &&
                        Application.isPlaying &&
                        mom.textureBakeResults.doMultiMaterial &&
                        validationLevel >= MBValidationLevel.robust)
                    {
                        MeshBakerUtility.MeshAnalysisResult mar;
                        if (!meshAnalysisResultCache.TryGetValue(m.GetInstanceID(), out mar))
                        {
                            MeshBakerUtility.doSubmeshesShareVertsOrTris(m, ref mar);
                            meshAnalysisResultCache.Add(m.GetInstanceID(), mar);
                        }
                        if (mar.hasOverlappingSubmeshVerts)
                        {
                            Debug.LogWarning("Object " + objsToMesh[i] + " in the list of objects to combine has overlapping submeshes (submeshes share vertices). If the UVs associated with the shared vertices are important then this bake may not work. If you are using multiple materials then this object can only be combined with objects that use the exact same set of textures (each atlas contains one texture). There may be other undesirable side affects as well. Mesh Master, available in the asset store can fix overlapping submeshes.");
                        }
                    }
                }
            }


            List <GameObject> objs = objsToMesh;

            if (mom is MeshBaker)
            {
                objs = mom.GetObjectsToCombine();
                //if (((MB3_MeshBaker)mom).useObjsToMeshFromTexBaker && tb != null) objs = tb.GetObjectsToCombine();
                if (objs == null || objs.Count == 0)
                {
                    Debug.LogError("No meshes to combine. Please assign some meshes to combine.");
                    return(false);
                }
            }

            return(true);
        }
Exemple #6
0
        /// <summary>
        /// 第一步:
        /// 写入 TexturePipelineData 的 MaterialPropTexturesSet 列表,和 usedObjsToMesh 列表
        /// 每个TexSet在 Atlas 中都是一个矩形。
        /// 如果 allowedMaterialsFilter (过滤器)为空,则将收集 allObjsToMesh 上的所有材质,usedObjsToMesh 将与allObjsToMesh相同
        /// 否则,将仅包括 allowedMaterialsFilter 中的材质,usedObjsToMesh将是使用这些材料的objs。
        /// </summary>
        internal static void Step1_CollectDistinctMatTexturesAndUsedObjects(TextureCombinePipelineData data,
                                                                            EditorMethodsInterface textureEditorMethods,
                                                                            List <GameObject> usedObjsToMesh)
        {
            // 收集UsedObjects上不同的材质纹理
            bool outOfBoundsUVs = false;
            Dictionary <int, MeshAnalysisResult[]> meshAnalysisResultsCache = new Dictionary <int, MeshAnalysisResult[]>(); //cache results

            for (int i = 0; i < data.allObjsToMesh.Count; i++)
            {
                GameObject obj = data.allObjsToMesh[i];

                if (obj == null)
                {
                    Debug.LogError("合并游戏物体列表中包含空物体");
                    return;
                }

                Mesh sharedMesh = MeshBakerUtility.GetMesh(obj);
                if (sharedMesh == null)
                {
                    Debug.LogError("游戏物体 " + obj.name + " 网格为空");
                    return;
                }

                Material[] sharedMaterials = MeshBakerUtility.GetGOMaterials(obj);
                if (sharedMaterials.Length == 0)
                {
                    Debug.LogError("游戏物体 " + obj.name + " 材质为空.");
                    return;
                }

                //analyze mesh or grab cached result of previous analysis, stores one result for each submesh
                //处理网格数据
                MeshAnalysisResult[] meshAnalysisResults; //每个游戏物体的主网格子网格数据数组
                if (!meshAnalysisResultsCache.TryGetValue(sharedMesh.GetInstanceID(), out meshAnalysisResults))
                {                                         //获取参与合并物体的网格分析数据
                    meshAnalysisResults = new MeshAnalysisResult[sharedMesh.subMeshCount];
                    for (int j = 0; j < sharedMesh.subMeshCount; j++)
                    {
                        MeshBakerUtility.hasOutOfBoundsUVs(sharedMesh, ref meshAnalysisResults[j], j);
                        if (data.normalizeTexelDensity)
                        {
                            meshAnalysisResults[j].submeshArea = GetSubmeshArea(sharedMesh, j);
                        }

                        if (data.fixOutOfBoundsUVs && !meshAnalysisResults[j].hasUVs)
                        {
                            meshAnalysisResults[j].uvRect = new Rect(0, 0, 1, 1);
                            Debug.LogWarning("Mesh for object " + obj + " has no UV channel but 'consider UVs' is enabled." +
                                             " Assuming UVs will be generated filling 0,0,1,1 rectangle.");
                        }
                    }
                    meshAnalysisResultsCache.Add(sharedMesh.GetInstanceID(), meshAnalysisResults);
                }

                //处理材质数据
                for (int matIdx = 0; matIdx < sharedMaterials.Length; matIdx++)
                {
                    Material mat = sharedMaterials[matIdx];

                    // 材质过滤器
                    if (data.allowedMaterialsFilter != null &&
                        !data.allowedMaterialsFilter.Contains(mat))
                    {
                        continue;
                    }

                    outOfBoundsUVs = outOfBoundsUVs || meshAnalysisResults[matIdx].hasOutOfBoundsUVs;

                    if (mat.name.Contains("(Instance)"))
                    {
                        Debug.LogError("The sharedMaterial on object " + obj.name + " has been 'Instanced'." +
                                       " This was probably caused by a script accessing the meshRender.material property in the editor. " +
                                       " The material to UV Rectangle mapping will be incorrect. " +
                                       "To fix this recreate the object from its prefab or re-assign its material from the correct asset.");
                        return;
                    }

                    if (data.fixOutOfBoundsUVs)
                    {
                        if (!MeshBakerUtility.AreAllSharedMaterialsDistinct(sharedMaterials))
                        {
                            Debug.LogWarning("游戏物体 " + obj.name + " 使用相同的材质在多个子网格. " +
                                             "可能生成奇怪的 resultAtlasesAndRects,尤其是与 _fixOutOfBoundsUVs 为 true 时");
                        }
                    }

                    //材质属性 Texutre 信息
                    MaterialPropTexture[] mts = new MaterialPropTexture[data.texPropertyNames.Count];
                    for (int propIdx = 0; propIdx < data.texPropertyNames.Count; propIdx++)
                    {
                        Texture tx           = null;
                        Vector2 scale        = Vector2.one;
                        Vector2 offset       = Vector2.zero;
                        float   texelDensity = 0f;
                        if (mat.HasProperty(data.texPropertyNames[propIdx].name))
                        {
                            Texture txx = GetTextureConsideringStandardShaderKeywords(data.ResultMaterial.shader.name, mat, data.texPropertyNames[propIdx].name);
                            if (txx != null)
                            {
                                if (txx is Texture2D)
                                {
                                    //TextureFormat 验证
                                    tx = txx;
                                    TextureFormat f           = ((Texture2D)tx).format;
                                    bool          isNormalMap = false;
                                    if (!Application.isPlaying && textureEditorMethods != null)
                                    {
                                        isNormalMap = textureEditorMethods.IsNormalMap((Texture2D)tx);
                                    }
                                    if ((f == TextureFormat.ARGB32 ||
                                         f == TextureFormat.RGBA32 ||
                                         f == TextureFormat.BGRA32 ||
                                         f == TextureFormat.RGB24 ||
                                         f == TextureFormat.Alpha8) && !isNormalMap) //DXT5 does not work
                                    {
                                        //可使用
                                    }
                                    else
                                    {
                                        //TRIED to copy texture using tex2.SetPixels(tex1.GetPixels()) but bug in 3.5 means DTX1 and 5 compressed textures come out skewe
                                        //尝试使用tex2.SetPixels(tex1.GetPixels())复制纹理,但是3.5中的bug意味着DTX1和5压缩纹理出现扭曲
                                        if (Application.isPlaying && data.packingAlgorithm != PackingAlgorithmEnum.MeshBakerTexturePacker_Fast)
                                        {
                                            Debug.LogWarning("合并列表中,游戏物体 " + obj.name + " 所使用的 Texture " +
                                                             tx.name + " 使用的格式 " + f +
                                                             "不是: ARGB32, RGBA32, BGRA32, RGB24, Alpha8 或 DXT. " +
                                                             "无法在运行时重新设置尺寸" +
                                                             "If format says 'compressed' try changing it to 'truecolor'");
                                            return;
                                        }
                                        else
                                        {
                                            tx = (Texture2D)mat.GetTexture(data.texPropertyNames[propIdx].name);
                                        }
                                    }
                                }
                                else
                                {
                                    Debug.LogError("合并列表中,游戏物体 " + obj.name + " 渲染网格使用的 Texture 不是 Texture2D. ");
                                    return;
                                }
                            }
                            //像素密度
                            if (tx != null && data.normalizeTexelDensity)
                            {
                                //不考虑平铺和UV采样超出范围
                                if (meshAnalysisResults[propIdx].submeshArea == 0)
                                {
                                    texelDensity = 0f;
                                }
                                else
                                {
                                    texelDensity = (tx.width * tx.height) / (meshAnalysisResults[propIdx].submeshArea);
                                }
                            }
                            //规格,偏移
                            GetMaterialScaleAndOffset(mat, data.texPropertyNames[propIdx].name, out offset, out scale);
                        }

                        mts[propIdx] = new MaterialPropTexture(tx, offset, scale, texelDensity);
                    }

                    // 收集材质参数值的平均值
                    data.nonTexturePropertyBlender.CollectAverageValuesOfNonTextureProperties(data.ResultMaterial, mat);

                    Vector2 obUVscale  = new Vector2(meshAnalysisResults[matIdx].uvRect.width, meshAnalysisResults[matIdx].uvRect.height);
                    Vector2 obUVoffset = new Vector2(meshAnalysisResults[matIdx].uvRect.x, meshAnalysisResults[matIdx].uvRect.y);

                    //Add to distinct set of textures if not already there
                    TextureTilingTreatment tilingTreatment = TextureTilingTreatment.none;
                    if (data.fixOutOfBoundsUVs)
                    {
                        tilingTreatment = TextureTilingTreatment.considerUVs;
                    }

                    //合并信息 distinctMaterialTextures 数据设置

                    //材质各参数 Texture,及 UV 偏移数据映射
                    MaterialPropTexturesSet setOfTexs = new MaterialPropTexturesSet(mts, obUVoffset, obUVscale, tilingTreatment);  //one of these per submesh
                    //材质及各变化参数Rect 数据
                    MatAndTransformToMerged matt = new MatAndTransformToMerged(new DRect(obUVoffset, obUVscale), data.fixOutOfBoundsUVs, mat);

                    setOfTexs.matsAndGOs.mats.Add(matt);

                    MaterialPropTexturesSet setOfTexs2 = data.distinctMaterialTextures.Find(x => x.IsEqual(setOfTexs, data.fixOutOfBoundsUVs, data.nonTexturePropertyBlender));
                    if (setOfTexs2 != null)
                    {
                        setOfTexs = setOfTexs2;
                    }
                    else
                    {
                        data.distinctMaterialTextures.Add(setOfTexs);
                    }

                    if (!setOfTexs.matsAndGOs.mats.Contains(matt))
                    {
                        setOfTexs.matsAndGOs.mats.Add(matt);
                    }

                    if (!setOfTexs.matsAndGOs.gos.Contains(obj))
                    {
                        setOfTexs.matsAndGOs.gos.Add(obj);
                        //已使用 游戏物体
                        if (!usedObjsToMesh.Contains(obj))
                        {
                            usedObjsToMesh.Add(obj);
                        }
                    }
                }
            }

            Debug.Log(string.Format("第一阶段完成;" +
                                    "参与合并的游戏物体的不同材质,各自包含与shader属性对应的不同的纹理,收集到 {0} 组 textures,即 {0} 个不同的材质," +
                                    "fixOutOfBoundsUV:{1} " +
                                    "considerNonTextureProperties:{2}",
                                    data.distinctMaterialTextures.Count, data.fixOutOfBoundsUVs, data.considerNonTextureProperties));

            if (data.distinctMaterialTextures.Count == 0)
            {
                Debug.LogError("None of the source object materials matched any of the allowed materials for submesh with result material: " + data.ResultMaterial);
                return;
            }

            TextureCombinerMerging merger = new TextureCombinerMerging(data.considerNonTextureProperties,
                                                                       data.nonTexturePropertyBlender, data.fixOutOfBoundsUVs);

            merger.MergeOverlappingDistinctMaterialTexturesAndCalcMaterialSubrects(data.distinctMaterialTextures);
        }