Exemple #1
0
        internal static Texture2D _copyTexturesIntoAtlas(Texture2D[] texToPack, int padding, Rect[] rs, int w, int h, TextureCombineHandler combiner)
        {
            Texture2D ta = new Texture2D(w, h, TextureFormat.ARGB32, true);

            MeshBakerUtility.setSolidColor(ta, Color.clear);
            for (int i = 0; i < rs.Length; i++)
            {
                Rect      r      = rs[i];
                Texture2D t      = texToPack[i];
                Texture2D tmpTex = null;
                int       x      = Mathf.RoundToInt(r.x * w);
                int       y      = Mathf.RoundToInt(r.y * h);
                int       ww     = Mathf.RoundToInt(r.width * w);
                int       hh     = Mathf.RoundToInt(r.height * h);
                if (t.width != ww && t.height != hh)
                {
                    tmpTex = t = MeshBakerUtility.resampleTexture(t, ww, hh);
                }
                ta.SetPixels(x, y, ww, hh, t.GetPixels());
                if (tmpTex != null)
                {
                    MeshBakerUtility.Destroy(tmpTex);
                }
            }
            ta.Apply();
            return(ta);
        }
Exemple #2
0
        public void CreateColoredTexToReplaceNull(string propName, int propIdx, bool considerMeshUVs, TextureCombineHandler combiner, Color col)
        {
            MaterialPropTexture matTex = ts[propIdx];

            matTex.t = combiner._createTemporaryTexture(propName, 16, 16, TextureFormat.ARGB32, true);
            MeshBakerUtility.setSolidColor(matTex.GetTexture2D(), col);
        }
Exemple #3
0
        /// <summary>
        /// Updates the skinned mesh bounds by creating a bounding box that contains the bones (skeleton) of the source objects.
        /// 通过创建包含源对象的骨骼(骨架)的边界框来更新蒙皮的网格边界。
        /// </summary>
        public static void UpdateSkinnedMeshApproximateBoundsFromBoundsStatic(List <GameObject> objectsInCombined, SkinnedMeshRenderer smr)
        {
            Bounds b    = new Bounds();
            Bounds bigB = new Bounds();

            if (MeshBakerUtility.GetBounds(objectsInCombined[0], out b))
            {
                bigB = b;
            }
            else
            {
                Debug.LogError("Could not get bounds. Not updating skinned mesh bounds");
                return;
            }
            for (int i = 1; i < objectsInCombined.Count; i++)
            {
                if (MeshBakerUtility.GetBounds(objectsInCombined[i], out b))
                {
                    bigB.Encapsulate(b);
                }
                else
                {
                    Debug.LogError("Could not get bounds. Not updating skinned mesh bounds");
                    return;
                }
            }
            smr.localBounds = bigB;
        }
Exemple #4
0
 internal void _destroyAllTemporaryTextures()
 {
     Debug.Log("Destroying " + _temporaryTextures.Count + " temporary textures");
     for (int i = 0; i < _temporaryTextures.Count; i++)
     {
         MeshBakerUtility.Destroy(_temporaryTextures[i].texture);
     }
     _temporaryTextures.Clear();
 }
 internal BlendShape[] GetBlendShapes(Mesh m, int gameObjectID, GameObject gameObject)
 {
     if (MeshBakerUtility.GetMajorVersion() > 5 ||
         (MeshBakerUtility.GetMajorVersion() == 5 && MeshBakerUtility.GetMinorVersion() >= 3))
     {
         MeshChannels mc;
         if (!meshIDToMeshChannels.TryGetValue(m.GetInstanceID(), out mc))
         {
             mc = new MeshChannels();
             meshIDToMeshChannels.Add(m.GetInstanceID(), mc);
         }
         if (mc.blendShapes == null)
         {
             BlendShape[] shapes   = new BlendShape[m.blendShapeCount];
             int          arrayLen = m.vertexCount;
             for (int i = 0; i < shapes.Length; i++)
             {
                 BlendShape shape = shapes[i] = new BlendShape();
                 shape.frames        = new MBBlendShapeFrame[MeshBakerUtility.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 = MeshBakerUtility.GetBlendShapeFrameWeight(m, i, j);
                     frame.vertices    = new Vector3[arrayLen];
                     frame.normals     = new Vector3[arrayLen];
                     frame.tangents    = new Vector3[arrayLen];
                     MeshBakerUtility.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
             BlendShape[] shapes = new BlendShape[mc.blendShapes.Length];
             for (int i = 0; i < shapes.Length; i++)
             {
                 shapes[i]               = new BlendShape();
                 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 BlendShape[0]);
     }
 }
Exemple #6
0
        internal Texture2D _createTextureCopy(string propertyName, Texture2D t)
        {
            Texture2D tx = MeshBakerUtility.createTextureCopy(t);

            tx.name = string.Format("tmpCopy{0}_{1}x{2}", _temporaryTextures.Count, tx.width, tx.height);
            TemporaryTexture txx = new TemporaryTexture(propertyName, tx);

            _temporaryTextures.Add(txx);
            return(tx);
        }
Exemple #7
0
        internal Texture2D _resizeTexture(string propertyName, Texture2D t, int w, int h)
        {
            Texture2D tx = MeshBakerUtility.resampleTexture(t, w, h);

            tx.name = string.Format("tmpResampled{0}_{1}x{2}", _temporaryTextures.Count, w, h);
            TemporaryTexture txx = new TemporaryTexture(propertyName, tx);

            _temporaryTextures.Add(txx);
            return(tx);
        }
Exemple #8
0
        //used to track temporary textures that were created so they can be destroyed
        public Texture2D _createTemporaryTexture(string propertyName, int w, int h, TextureFormat texFormat, bool mipMaps)
        {
            Texture2D t = new Texture2D(w, h, texFormat, mipMaps);

            t.name = string.Format("tmp{0}_{1}x{2}", _temporaryTextures.Count, w, h);
            MeshBakerUtility.setSolidColor(t, Color.clear);
            TemporaryTexture txx = new TemporaryTexture(propertyName, t);

            _temporaryTextures.Add(txx);
            return(t);
        }
Exemple #9
0
        /// <summary>
        /// Creates the atlases.创建图集
        /// saveAtlasesAsAssets 创建图集并保存至项目资源目录,或者内存中
        /// editorMethods 贴图格式编辑器方法
        /// </summary>
        public AtlasesAndRects[] CreateAtlases(ProgressUpdateDelegate progressInfo,
                                               bool saveAtlasesAsAssets             = false,
                                               EditorMethodsInterface editorMethods = null)
        {
            AtlasesAndRects[] resultAtlasesAndRects = null;
            try
            {
                _coroutineResult = new CreateAtlasesCoroutineResult();

                TextureCombineHandler.RunCorutineWithoutPause(
                    CreateAtlasesCoroutine(progressInfo, _coroutineResult, saveAtlasesAsAssets, editorMethods, 1000f), 0);
                if (_coroutineResult.success && textureBakeResults != null)
                {
                    resultAtlasesAndRects = this.OnCombinedTexturesCoroutineAtlasesAndRects;
                }
            }
            catch (Exception e)
            {
                Debug.LogError(e);
            }
            finally
            {
                if (saveAtlasesAsAssets)
                { //Atlases were saved to project so we don't need these ones
                    if (resultAtlasesAndRects != null)
                    {
                        for (int j = 0; j < resultAtlasesAndRects.Length; j++)
                        {
                            AtlasesAndRects mAndA = resultAtlasesAndRects[j];
                            if (mAndA != null && mAndA.atlases != null)
                            {
                                for (int i = 0; i < mAndA.atlases.Length; i++)
                                {
                                    if (mAndA.atlases[i] != null)
                                    {
                                        if (editorMethods != null)
                                        {
                                            editorMethods.Destroy(mAndA.atlases[i]);
                                        }
                                        else
                                        {
                                            MeshBakerUtility.Destroy(mAndA.atlases[i]);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            return(resultAtlasesAndRects);
        }
 Vector3[] _getMeshNormals(Mesh m)
 {
     Vector3[] ns = m.normals;
     if (ns.Length == 0)
     {
         //MB2_Log.LogDebug("Mesh " + m + " has no normals. Generating");
         Debug.LogWarning("Mesh " + m + " didn't have normals. Generating normals.");
         Mesh tempMesh = (Mesh)GameObject.Instantiate(m);
         tempMesh.RecalculateNormals();
         ns = tempMesh.normals;
         MeshBakerUtility.Destroy(tempMesh);
     }
     return(ns);
 }
        internal Vector2[] GetUv4(Mesh m)
        {
            MeshChannels mc;

            if (!meshIDToMeshChannels.TryGetValue(m.GetInstanceID(), out mc))
            {
                mc = new MeshChannels();
                meshIDToMeshChannels.Add(m.GetInstanceID(), mc);
            }
            if (mc.uv4 == null)
            {
                mc.uv4 = MeshBakerUtility.GetMeshUV3orUV4(m, false);
            }
            return(mc.uv4);
        }
Exemple #12
0
        internal void _destroyTemporaryTextures(string propertyName)
        {
            int numDestroyed = 0;

            for (int i = _temporaryTextures.Count - 1; i >= 0; i--)
            {
                if (_temporaryTextures[i].property.Equals(propertyName))
                {
                    numDestroyed++;
                    MeshBakerUtility.Destroy(_temporaryTextures[i].texture);
                    _temporaryTextures.RemoveAt(i);
                }
            }
            Debug.Log("Destroying " + numDestroyed + " temporary textures " + propertyName + " num remaining " + _temporaryTextures.Count);
        }
        internal BoneWeight[] GetBoneWeights(Renderer r, int numVertsInMeshBeingAdded)
        {
            MeshChannels mc;
            Mesh         m = MeshBakerUtility.GetMesh(r.gameObject);

            if (!meshIDToMeshChannels.TryGetValue(m.GetInstanceID(), out mc))
            {
                mc = new MeshChannels();
                meshIDToMeshChannels.Add(m.GetInstanceID(), mc);
            }
            if (mc.boneWeights == null)
            {
                mc.boneWeights = _getBoneWeights(r, numVertsInMeshBeingAdded);
            }
            return(mc.boneWeights);
        }
        internal Matrix4x4[] GetBindposes(Renderer r)
        {
            MeshChannels mc;
            Mesh         m = MeshBakerUtility.GetMesh(r.gameObject);

            if (!meshIDToMeshChannels.TryGetValue(m.GetInstanceID(), out mc))
            {
                mc = new MeshChannels();
                meshIDToMeshChannels.Add(m.GetInstanceID(), mc);
            }
            if (mc.bindPoses == null)
            {
                mc.bindPoses = _getBindPoses(r);
            }
            return(mc.bindPoses);
        }
Exemple #15
0
        public bool YisFlipped()
        {
            string graphicsDeviceVersion = SystemInfo.graphicsDeviceVersion.ToLower();
            bool   flipY;

            if (!MeshBakerUtility.GraphicsUVStartsAtTop())
            {
                flipY = false;
            }
            else
            {
                // "opengl es, direct3d"
                flipY = true;
            }

            Debug.Log("Graphics device version is: " + graphicsDeviceVersion + " flipY:" + flipY);
            return(flipY);
        }
Exemple #16
0
        public void EnableDisableSourceObjectRenderers(bool show)
        {
            for (int i = 0; i < GetObjectsToCombine().Count; i++)
            {
                GameObject go = GetObjectsToCombine()[i];
                if (go != null)
                {
                    Renderer mr = MeshBakerUtility.GetRenderer(go);
                    if (mr != null)
                    {
                        mr.enabled = show;
                    }

                    LODGroup lodG = mr.GetComponentInParent <LODGroup>();
                    if (lodG != null)
                    {
                        bool  isOnlyInGroup = true;
                        LOD[] lods          = lodG.GetLODs();
                        for (int j = 0; j < lods.Length; j++)
                        {
                            for (int k = 0; k < lods[j].renderers.Length; k++)
                            {
                                if (lods[j].renderers[k] != mr)
                                {
                                    isOnlyInGroup = false;
                                    break;
                                }
                            }
                        }

                        if (isOnlyInGroup)
                        {
                            lodG.enabled = show;
                        }
                    }
                }
            }
        }
Exemple #17
0
        /// <summary>
        /// 多材质验证
        /// </summary>
        /// <returns></returns>
        bool _ValidateResultMaterials()
        {
            HashSet <Material> allMatsOnObjs = new HashSet <Material>();

            for (int i = 0; i < objsToMesh.Count; i++)
            {
                if (objsToMesh[i] != null)
                {
                    Material[] ms = MeshBakerUtility.GetGOMaterials(objsToMesh[i]);
                    for (int j = 0; j < ms.Length; j++)
                    {
                        if (ms[j] != null)
                        {
                            allMatsOnObjs.Add(ms[j]);
                        }
                    }
                }
            }

            //多材质判断
            HashSet <Material> allMatsInMapping = new HashSet <Material>();

            for (int i = 0; i < resultMaterials.Length; i++)
            {
                //查重
                for (int j = i + 1; j < resultMaterials.Length; j++)
                {
                    if (resultMaterials[i].combinedMaterial == resultMaterials[j].combinedMaterial)
                    {
                        Debug.LogError(String.Format("Source To Combined Mapping: Submesh {0} and Submesh {1} use the same combined material. These should be different", i, j));
                        return(false);
                    }
                }

                //判空
                MultiMaterial mm = resultMaterials[i];
                if (mm.combinedMaterial == null)
                {
                    Debug.LogError("Combined Material is null please create and assign a result material.");
                    return(false);
                }
                Shader targShader = mm.combinedMaterial.shader;
                for (int j = 0; j < mm.sourceMaterials.Count; j++)
                {
                    if (mm.sourceMaterials[j] == null)
                    {
                        Debug.LogError("There are null entries in the list of Source Materials");
                        return(false);
                    }
                    if (targShader != mm.sourceMaterials[j].shader)
                    {
                        Debug.LogWarning("Source material " + mm.sourceMaterials[j] + " does not use shader " + targShader + " it may not have the required textures. If not empty textures will be generated.");
                    }
                    if (allMatsInMapping.Contains(mm.sourceMaterials[j]))
                    {
                        Debug.LogError("A Material " + mm.sourceMaterials[j] + " appears more than once in the list of source materials in the source material to combined mapping. Each source material must be unique.");
                        return(false);
                    }
                    allMatsInMapping.Add(mm.sourceMaterials[j]);
                }
            }

            if (allMatsOnObjs.IsProperSubsetOf(allMatsInMapping))
            {
                allMatsInMapping.ExceptWith(allMatsOnObjs);
                Debug.LogWarning("There are materials in the mapping that are not used on your source objects: " + PrintSet(allMatsInMapping));
            }
            if (resultMaterials != null && resultMaterials.Length > 0 && allMatsInMapping.IsProperSubsetOf(allMatsOnObjs))
            {
                allMatsOnObjs.ExceptWith(allMatsInMapping);
                Debug.LogError("There are materials on the objects to combine that are not in the mapping: " + PrintSet(allMatsOnObjs));
                return(false);
            }
            return(true);
        }
Exemple #18
0
        public void SuggestTreatment(List <GameObject> objsToMesh, Material[] resultMaterials, List <ShaderTextureProperty> _customShaderPropNames)
        {
            this._customShaderPropNames = _customShaderPropNames;
            StringBuilder sb = new StringBuilder();
            Dictionary <int, MeshAnalysisResult[]> meshAnalysisResultsCache = new Dictionary <int, MeshAnalysisResult[]>(); //cache results

            for (int i = 0; i < objsToMesh.Count; i++)
            {
                GameObject obj = objsToMesh[i];
                if (obj == null)
                {
                    continue;
                }
                Material[] ms = MeshBakerUtility.GetGOMaterials(objsToMesh[i]);
                if (ms.Length > 1)
                { // and each material is not mapped to its own layer
                    sb.AppendFormat("\nObject {0} uses {1} materials. Possible treatments:\n", objsToMesh[i].name, ms.Length);
                    sb.AppendFormat("  1) Collapse the submeshes together into one submesh in the combined mesh. Each of the original submesh materials will map to a different UV rectangle in the atlas(es) used by the combined material.\n");
                    sb.AppendFormat("  2) Use the multiple materials feature to map submeshes in the source mesh to submeshes in the combined mesh.\n");
                }
                Mesh m = MeshBakerUtility.GetMesh(obj);

                MeshAnalysisResult[] mar;
                if (!meshAnalysisResultsCache.TryGetValue(m.GetInstanceID(), out mar))
                {
                    mar = new MeshAnalysisResult[m.subMeshCount];
                    MeshBakerUtility.doSubmeshesShareVertsOrTris(m, ref mar[0]);
                    for (int j = 0; j < m.subMeshCount; j++)
                    {
                        MeshBakerUtility.hasOutOfBoundsUVs(m, ref mar[j], j);
                        //DRect outOfBoundsUVRect = new DRect(mar[j].uvRect);
                        mar[j].hasOverlappingSubmeshTris  = mar[0].hasOverlappingSubmeshTris;
                        mar[j].hasOverlappingSubmeshVerts = mar[0].hasOverlappingSubmeshVerts;
                    }
                    meshAnalysisResultsCache.Add(m.GetInstanceID(), mar);
                }

                for (int j = 0; j < ms.Length; j++)
                {
                    if (mar[j].hasOutOfBoundsUVs)
                    {
                        DRect r = new DRect(mar[j].uvRect);
                        sb.AppendFormat("\nObject {0} submesh={1} material={2} uses UVs outside the range 0,0 .. 1,1 to create tiling that tiles the box {3},{4} .. {5},{6}. This is a problem because the UVs outside the 0,0 .. 1,1 " +
                                        "rectangle will pick up neighboring textures in the atlas. Possible Treatments:\n", obj, j, ms[j], r.x.ToString("G4"), r.y.ToString("G4"), (r.x + r.width).ToString("G4"), (r.y + r.height).ToString("G4"));
                        sb.AppendFormat("    1) Ignore the problem. The tiling may not affect result significantly.\n");
                        sb.AppendFormat("    2) Use the 'fix out of bounds UVs' feature to bake the tiling and scale the UVs to fit in the 0,0 .. 1,1 rectangle.\n");
                        sb.AppendFormat("    3) Use the Multiple Materials feature to map the material on this submesh to its own submesh in the combined mesh. No other materials should map to this submesh. This will result in only one texture in the atlas(es) and the UVs should tile correctly.\n");
                        sb.AppendFormat("    4) Combine only meshes that use the same (or subset of) the set of materials on this mesh. The original material(s) can be applied to the result\n");
                    }
                }
                if (mar[0].hasOverlappingSubmeshVerts)
                {
                    sb.AppendFormat("\nObject {0} has submeshes that share vertices. This is a problem because each vertex can have only one UV coordinate and may be required to map to different positions in the various atlases that are generated. Possible treatments:\n", objsToMesh[i]);
                    sb.AppendFormat(" 1) Ignore the problem. The vertices may not affect the result.\n");
                    sb.AppendFormat(" 2) Use the Multiple Materials feature to map the submeshs that overlap to their own submeshs in the combined mesh. No other materials should map to this submesh. This will result in only one texture in the atlas(es) and the UVs should tile correctly.\n");
                    sb.AppendFormat(" 3) Combine only meshes that use the same (or subset of) the set of materials on this mesh. The original material(s) can be applied to the result\n");
                }
            }
            Dictionary <Material, List <GameObject> > m2gos = new Dictionary <Material, List <GameObject> >();

            for (int i = 0; i < objsToMesh.Count; i++)
            {
                if (objsToMesh[i] != null)
                {
                    Material[] ms = MeshBakerUtility.GetGOMaterials(objsToMesh[i]);
                    for (int j = 0; j < ms.Length; j++)
                    {
                        if (ms[j] != null)
                        {
                            List <GameObject> lgo;
                            if (!m2gos.TryGetValue(ms[j], out lgo))
                            {
                                lgo = new List <GameObject>();
                                m2gos.Add(ms[j], lgo);
                            }
                            if (!lgo.Contains(objsToMesh[i]))
                            {
                                lgo.Add(objsToMesh[i]);
                            }
                        }
                    }
                }
            }

            for (int i = 0; i < resultMaterials.Length; i++)
            {
                string resultMatShaderName = resultMaterials[i] != null ? "None" : resultMaterials[i].shader.name;
                TexturePipelineData data   = CreatePipelineData(resultMaterials[i], new List <ShaderTextureProperty>(), objsToMesh, new List <Material>(), new List <MaterialPropTexturesSet>());
                TextureCombinerPipeline._CollectPropertyNames(data);
                foreach (Material m in m2gos.Keys)
                {
                    for (int j = 0; j < data.texPropertyNames.Count; j++)
                    {
                        if (m.HasProperty(data.texPropertyNames[j].name))
                        {
                            Texture txx = TextureCombinerPipeline.GetTextureConsideringStandardShaderKeywords(resultMatShaderName, m, data.texPropertyNames[j].name);
                            if (txx != null)
                            {
                                Vector2 o = m.GetTextureOffset(data.texPropertyNames[j].name);
                                Vector3 s = m.GetTextureScale(data.texPropertyNames[j].name);
                                if (o.x < 0f || o.x + s.x > 1f ||
                                    o.y < 0f || o.y + s.y > 1f)
                                {
                                    sb.AppendFormat("\nMaterial {0} used by objects {1} uses texture {2} that is tiled (scale={3} offset={4}). If there is more than one texture in the atlas " +
                                                    " then Mesh Baker will bake the tiling into the atlas. If the baked tiling is large then quality can be lost. Possible treatments:\n", m, PrintList(m2gos[m]), txx, s, o);
                                    sb.AppendFormat("  1) Use the baked tiling.\n");
                                    sb.AppendFormat("  2) Use the Multiple Materials feature to map the material on this object/submesh to its own submesh in the combined mesh. No other materials should map to this submesh. The original material can be applied to this submesh.\n");
                                    sb.AppendFormat("  3) Combine only meshes that use the same (or subset of) the set of textures on this mesh. The original material can be applied to the result.\n");
                                }
                            }
                        }
                    }
                }
            }
            string outstr = "";

            if (sb.Length == 0)
            {
                outstr = "====== No problems detected. These meshes should combine well ====\n  If there are problems with the combined meshes please report the problem to digitalOpus.ca so we can improve Mesh Baker.";
            }
            else
            {
                outstr = "====== There are possible problems with these meshes that may prevent them from combining well. TREATMENT SUGGESTIONS (copy and paste to text editor if too big) =====\n" + sb.ToString();
            }
            Debug.Log(outstr);
        }
        public IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo,
                                         TexturePipelineData data,
                                         TextureCombineHandler combiner,
                                         AtlasPackingResult packedAtlasRects,
                                         Texture2D[] atlases,
                                         EditorMethodsInterface textureEditorMethods)
        {
            Debug.Assert(!data.IsOnlyOneTextureInAtlasReuseTextures());
            Rect[] uvRects = packedAtlasRects.rects;

            int atlasSizeX = packedAtlasRects.atlasX;
            int atlasSizeY = packedAtlasRects.atlasY;

            Debug.Log("Generated atlas will be " + atlasSizeX + "x" + atlasSizeY);

            //create a game object
            GameObject renderAtlasesGO = null;

            try
            {
                renderAtlasesGO = new GameObject("MBrenderAtlasesGO");
                AtlasPackerRenderTexture atlasRenderTexture = renderAtlasesGO.AddComponent <AtlasPackerRenderTexture>();
                renderAtlasesGO.AddComponent <Camera>();
                if (data._considerNonTextureProperties)
                {
                    Debug.LogWarning("Blend Non-Texture Properties has limited functionality when used with Mesh Baker Texture Packer Fast.");
                }

                for (int propIdx = 0; propIdx < data.numAtlases; propIdx++)
                {
                    Texture2D atlas = null;
                    if (!TextureCombinerPipeline._ShouldWeCreateAtlasForThisProperty(propIdx, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor))
                    {
                        atlas = null;
                        Debug.Log("Not creating atlas for " + data.texPropertyNames[propIdx].name + " because textures are null and default value parameters are the same.");
                    }
                    else
                    {
                        GC.Collect();

                        TextureCombinerPackerBase.CreateTemporaryTexturesForAtlas(data.distinctMaterialTextures, combiner, propIdx, data);

                        if (progressInfo != null)
                        {
                            progressInfo("Creating Atlas '" + data.texPropertyNames[propIdx].name + "'", .01f);
                        }
                        // ===========
                        // configure it
                        Debug.Log("About to render " + data.texPropertyNames[propIdx].name + " isNormal=" + data.texPropertyNames[propIdx].isNormalMap);
                        atlasRenderTexture.width                        = atlasSizeX;
                        atlasRenderTexture.height                       = atlasSizeY;
                        atlasRenderTexture.padding                      = data._atlasPadding;
                        atlasRenderTexture.rects                        = uvRects;
                        atlasRenderTexture.textureSets                  = data.distinctMaterialTextures;
                        atlasRenderTexture.indexOfTexSetToRender        = propIdx;
                        atlasRenderTexture.texPropertyName              = data.texPropertyNames[propIdx];
                        atlasRenderTexture.isNormalMap                  = data.texPropertyNames[propIdx].isNormalMap;
                        atlasRenderTexture.fixOutOfBoundsUVs            = data._fixOutOfBoundsUVs;
                        atlasRenderTexture.considerNonTextureProperties = data._considerNonTextureProperties;
                        atlasRenderTexture.resultMaterialTextureBlender = data.nonTexturePropertyBlender;
                        // call render on it
                        atlas = atlasRenderTexture.OnRenderAtlas(combiner);

                        // destroy it
                        // =============
                        Debug.Log("Saving atlas " + data.texPropertyNames[propIdx].name + " w=" + atlas.width + " h=" + atlas.height + " id=" + atlas.GetInstanceID());
                    }
                    atlases[propIdx] = atlas;
                    if (progressInfo != null)
                    {
                        progressInfo("Saving atlas: '" + data.texPropertyNames[propIdx].name + "'", .04f);
                    }
                    if (data._saveAtlasesAsAssets && textureEditorMethods != null)
                    {
                        textureEditorMethods.SaveAtlasToAssetDatabase(atlases[propIdx], data.texPropertyNames[propIdx], propIdx, data.resultMaterial);
                    }
                    else
                    {
                        data.resultMaterial.SetTexture(data.texPropertyNames[propIdx].name, atlases[propIdx]);
                    }
                    data.resultMaterial.SetTextureOffset(data.texPropertyNames[propIdx].name, Vector2.zero);
                    data.resultMaterial.SetTextureScale(data.texPropertyNames[propIdx].name, Vector2.one);
                    combiner._destroyTemporaryTextures(data.texPropertyNames[propIdx].name); // need to save atlases before doing this
                }
            }
            catch (Exception ex)
            {
                //Debug.LogError(ex);
                Debug.LogException(ex);
            }
            finally
            {
                if (renderAtlasesGO != null)
                {
                    MeshBakerUtility.Destroy(renderAtlasesGO);
                }
            }
            yield break;
        }
Exemple #20
0
        /// <summary>
        /// Creates for materials on renderer.
        /// 生成 TextureBakeResult,如果要合并的所有游戏物体都使用相同的材质,则可以使用该 TextureBakeResult。
        /// 将游戏物体的渲染器所使用的所有材质映射到 Atlas 中的矩形0,0..1,1 中。
        /// 用于创建临时 TextureCombineResult,Mesh 合并时,TextureCombineResult 为空时调用
        /// </summary>
        public static TextureBakeResults CreateForMaterialsOnRenderer(GameObject[] gos, List <Material> matsOnTargetRenderer)
        {
            HashSet <Material> fullMaterialList = new HashSet <Material>(matsOnTargetRenderer);

            for (int i = 0; i < gos.Length; i++)
            {
                if (gos[i] == null)
                {
                    Debug.LogError(string.Format("列表中第 {0} 个游戏物体为空", i));
                    return(null);
                }
                Material[] oMats = MeshBakerUtility.GetGOMaterials(gos[i]);
                if (oMats.Length == 0)
                {
                    Debug.LogError(string.Format("列表中第 {0} 个游戏物体没有 renderer 组件", i));
                    return(null);
                }
                for (int j = 0; j < oMats.Length; j++)
                {
                    if (!fullMaterialList.Contains(oMats[j]))
                    {
                        fullMaterialList.Add(oMats[j]);
                    }
                }
            }
            //所有游戏位图的源材质
            Material[] rms = new Material[fullMaterialList.Count];
            fullMaterialList.CopyTo(rms);

            TextureBakeResults       textureCombineResult = (TextureBakeResults)CreateInstance(typeof(TextureBakeResults));
            List <MaterialAndUVRect> sourceMatUVRects     = new List <MaterialAndUVRect>();

            for (int i = 0; i < rms.Length; i++)
            {
                if (rms[i] != null)
                {
                    MaterialAndUVRect matAndUVRect = new MaterialAndUVRect(rms[i],
                                                                           new Rect(0f, 0f, 1f, 1f),
                                                                           true,
                                                                           new Rect(0f, 0f, 1f, 1f),
                                                                           new Rect(0f, 0f, 1f, 1f),
                                                                           new Rect(0, 0, 0, 0),
                                                                           TextureTilingTreatment.none,
                                                                           "");
                    if (!sourceMatUVRects.Contains(matAndUVRect))
                    {
                        sourceMatUVRects.Add(matAndUVRect);
                    }
                }
            }

            textureCombineResult.resultMaterials = new MultiMaterial[sourceMatUVRects.Count];
            for (int i = 0; i < sourceMatUVRects.Count; i++)
            {
                textureCombineResult.resultMaterials[i] = new MultiMaterial();
                List <Material> sourceMats = new List <Material>();
                sourceMats.Add(sourceMatUVRects[i].material);
                textureCombineResult.resultMaterials[i].sourceMaterials  = sourceMats;
                textureCombineResult.resultMaterials[i].combinedMaterial = sourceMatUVRects[i].material;
                textureCombineResult.resultMaterials[i].considerMeshUVs  = false;
            }
            if (rms.Length == 1)
            {
                textureCombineResult.doMultiMaterial = false;
            }
            else
            {
                textureCombineResult.doMultiMaterial = true;
            }

            textureCombineResult.materialsAndUVRects = sourceMatUVRects.ToArray();
            return(textureCombineResult);
        }
Exemple #21
0
        /// <summary>
        /// 创建贴图 Atlas 协程
        /// </summary>
        /// <returns></returns>
        public IEnumerator CreateAtlasesCoroutine(ProgressUpdateDelegate progressInfo,
                                                  CreateAtlasesCoroutineResult coroutineResult,
                                                  bool saveAtlasesAsAssets             = false,
                                                  EditorMethodsInterface editorMethods = null,
                                                  float maxTimePerFrame = .01f)
        {
            OnCombinedTexturesCoroutineAtlasesAndRects = null;

            //--- 1、合并前检测
            if (maxTimePerFrame <= 0f)
            {
                Debug.LogError("maxTimePerFrame must be a value greater than zero");
                coroutineResult.isFinished = true;
                yield break;
            }

            //验证等级
            ValidationLevel vl = Application.isPlaying ? ValidationLevel.quick : ValidationLevel.robust;

            //验证
            if (!DoCombinedValidate(this, ObjsToCombineTypes.dontCare, null, vl))
            {
                coroutineResult.isFinished = true;
                yield break;
            }

            //合并为多材质验证
            if (_doMultiMaterial && !_ValidateResultMaterials())
            {
                coroutineResult.isFinished = true;
                yield break;
            }
            else if (!_doMultiMaterial)
            {
                //合并为单独材质
                if (_resultMaterial == null)
                {
                    Debug.LogError("Combined Material is null please create and assign a result material.");
                    coroutineResult.isFinished = true;
                    yield break;
                }
                Shader targShader = _resultMaterial.shader;
                for (int i = 0; i < objsToMesh.Count; i++)
                {
                    Material[] ms = MeshBakerUtility.GetGOMaterials(objsToMesh[i]);
                    for (int j = 0; j < ms.Length; j++)
                    {
                        Material m = ms[j];
                        if (m != null && m.shader != targShader)
                        {
                            Debug.LogWarning("游戏物体" + objsToMesh[i] + " 没有使用 shader " + targShader +
                                             " it may not have the required textures. " +
                                             "If not small solid color textures will be generated.");
                        }
                    }
                }
            }

            TextureCombineHandler combiner = CreateAndConfigureTextureCombiner();

            combiner.saveAtlasesAsAssets = saveAtlasesAsAssets;

            ////--- 2、初始化存储合并结果的数据结构
            int numResults = 1;

            if (_doMultiMaterial)
            {
                numResults = resultMaterials.Length;
            }

            OnCombinedTexturesCoroutineAtlasesAndRects = new AtlasesAndRects[numResults];
            for (int i = 0; i < OnCombinedTexturesCoroutineAtlasesAndRects.Length; i++)
            {
                OnCombinedTexturesCoroutineAtlasesAndRects[i] = new AtlasesAndRects();
            }

            //--- 3、开始合并材质(单个,多个)
            for (int i = 0; i < OnCombinedTexturesCoroutineAtlasesAndRects.Length; i++)
            {
                Material        resMatToPass;
                List <Material> sourceMats;
                if (_doMultiMaterial)
                {
                    sourceMats   = resultMaterials[i].sourceMaterials;
                    resMatToPass = resultMaterials[i].combinedMaterial;
                    combiner.fixOutOfBoundsUVs = resultMaterials[i].considerMeshUVs;
                }
                else
                {
                    resMatToPass = _resultMaterial;
                    sourceMats   = null;
                }

                //TextureHandler 材质合并协程结果
                CombineTexturesIntoAtlasesCoroutineResult coroutineResult2 = new CombineTexturesIntoAtlasesCoroutineResult();
                yield return(combiner.CombineTexturesIntoAtlasesCoroutine(progressInfo,
                                                                          OnCombinedTexturesCoroutineAtlasesAndRects[i],
                                                                          resMatToPass,
                                                                          objsToMesh,
                                                                          sourceMats,
                                                                          editorMethods,
                                                                          coroutineResult2,
                                                                          maxTimePerFrame));

                coroutineResult.success = coroutineResult2.success;
                if (!coroutineResult.success)
                {
                    coroutineResult.isFinished = true;
                    yield break;
                }
            }

            //--- 4、TextureBakeResults 保存合并结果
            unpackMat2RectMap(textureBakeResults);
            textureBakeResults.doMultiMaterial = _doMultiMaterial;
            if (_doMultiMaterial)
            {
                textureBakeResults.resultMaterials = resultMaterials;
            }
            else
            {
                MultiMaterial[] resMats = new MultiMaterial[1];
                resMats[0] = new MultiMaterial();
                resMats[0].combinedMaterial = _resultMaterial;
                resMats[0].considerMeshUVs  = _fixOutOfBoundsUVs;
                resMats[0].sourceMaterials  = new List <Material>();
                for (int i = 0; i < textureBakeResults.materialsAndUVRects.Length; i++)
                {
                    resMats[0].sourceMaterials.Add(textureBakeResults.materialsAndUVRects[i].material);
                }
                textureBakeResults.resultMaterials = resMats;
            }

            //--- 5、传递合并结果到 MeshCombiner
            MeshBakerCommon[] mb = GetComponentsInChildren <MeshBakerCommon>();
            for (int i = 0; i < mb.Length; i++)
            {
                mb[i].textureBakeResults = textureBakeResults;
            }
            coroutineResult.isFinished = true;

            //--- 6、合并材质结束回调
            if (coroutineResult.success && onBuiltAtlasesSuccess != null)
            {
                onBuiltAtlasesSuccess();
            }
            if (!coroutineResult.success && onBuiltAtlasesFail != null)
            {
                onBuiltAtlasesFail();
            }
        }
Exemple #22
0
        /// <summary>
        /// Джх╬ Atlas
        /// </summary>
        /// <returns></returns>
        public Texture2D DoRenderAtlas(GameObject gameObject,
                                       int width,
                                       int height,
                                       int padding,
                                       Rect[] rss,
                                       List <MaterialPropTexturesSet> textureSetss,
                                       int indexOfTexSetToRenders,
                                       ShaderTextureProperty texPropertyname,
                                       TextureCombinerNonTextureProperties resultMaterialTextureBlender,
                                       bool isNormalMap,
                                       bool fixOutOfBoundsUVs,
                                       bool considerNonTextureProperties,
                                       TextureCombineHandler texCombiner)
        {
            textureSets           = textureSetss;
            indexOfTexSetToRender = indexOfTexSetToRenders;
            _texPropertyName      = texPropertyname;
            _padding                      = padding;
            _isNormalMap                  = isNormalMap;
            _fixOutOfBoundsUVs            = fixOutOfBoundsUVs;
            _resultMaterialTextureBlender = resultMaterialTextureBlender;
            rs = rss;
            Shader s;

            if (_isNormalMap)
            {
                s = Shader.Find("MeshBaker/NormalMapShader");
            }
            else
            {
                s = Shader.Find("MeshBaker/AlbedoShader");
            }
            if (s == null)
            {
                Debug.LogError("Could not find shader for RenderTexture. Try reimporting mesh baker");
                return(null);
            }
            mat = new Material(s);
            _destinationTexture            = new RenderTexture(width, height, 24, RenderTextureFormat.ARGB32);
            _destinationTexture.filterMode = FilterMode.Point;

            myCamera = gameObject.GetComponent <Camera>();
            myCamera.orthographic     = true;
            myCamera.orthographicSize = height >> 1;
            myCamera.aspect           = ((float)width) / height;
            myCamera.targetTexture    = _destinationTexture;
            myCamera.clearFlags       = CameraClearFlags.Color;

            Transform camTransform = myCamera.GetComponent <Transform>();

            camTransform.localPosition = new Vector3(width / 2.0f, height / 2f, 3);
            camTransform.localRotation = Quaternion.Euler(0, 180, 180);

            _doRenderAtlas = true;
            Debug.Log(string.Format("Begin Camera.Render destTex w={0} h={1} camPos={2} camSize={3} camAspect={4}",
                                    width, height, camTransform.localPosition, myCamera.orthographicSize, myCamera.aspect.ToString("f5")));
            //This triggers the OnRenderObject callback
            myCamera.Render();
            _doRenderAtlas = false;

            MeshBakerUtility.Destroy(mat);
            MeshBakerUtility.Destroy(_destinationTexture);

            Debug.Log("Finished Camera.Render ");

            Texture2D tempTex = targTex;

            targTex = null;
            return(tempTex);
        }
Exemple #23
0
        IEnumerator _CombineTexturesIntoAtlases(ProgressUpdateDelegate progressInfo,
                                                CombineTexturesIntoAtlasesCoroutineResult result,
                                                AtlasesAndRects resultAtlasesAndRects,
                                                Material resultMaterial,
                                                List <GameObject> objsToMesh,
                                                List <Material> allowedMaterialsFilter,
                                                EditorMethodsInterface textureEditorMethods,
                                                List <AtlasPackingResult> atlasPackingResult,
                                                bool onlyPackRects,
                                                bool splitAtlasWhenPackingIfTooBig)
        {
            try
            {
                _temporaryTextures.Clear();
                MaterialPropTexture.readyToBuildAtlases = false;

                // ---- 0.合并材质前回调
                if (textureEditorMethods != null)
                {
                    textureEditorMethods.Clear();
                    textureEditorMethods.OnPreTextureBake();
                }

                // ---- 1.合并材质参数校验
                if (objsToMesh == null || objsToMesh.Count == 0)
                {
                    Debug.LogError("没有游戏物体参与合并");
                    result.success = false;
                    yield break;
                }

                if (_atlasPadding < 0)
                {
                    Debug.LogError("Atlas padding 必须大于等于零");
                    result.success = false;
                    yield break;
                }

                if (_maxTilingBakeSize < 2 || _maxTilingBakeSize > 4096)
                {
                    Debug.LogError("无效Tilling尺寸的值Invalid value for max tiling bake size.");
                    result.success = false;
                    yield break;
                }

                for (int i = 0; i < objsToMesh.Count; i++)
                {
                    Material[] ms = MeshBakerUtility.GetGOMaterials(objsToMesh[i]);
                    for (int j = 0; j < ms.Length; j++)
                    {
                        Material m = ms[j];
                        if (m == null)
                        {
                            Debug.LogError("游戏物体" + objsToMesh[i] + " 材质为空 ");
                            result.success = false;
                            yield break;
                        }
                    }
                }

                if (_fixOutOfBoundsUVs && (_packingAlgorithm == PackingAlgorithmEnum.MeshBakerTexturePacker_Horizontal ||
                                           _packingAlgorithm == PackingAlgorithmEnum.MeshBakerTexturePacker_Vertical))
                {
                    Debug.LogWarning("合并算法为 MeshBakerTexturePacker_Horizontal 或 MeshBakerTexturePacker_Vertical,建议不打开 Consider Mesh UVs 选项");
                }

                if (progressInfo != null)
                {
                    progressInfo("Collecting textures for " + objsToMesh.Count + " meshes.", .01f);
                }

                // ---- 2.创建材质合并管线数据
                TexturePipelineData data = CreatePipelineData(resultMaterial,
                                                              new List <ShaderTextureProperty>(),
                                                              objsToMesh,
                                                              allowedMaterialsFilter,
                                                              new List <MaterialPropTexturesSet>());

                // ---- 3.将材质的 shader 各参数信息写入管线数据中
                if (!TextureCombinerPipeline._CollectPropertyNames(data))
                {
                    result.success = false;
                    yield break;
                }

                // ---- 4.加载 Texture 混合器
                data.nonTexturePropertyBlender.LoadTextureBlendersIfNeeded(data.resultMaterial);

                // ---- 5.选择本地合并,或运行时合并
                if (onlyPackRects)
                {
                    yield return(__RunTexturePackerOnly(result, data, splitAtlasWhenPackingIfTooBig, textureEditorMethods, atlasPackingResult));
                }
                else
                {
                    yield return(__CombineTexturesIntoAtlases(progressInfo, result, resultAtlasesAndRects, data, splitAtlasWhenPackingIfTooBig, textureEditorMethods));
                }
            }
            finally
            {
                // ---- 6.删除缓存,合并材质完成回调
                _destroyAllTemporaryTextures();
                if (textureEditorMethods != null)
                {
                    textureEditorMethods.RestoreReadFlagsAndFormats(progressInfo);
                    textureEditorMethods.OnPostTextureBake();
                }
            }
        }
        /// <summary>
        /// 第一步:
        ///     写入 TexturePipelineData 的 MaterialPropTexturesSet 列表,和 usedObjsToMesh 列表
        /// 每个TexSet在 Atlas 中都是一个矩形。
        /// 如果 allowedMaterialsFilter (过滤器)为空,那么将收集 allObjsToMesh 上的所有材质,usedObjsToMesh 将与allObjsToMesh相同
        /// 否则,将仅包括allowedMaterialsFilter中的材料,而usedObjsToMesh将是使用这些材料的objs。
        /// </summary>
        internal static IEnumerator __Step1_CollectDistinctMatTexturesAndUsedObjects(ProgressUpdateDelegate progressInfo,
                                                                                     CombineTexturesIntoAtlasesCoroutineResult result,
                                                                                     TexturePipelineData data,
                                                                                     EditorMethodsInterface textureEditorMethods,
                                                                                     List <GameObject> usedObjsToMesh)
        {
            // Collect distinct list of textures to combine from the materials on objsToCombine
            // 收集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 (progressInfo != null)
                {
                    progressInfo("Collecting textures for " + obj, ((float)i) / data.allObjsToMesh.Count / 2f);
                }

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

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

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

                //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);
                }

                if (data._fixOutOfBoundsUVs)
                {
                    Debug.Log("Mesh Analysis for object " + obj +
                              " numSubmesh=" + meshAnalysisResults.Length +
                              " HasOBUV=" + meshAnalysisResults[0].hasOutOfBoundsUVs +
                              " UVrectSubmesh0=" + meshAnalysisResults[0].uvRect);
                }


                //处理材质数据
                for (int matIdx = 0; matIdx < sharedMaterials.Length; matIdx++)
                {
                    ////for each submesh
                    //if (progressInfo != null)
                    //{
                    //    progressInfo(string.Format("Collecting textures for {0} submesh {1}", obj, matIdx),
                    //        ((float)i) / data.allObjsToMesh.Count / 2f);
                    //}
                    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.");
                        result.success = false;
                        yield break;
                    }

                    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'");
                                            result.success = false;
                                            yield break;
                                        }
                                        else
                                        {
                                            tx = (Texture2D)mat.GetTexture(data.texPropertyNames[propIdx].name);
                                        }
                                    }
                                }
                                else
                                {
                                    Debug.LogError("合并列表中,游戏物体 " + obj.name + " 渲染网格使用的 Texture 不是 Texture2D. ");
                                    result.success = false;
                                    yield break;
                                }
                            }
                            //像素密度
                            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);
                result.success = false;
                yield break;
            }

            TextureCombinerMerging merger = new TextureCombinerMerging(data._considerNonTextureProperties,
                                                                       data.nonTexturePropertyBlender, data._fixOutOfBoundsUVs);

            merger.MergeOverlappingDistinctMaterialTexturesAndCalcMaterialSubrects(data.distinctMaterialTextures);

            yield break;
        }
        /// <summary>
        /// A material can appear more than once in an atlas if using fixOutOfBoundsUVs.
        /// in this case you need to use the UV rect of the mesh to find the correct rectangle.
        /// If the all properties on the mat use the same tiling then
        /// encapsulatingRect can be larger and will include baked UV and material tiling
        /// If mat uses different tiling for different maps then encapsulatingRect is the uvs of
        /// source mesh used to bake atlas and sourceMaterialTilingOut is 0,0,1,1. This works because
        /// material tiling was baked into the atlas.
        /// 尝试获取源物体材质在合并材质中的映射信息
        /// 如果使用fixOutOfBoundsUVs,一个材质可以在图集中出现多次。在这种情况下,您需要使用网格的UV矩形来找到正确的矩形。
        /// 如果材质上的所有属性都使用相同的拼贴,则 encapsulatingRect 可以更大,并将包含烘焙的UV和材质平铺
        /// 如果mat 对不同映射使用不同的tiling,则 encapsulatingRect 是用于烘焙图集的 uvs 且 sourceMaterialTilingOut 为0,0,1,1。
        /// 材质 tiling 烘焙到 atlas 中。
        /// </summary>
        public bool TryGetMaterialToUVRectMap(Material sourceMat,
                                              Mesh sourceMesh,
                                              int submeshIdx,
                                              int idxInResultMats,
                                              MeshChannelsCache meshChannelCache,
                                              Dictionary <int, MeshAnalysisResult[]> meshAnalysisCache,
                                              out TextureTilingTreatment tilingTreatment,
                                              out Rect rectInAtlas,
                                              out Rect encapsulatingRectOut,
                                              out Rect sourceMaterialTilingOut,
                                              ref string errorMsg)
        {
            for (int i = 0; i < resultAsset.materialsAndUVRects.Length; i++)
            {
                resultAsset.materialsAndUVRects[i].allPropsUseSameTiling = true;
            }

            tilingTreatment = TextureTilingTreatment.unknown;
            if (resultAsset.materialsAndUVRects.Length == 0)
            {
                errorMsg                = "Texture Bake Result 资源中的 材质UVRect 映射信息为空,需重新合并";
                rectInAtlas             = new Rect();
                encapsulatingRectOut    = new Rect();
                sourceMaterialTilingOut = new Rect();
                return(false);
            }
            if (sourceMat == null)
            {
                rectInAtlas             = new Rect();
                encapsulatingRectOut    = new Rect();
                sourceMaterialTilingOut = new Rect();
                errorMsg = string.Format("网格 {0} 的子网格 {1} 缺少材质,无法获取映射关系", sourceMesh.name, submeshIdx);
                return(false);
            }
            if (submeshIdx >= sourceMesh.subMeshCount)
            {
                errorMsg                = "参数错误 :Submesh index 大于子网格数量";
                rectInAtlas             = new Rect();
                encapsulatingRectOut    = new Rect();
                sourceMaterialTilingOut = new Rect();
                return(false);
            }

            //源材质在 matsAndSrcUVRect 的 ID
            int idx = -1;

            for (int i = 0; i < matsAndSrcUVRect.Length; i++)
            {
                if (sourceMat == matsAndSrcUVRect[i].material)
                {
                    idx = i;
                    break;
                }
            }
            if (idx == -1)
            {
                rectInAtlas             = new Rect();
                encapsulatingRectOut    = new Rect();
                sourceMaterialTilingOut = new Rect();
                errorMsg = string.Format("Material {0} 在 Texture Bake Result 中无法找到", sourceMat.name);
                return(false);
            }

            //不处理网格 UVs
            if (!resultAsset.resultMaterials[idxInResultMats].considerMeshUVs)
            {
                if (numTimesMatAppearsInAtlas[idx] != 1)
                {
                    Debug.LogError("TextureBakeResults 资源错误,FixOutOfBoundsUVs is false and a material appears more than once.");
                }
                MaterialAndUVRect mr = matsAndSrcUVRect[idx];
                rectInAtlas             = mr.atlasRect;
                tilingTreatment         = mr.tilingTreatment;
                encapsulatingRectOut    = mr.GetEncapsulatingRect();
                sourceMaterialTilingOut = mr.GetMaterialTilingRect();
                return(true);
            }
            else
            {
                //todo what if no UVs
                //Find UV rect in source mesh
                //源网格分析,并缓存
                MeshAnalysisResult[] meshAnalysisInfo;
                if (!meshAnalysisCache.TryGetValue(sourceMesh.GetInstanceID(), out meshAnalysisInfo))
                {
                    meshAnalysisInfo = new MeshAnalysisResult[sourceMesh.subMeshCount];
                    for (int j = 0; j < sourceMesh.subMeshCount; j++)
                    {
                        Vector2[] uvss = meshChannelCache.GetUv0Raw(sourceMesh);
                        MeshBakerUtility.hasOutOfBoundsUVs(uvss, sourceMesh, ref meshAnalysisInfo[j], j);
                    }
                    meshAnalysisCache.Add(sourceMesh.GetInstanceID(), meshAnalysisInfo);
                }

                //this could be a mesh that was not used in the texture baking that has huge UV tiling too big for the rect that was baked
                //find a record that has an atlas uvRect capable of containing this
                //这可能是未在纹理烘焙中使用的网格,该网格的UV贴图对于烘焙的rect而言太大
                //找到一条记录,该记录具有能够包含此图集的uvRect
                bool found                = false;
                Rect encapsulatingRect    = new Rect(0, 0, 0, 0);
                Rect sourceMaterialTiling = new Rect(0, 0, 0, 0);

                //Debug.Log(string.Format("尝试在图集中查找能够使用材质{1}保持网格{0}的平铺采样rect的矩形",
                //    m, sourceMat, meshAnalysisInfo[submeshIdx].uvRect.ToString("f5")));

                for (int i = idx; i < matsAndSrcUVRect.Length; i++)
                {
                    MaterialAndUVRect matAndUVrect = matsAndSrcUVRect[i];
                    if (matAndUVrect.material == sourceMat)
                    {
                        if (matAndUVrect.allPropsUseSameTiling)
                        {
                            encapsulatingRect    = matAndUVrect.allPropsUseSameTiling_samplingEncapsulatinRect;
                            sourceMaterialTiling = matAndUVrect.allPropsUseSameTiling_sourceMaterialTiling;
                        }
                        else
                        {
                            encapsulatingRect    = matAndUVrect.propsUseDifferntTiling_srcUVsamplingRect;
                            sourceMaterialTiling = new Rect(0, 0, 1, 1);
                        }

                        if (UVRectUtility.IsMeshAndMaterialRectEnclosedByAtlasRect(
                                matAndUVrect.tilingTreatment,
                                meshAnalysisInfo[submeshIdx].uvRect,
                                sourceMaterialTiling,
                                encapsulatingRect))
                        {
                            Debug.Log("在图集中找到" + "ID 为 " + i + "包含" + sourceMesh + "  的 tiled sampling 的 Rect");
                            idx   = i;
                            found = true;
                            break;
                        }
                    }
                }
                if (found)
                {
                    MaterialAndUVRect mr = matsAndSrcUVRect[idx];
                    rectInAtlas             = mr.atlasRect;
                    tilingTreatment         = mr.tilingTreatment;
                    encapsulatingRectOut    = mr.GetEncapsulatingRect();
                    sourceMaterialTilingOut = mr.GetMaterialTilingRect();
                    return(true);
                }
                else
                {
                    rectInAtlas             = new Rect();
                    encapsulatingRectOut    = new Rect();
                    sourceMaterialTilingOut = new Rect();
                    errorMsg = string.Format("Could not find a tiled rectangle in the atlas capable of containing the uv and material tiling on mesh {0} for material {1}. " +
                                             "Was this mesh included when atlases were baked?", sourceMesh.name, sourceMat);
                    return(false);
                }
            }
        }
        //网格合并验证
        public static bool DoCombinedValidate(MeshBakerRoot mom, ObjsToCombineTypes objToCombineType, EditorMethodsInterface editorMethods, ValidationLevel validationLevel)
        {
            if (mom.textureBakeResults == null)
            {
                Debug.LogError("Need to set Texture Bake Result on " + mom);
                return(false);
            }
            if (mom is MeshBakerCommon)
            {
                //MB3_MeshBakerCommon momMB = (MB3_MeshBakerCommon)mom;
                //MB3_TextureBaker tb = momMB.GetTextureBaker();
                //if (tb != null && tb.textureBakeResults != mom.textureBakeResults)
                //{
                //    Debug.LogWarning("Texture Bake Result on this component is not the same as the Texture Bake Result on the MB3_TextureBaker.");
                //}
            }
            //网格分析结果缓存
            Dictionary <int, MeshAnalysisResult> meshAnalysisResultCache = null;

            if (validationLevel == ValidationLevel.robust)
            {
                meshAnalysisResultCache = new Dictionary <int, MeshAnalysisResult>();
            }

            //获取将合并网格的游戏物体
            List <GameObject> objsToMesh = mom.GetObjectsToCombine();

            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 && mom.textureBakeResults.doMultiMaterial &&
                        validationLevel >= ValidationLevel.robust)
                    {
                        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.");
                        }
                    }
                }
            }


            List <GameObject> objs = objsToMesh;

            if (mom is MeshCombinerEntrance)
            {
                objs = mom.GetObjectsToCombine();
                if (objs == null || objs.Count == 0)
                {
                    Debug.LogError("No meshes to combine. Please assign some meshes to combine.");
                    return(false);
                }

                //skinned 网格验证
                //if (mom is MB3_MeshBaker && ((MB3_MeshBaker)mom).meshCombiner.renderType == MB_RenderType.skinnedMeshRenderer)
                //{
                //    if (!editorMethods.ValidateSkinnedMeshes(objs))
                //    {
                //        return false;
                //    }
                //}
            }

            if (editorMethods != null)
            {
                editorMethods.CheckPrefabTypes(objToCombineType, objsToMesh);
            }
            return(true);
        }