private void CreateAtlas(Hashtable aRow) { Material atlasMat = (Material)aRow["atlasMat"]; Material origMat = (Material)aRow["origMat"]; // find 1st row that uses this atlasMat // (1st row defines which keys are active) int minOrder = 999999; Hashtable masterRow = null; for(int i=0;i<submeshRows.Count;i++) { Hashtable row = (Hashtable)submeshRows[i]; if((Material)row["atlasMat"] == atlasMat) { if(minOrder > (int)row["order"]) { masterRow = row; minOrder = (int)row["order"]; } } } int maxAtlasSize = (int)masterRow["atlasMaxSize"]; // find texture keys to use atlasMat = (Material)masterRow["atlasMat"]; List<string> keys = new List<string>(); string masterTexKey = null; Texture masterTex = null; foreach(string key in textureKeys) { if(atlasMat.HasProperty(key)) { keys.Add(key); if(masterTexKey == null || masterTex == null || masterTex.GetType() != typeof(Texture2D)) { masterTexKey = key; masterTex = atlasMat.GetTexture(key); } } } if(masterTex == null || masterTex.GetType() != typeof(Texture2D)) return; // find all rows that have the same base texture or same atlasMat as masterRow List<Hashtable> atlasRows = new List<Hashtable>(); for(int i=0;i<submeshRows.Count;i++) { Hashtable row = (Hashtable)submeshRows[i]; Material m = (Material)row["atlasMat"]; if(row["atlasMat"] == atlasMat || (m.HasProperty(masterTexKey) && m.GetTexture(masterTexKey) == masterTex)) { atlasRows.Add(row); } } // find base textures per material key List<Texture2D> texturesToInclude = new List<Texture2D>(); for(int i=0;i<keys.Count;i++) { string key = keys[i]; for(int j=0;j<atlasRows.Count;j++) { Material m = (Material)atlasRows[j]["origMat"]; Texture tex = null; if(m.HasProperty(key)) tex = m.GetTexture(key); if(tex != null && tex.GetType() != typeof(Texture2D)) tex = null; texturesToInclude.Add((Texture2D)tex); } } if(texturesToInclude.Count <= keys.Count) { // Only 1 row included in atlas for(int j=0;j<atlasRows.Count;j++) { origMat = (Material)atlasRows[j]["origMat"]; atlasMat = (Material)atlasRows[j]["atlasMat"]; for(int i=0;i<keys.Count;i++) { string key = keys[i]; Texture tex = null; if(origMat.HasProperty(key)) tex = origMat.GetTexture(key); if(atlasMat.HasProperty(key)) atlasMat.SetTexture(key, tex); } } } else { // make an atlas per key string key = keys[0]; List<Texture2D> tList = new List<Texture2D>(); List<int> rowIndexes = new List<int>(); int nrOfUniqueTextures = 0; for(int j=0;j<atlasRows.Count;j++) { Texture2D t = texturesToInclude[j]; if(t != null) { float atlasSize = (float)((int)atlasRows[j]["atlasSize"]) / 2f; float scale = 1f / atlasSize; if(scale != 1f) t = t.ScaledCopy((int)(t.width * scale), (int)(t.height * scale), false); int k=0; for(;k<tList.Count;k++) { if(tList[k] == t) break; } if(k>=tList.Count) nrOfUniqueTextures++; tList.Add(t); rowIndexes.Add(j); } } Rect[] rects = null; Texture2D atlas = null; if(nrOfUniqueTextures == 1) { for(int j=0;j<atlasRows.Count;j++) { origMat = (Material)atlasRows[j]["origMat"]; atlasMat = (Material)atlasRows[j]["atlasMat"]; for(int i=0;i<keys.Count;i++) { key = keys[i]; Texture tex = null; if(origMat.HasProperty(key)) tex = origMat.GetTexture(key); if(atlasMat.HasProperty(key)) atlasMat.SetTexture(key, tex); } atlasRows[j]["isAtlas"] = false; } } else if(tList.Count>1) { atlas = new Texture2D(512, 512); rects = atlas.PackTextures(tList.ToArray(), 0, maxAtlasSize); masterRow["atlasMaxSize"] = Mathf.Max(atlas.width, atlas.height); for(int j=0;j<rowIndexes.Count;j++) { // clear current texture Hashtable row = atlasRows[rowIndexes[j]]; atlasMat = (Material)row["atlasMat"]; row["atlasRect"] = new Rect(0,0,1,1); if(atlasMat.HasProperty(key)) atlasMat.SetTexture(key, null); } for(int j=0;j<rowIndexes.Count;j++) { // set atlas texture Hashtable row = atlasRows[rowIndexes[j]]; atlasMat = (Material)row["atlasMat"]; row["atlasRect"] = rects[j]; if(atlasMat.HasProperty(key)) atlasMat.SetTexture(key, atlas); row["isAtlas"] = true; } for(int i=1;i<keys.Count;i++) { key = keys[i]; Texture2D subAtlas = new Texture2D(atlas.width, atlas.height, TextureFormat.RGBA32, true); subAtlas.Fill(new Color(0,0,0,0)); for(int j=0;j<rowIndexes.Count;j++) { // clear current texture Hashtable row = atlasRows[rowIndexes[j]]; Rect atlasRect = (Rect)row["atlasRect"]; origMat = (Material)row["origMat"]; if(origMat.HasProperty(key) && atlasMat.HasProperty(key)) { Texture t = origMat.GetTexture(key); if(t != null && t.GetType() == typeof(Texture2D)) { if(key == "_BumpMap" || key == "_NormalMap" || key == "_DetailBumpMap" || key == "_DetailNormalMap") { t = ((Texture2D)t).FromUnityNormalMap(); } t = ((Texture2D)t).ScaledCopy(Mathf.RoundToInt(atlas.width * atlasRect.width), Mathf.RoundToInt(atlas.height * atlasRect.height), false); subAtlas.CopyFrom((Texture2D)t, Mathf.RoundToInt(atlas.width * atlasRect.x), Mathf.RoundToInt(atlas.height * atlasRect.y), 0, 0, t.width, t.height); atlasMat.SetTexture(key, subAtlas); } } } } } } Resources.UnloadUnusedAssets(); }