public IEnumerator GetTextureAtlas(Texture2D[] textures, Action <TextureAtlas> callback)
        {
            TextureAtlas atlas = null;

            // Clear out any atlases that were removed
            m_Atlases.RemoveAll(a => a == null);
            yield return(null);

            foreach (var a in m_Atlases)
            {
                // At a minimum the atlas should have all of the textures requested, but can be a superset
                if (!textures.Except(a.textures).Any())
                {
                    atlas = a;
                    break;
                }

                yield return(null);
            }

            if (!atlas)
            {
                atlas = ScriptableObject.CreateInstance <TextureAtlas>();

                foreach (var t in textures)
                {
                    var assetImporter   = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(t));
                    var textureImporter = assetImporter as TextureImporter;
                    if (textureImporter && !textureImporter.isReadable)
                    {
                        textureImporter.isReadable = true;
                        textureImporter.SaveAndReimport();
                    }
                    else if (!assetImporter)
                    {
                        // In-memory textures need to be saved to disk in order to be referenced by the texture atlas
                        SaveUniqueAtlasAsset(t);
                    }
                    yield return(null);
                }

                var textureAtlas = new Texture2D(0, 0, TextureFormat.RGB24, true, PlayerSettings.colorSpace == ColorSpace.Linear);
                var uvs          = textureAtlas.PackTextures(textures.ToArray(), 0, 1024, true);

                if (uvs != null)
                {
                    atlas.textureAtlas = textureAtlas;
                    atlas.uvs          = uvs;
                    atlas.textures     = textures;

                    SaveUniqueAtlasAsset(textureAtlas);
                    SaveUniqueAtlasAsset(atlas);

                    m_Atlases.Add(atlas);
                }

                yield return(null);
            }

            if (callback != null)
            {
                callback(atlas);
            }
        }
Exemple #2
0
        public IEnumerator Batch(GameObject go)
        {
            var renderers = go.GetComponentsInChildren <Renderer>();
            var materials = new HashSet <Material>(renderers.SelectMany(r => r.sharedMaterials));

            var textures = new HashSet <Texture2D>(materials.Select(m =>
            {
                if (m)
                {
                    return(m.mainTexture as Texture2D);
                }

                return(null);
            }).Where(t => t != null)).ToList();

            textures.Add(whiteTexture);

            TextureAtlas atlas = null;

            yield return(TextureAtlasModule.instance.GetTextureAtlas(textures.ToArray(), a => atlas = a));

            var atlasLookup   = new Dictionary <Texture2D, Rect>();
            var atlasTextures = atlas.textures;

            for (int i = 0; i < atlasTextures.Length; i++)
            {
                atlasLookup[atlasTextures[i]] = atlas.uvs[i];
            }

            MeshFilter[] meshFilters = go.GetComponentsInChildren <MeshFilter>();
            var          combine     = new List <CombineInstance>();

            for (int i = 0; i < meshFilters.Length; i++)
            {
                var mf         = meshFilters[i];
                var sharedMesh = mf.sharedMesh;

                if (!sharedMesh)
                {
                    continue;
                }

                if (!sharedMesh.isReadable)
                {
                    var assetPath = AssetDatabase.GetAssetPath(sharedMesh);
                    if (!string.IsNullOrEmpty(assetPath))
                    {
                        var importer = AssetImporter.GetAtPath(assetPath) as ModelImporter;
                        if (importer)
                        {
                            importer.isReadable = true;
                            importer.SaveAndReimport();
                        }
                    }
                }

                var ci = new CombineInstance();

                var mesh = Object.Instantiate(sharedMesh);

                var mr = mf.GetComponent <MeshRenderer>();
                var sharedMaterials = mr.sharedMaterials;
                var uv     = mesh.uv;
                var colors = mesh.colors;
                if (colors == null || colors.Length == 0)
                {
                    colors = new Color[uv.Length];
                }
                var updated   = new bool[uv.Length];
                var triangles = new List <int>();

                // Some meshes have submeshes that either aren't expected to render or are missing a material, so go ahead and skip
                var subMeshCount = Mathf.Min(mesh.subMeshCount, sharedMaterials.Length);
                for (int j = 0; j < subMeshCount; j++)
                {
                    var sharedMaterial = sharedMaterials[Mathf.Min(j, sharedMaterials.Length - 1)];
                    var mainTexture    = whiteTexture;
                    var materialColor  = Color.white;

                    if (sharedMaterial)
                    {
                        var texture = sharedMaterial.mainTexture as Texture2D;
                        if (texture)
                        {
                            mainTexture = texture;
                        }

                        if (sharedMaterial.HasProperty("_Color"))
                        {
                            materialColor = sharedMaterial.color;
                        }
                    }

                    if (mesh.GetTopology(j) != MeshTopology.Triangles)
                    {
                        Debug.LogWarning("Mesh must have triangles", mf);
                        continue;
                    }

                    triangles.Clear();
                    mesh.GetTriangles(triangles, j);
                    var uvOffset = atlasLookup[mainTexture];
                    foreach (var t in triangles)
                    {
                        if (!updated[t])
                        {
                            var uvCoord = uv[t];
                            if (mainTexture == whiteTexture)
                            {
                                // Sample at center of white texture to avoid sampling edge colors incorrectly
                                uvCoord.x = 0.5f;
                                uvCoord.y = 0.5f;
                            }

                            uvCoord.x = Mathf.Lerp(uvOffset.xMin, uvOffset.xMax, uvCoord.x);
                            uvCoord.y = Mathf.Lerp(uvOffset.yMin, uvOffset.yMax, uvCoord.y);
                            uv[t]     = uvCoord;

                            if (mainTexture == whiteTexture)
                            {
                                colors[t] = materialColor;
                            }
                            else
                            {
                                colors[t] = Color.white;
                            }

                            updated[t] = true;
                        }
                    }

                    yield return(null);
                }
                mesh.uv     = uv;
                mesh.uv2    = null;
                mesh.colors = colors;

                ci.mesh      = mesh;
                ci.transform = mf.transform.localToWorldMatrix;
                combine.Add(ci);

                mf.gameObject.SetActive(false);

                yield return(null);
            }

            var combinedMesh = new Mesh();

            combinedMesh.indexFormat = IndexFormat.UInt32;
            combinedMesh.CombineMeshes(combine.ToArray(), true, true);
            combinedMesh.RecalculateBounds();
            var meshFilter = go.AddComponent <MeshFilter>();

            meshFilter.sharedMesh = combinedMesh;

            for (int i = 0; i < meshFilters.Length; i++)
            {
                Object.DestroyImmediate(meshFilters[i].gameObject);
            }

            var meshRenderer = go.AddComponent <MeshRenderer>();
            var material     = new Material(Shader.Find("Custom/AutoLOD/SimpleBatcher"));

            material.mainTexture        = atlas.textureAtlas;
            meshRenderer.sharedMaterial = material;
        }
Exemple #3
0
        public IEnumerator Batch(GameObject hlodRoot, System.Action <float> progress)
        {
            yield return(PackTextures(hlodRoot));

            Dictionary <Texture2D, Material> createdMaterials = new Dictionary <Texture2D, Material>();


            for (int childIndex = 0; childIndex < hlodRoot.transform.childCount; ++childIndex)
            {
                var child = hlodRoot.transform.GetChild(childIndex);

                var go        = child.gameObject;
                var renderers = go.GetComponentsInChildren <Renderer>();
                var materials = new HashSet <Material>(renderers.SelectMany(r => r.sharedMaterials));

                TextureAtlas atlas = packer.GetAtlas(go);

                var atlasLookup   = new Dictionary <Texture2D, Rect>();
                var atlasTextures = atlas.textures;
                for (int i = 0; i < atlasTextures.Length; i++)
                {
                    atlasLookup[atlasTextures[i]] = atlas.uvs[i];
                }

                MeshFilter[] meshFilters = go.GetComponentsInChildren <MeshFilter>();
                var          combine     = new List <CombineInstance>();
                for (int i = 0; i < meshFilters.Length; i++)
                {
                    var mf         = meshFilters[i];
                    var sharedMesh = mf.sharedMesh;

                    if (!sharedMesh)
                    {
                        continue;
                    }

                    if (!sharedMesh.isReadable)
                    {
                        var assetPath = AssetDatabase.GetAssetPath(sharedMesh);
                        if (!string.IsNullOrEmpty(assetPath))
                        {
                            var importer = AssetImporter.GetAtPath(assetPath) as ModelImporter;
                            if (importer)
                            {
                                importer.isReadable = true;
                                importer.SaveAndReimport();
                            }
                        }
                    }

                    var mesh = Object.Instantiate(sharedMesh);

                    var mr = mf.GetComponent <MeshRenderer>();
                    var sharedMaterials = mr.sharedMaterials;
                    var uv     = mesh.uv;
                    var colors = mesh.colors;
                    if (colors == null || colors.Length == 0)
                    {
                        colors = new Color[uv.Length];
                    }
                    var updated   = new bool[uv.Length];
                    var triangles = new List <int>();

                    // Some meshes have submeshes that either aren't expected to render or are missing a material, so go ahead and skip
                    var subMeshCount = Mathf.Min(mesh.subMeshCount, sharedMaterials.Length);
                    for (int j = 0; j < subMeshCount; j++)
                    {
                        var sharedMaterial = sharedMaterials[Mathf.Min(j, sharedMaterials.Length - 1)];
                        var mainTexture    = whiteTexture;
                        var materialColor  = Color.white;

                        if (sharedMaterial)
                        {
                            var texture = GetTexture(sharedMaterial);
                            if (texture)
                            {
                                mainTexture = texture;
                            }

                            if (sharedMaterial.HasProperty("_Color"))
                            {
                                materialColor = sharedMaterial.color;
                            }
                        }

                        if (mesh.GetTopology(j) != MeshTopology.Triangles)
                        {
                            Debug.LogWarning("Mesh must have triangles", mf);
                            continue;
                        }

                        triangles.Clear();
                        mesh.GetTriangles(triangles, j);
                        var uvOffset = atlasLookup[mainTexture];
                        foreach (var t in triangles)
                        {
                            if (!updated[t])
                            {
                                var uvCoord = uv[t];
                                if (mainTexture == whiteTexture)
                                {
                                    // Sample at center of white texture to avoid sampling edge colors incorrectly
                                    uvCoord.x = 0.5f;
                                    uvCoord.y = 0.5f;
                                }

                                uvCoord.x = Mathf.Lerp(uvOffset.xMin, uvOffset.xMax, uvCoord.x);
                                uvCoord.y = Mathf.Lerp(uvOffset.yMin, uvOffset.yMax, uvCoord.y);
                                uv[t]     = uvCoord;

                                if (mainTexture == whiteTexture)
                                {
                                    colors[t] = materialColor;
                                }
                                else
                                {
                                    colors[t] = Color.white;
                                }

                                updated[t] = true;
                            }
                        }
                    }

                    mesh.uv     = uv;
                    mesh.uv2    = null;
                    mesh.colors = colors;

                    for (int j = 0; j < subMeshCount; ++j)
                    {
                        var ci = new CombineInstance();
                        ci.mesh         = mesh;
                        ci.subMeshIndex = j;
                        ci.transform    = mf.transform.localToWorldMatrix;
                        combine.Add(ci);
                    }


                    mf.gameObject.SetActive(false);
                }

                var combinedMesh = new Mesh();
#if UNITY_2017_3_OR_NEWER
                combinedMesh.indexFormat = IndexFormat.UInt32;
#endif
                combinedMesh.CombineMeshes(combine.ToArray(), true, true);
                combinedMesh.RecalculateBounds();
                var meshFilter = go.AddComponent <MeshFilter>();
                meshFilter.sharedMesh = combinedMesh;

                for (int i = 0; i < meshFilters.Length; i++)
                {
                    Object.DestroyImmediate(meshFilters[i].gameObject);
                }

                var      meshRenderer = go.AddComponent <MeshRenderer>();
                Material material     = null;
                if (createdMaterials.ContainsKey(atlas.textureAtlas) == false)
                {
                    if (option.BatchMaterial == null)
                    {
                        material = new Material(Shader.Find("Custom/AutoLOD/SimpleBatcher"));
                    }
                    else
                    {
                        material = new Material(option.BatchMaterial);
                    }

                    material.mainTexture = atlas.textureAtlas;

                    string matName = hlodRoot.name + "_" + createdMaterials.Count;
                    AssetDatabase.CreateAsset(material, "Assets/" + SceneLOD.GetSceneLODPath() + matName + ".mat");

                    createdMaterials.Add(atlas.textureAtlas, material);
                }
                else
                {
                    material = createdMaterials[atlas.textureAtlas];
                }

                meshRenderer.sharedMaterial = material;

                string assetName = hlodRoot.name + "_" + go.name;

                AssetDatabase.CreateAsset(combinedMesh,
                                          "Assets/" + SceneLOD.GetSceneLODPath() + assetName + ".asset");
                AssetDatabase.SaveAssets();

                if (progress != null)
                {
                    progress((float)childIndex / (float)hlodRoot.transform.childCount);
                }
                yield return(null);
            }
        }