void AddNewTexture(TextureAtlas textureAtlas) { // load atlas texture from disk Texture2D atlasTexture = (Texture2D)AssetDatabase.LoadAssetAtPath(textureAtlas.texturePath, typeof(Texture2D)); // cut texture rects from atlas texture Dictionary <Texture2D, Rect> textureAtlasRects = TextureAtlasHelper.CutTexturesFromAtlasRects(textureAtlas.atlasRects, atlasTexture); textureAtlas.atlasRects.Add(_newTextureName, new Rect(0, 0, _newTexture.width, _newTexture.height)); // update atlas rects int size; textureAtlas.atlasRects = TextureAtlasHelper.RepackRects(textureAtlas.atlasRects, out size, (_enableAtlasResize) ? _minAtlasSize : textureAtlas.size, (_enableAtlasResize) ? _maxAtlasSize : textureAtlas.size); // update atlas size textureAtlas.size = size; // add new texture to texture rects textureAtlasRects.Add(_newTexture, textureAtlas.atlasRects [_newTextureName]); TextureAtlasHelper.EnableReading(_newTexture); // recreate atlas texture TextureAtlasHelper.CreateTexture(textureAtlasRects, textureAtlas.size, textureAtlas.texturePath); // save atlas file to disk string atlasPath = AssetDatabase.GetAssetPath(_atlasFile); textureAtlas.Save(atlasPath); AssetDatabase.Refresh(); }
void Generate() { List <GameObject> prefabs = new List <GameObject> (); try { // ================== // BUILD DICTIONARIES // ================== Dictionary <Texture2D, HashSet <MeshFilter> > meshFiltersPerTexture = new Dictionary <Texture2D, HashSet <MeshFilter> > (); Dictionary <GameObject, HashSet <MeshFilter> > meshFiltersPerPrefab = new Dictionary <GameObject, HashSet <MeshFilter> > (); HashSet <Texture2D> textures = new HashSet <Texture2D> (); for (int i = 0; i < _prefabsNames.Count; i++) { if (!_prefabSelection [i]) { continue; } string prefabName = _prefabsNames [i]; GameObject prefab = (GameObject)PrefabUtility.InstantiatePrefab(AssetDatabase.LoadAssetAtPath(string.Format(PREFAB_FILE_PATTERN, _inputFolder, prefabName), typeof(GameObject))); PrefabUtility.DisconnectPrefabInstance(prefab); prefabs.Add(prefab); MeshFilter[] childMeshFilters = prefab.GetComponentsInChildren <MeshFilter> (); foreach (MeshFilter meshFilter in childMeshFilters) { Renderer renderer = FindRenderer(meshFilter.gameObject); if (renderer == null) { Debug.LogWarning("renderer is null (prefab: " + prefabName + ")"); continue; } Material material = renderer.sharedMaterial; if (material.mainTexture == null) { Debug.LogWarning("main texture is null (material: " + material.name + ", prefab: " + prefabName + ")"); continue; } Texture2D texture = (Texture2D)material.mainTexture; textures.Add(texture); HashSet <MeshFilter> prefabMeshFilters; if (!meshFiltersPerPrefab.TryGetValue(prefab, out prefabMeshFilters)) { prefabMeshFilters = new HashSet <MeshFilter> (); meshFiltersPerPrefab.Add(prefab, prefabMeshFilters); } prefabMeshFilters.Add(meshFilter); HashSet <MeshFilter> textureMeshFilters; if (!meshFiltersPerTexture.TryGetValue(texture, out textureMeshFilters)) { textureMeshFilters = new HashSet <MeshFilter> (); meshFiltersPerTexture.Add(texture, textureMeshFilters); } textureMeshFilters.Add(meshFilter); } } // ==================== // CHANGE READ SETTINGS // ==================== TextureAtlasHelper.EnableReading(textures); // ================== // CREATE ATLAS RECTS // ================== int size; Dictionary <Texture2D, Rect> atlasRectsPerTexture = TextureAtlasHelper.PackTextures(textures, out size, _minAtlasSize, _maxAtlasSize); Dictionary <string, Rect> atlasRects = new Dictionary <string, Rect> (); foreach (KeyValuePair <Texture2D, Rect> textureAtlasRect in atlasRectsPerTexture) { string textureName = TextureAtlasHelper.GetAtlasRectId(textureAtlasRect.Key); if (atlasRects.ContainsKey(textureName)) { int attemptToRename = 1; string newTextureName; while (true) { newTextureName = string.Format("{0} ({1})", textureName, attemptToRename); if (!atlasRects.ContainsKey(newTextureName)) { break; } attemptToRename++; } Debug.LogWarning("different textures with same name (newTextureName: " + newTextureName + ")"); textureName = newTextureName; } atlasRects.Add(textureName, textureAtlasRect.Value); } // ==================== // CREATE ATLAS TEXTURE // ==================== string atlasTexturePath = string.Format(TEXTURE_FILE_PATTERN, _texturesFolder, _atlasName); AssetDatabase.DeleteAsset(atlasTexturePath); Texture2D atlasTexture = TextureAtlasHelper.CreateTexture(atlasRectsPerTexture, size, atlasTexturePath); // ================= // UPDATE MESHES UVS // ================= Dictionary <Mesh, Mesh> newMeshes = new Dictionary <Mesh, Mesh> (); foreach (KeyValuePair <Texture2D, Rect> textureAtlasRect in atlasRectsPerTexture) { HashSet <MeshFilter> meshFilters = meshFiltersPerTexture [textureAtlasRect.Key]; Vector2 scale = new Vector2(textureAtlasRect.Value.width / (float)size, textureAtlasRect.Value.height / (float)size); Vector2 translate = new Vector2(textureAtlasRect.Value.x / (float)size, textureAtlasRect.Value.y / (float)size); foreach (MeshFilter meshFilter in meshFilters) { Mesh newMesh = new Mesh(); Mesh mesh = meshFilter.sharedMesh; if (mesh == null) { throw new Exception("mesh is null: " + meshFilter.name); } newMesh.name = mesh.name; newMesh.vertices = mesh.vertices; newMesh.normals = mesh.normals; Vector2[] newUv = new Vector2[mesh.uv.Length]; for (int i = 0; i < mesh.uv.Length; i++) { Vector2 uv = mesh.uv [i]; newUv [i] = translate + new Vector2(uv.x * scale.x, uv.y * scale.y); } newMesh.uv = newUv; newMesh.triangles = mesh.triangles; newMesh.tangents = mesh.tangents; if (_combineChildMeshes) { string meshName = meshFilter.name; ColorMaskGroup colorMaskGroup = null; for (int i = 0; i < _colorMaskGroups.Count; i++) { if (meshName.Contains(_colorMaskGroups [i].meshNameFilter)) { colorMaskGroup = _colorMaskGroups [i]; break; } } if (colorMaskGroup != null) { newMesh.colors = FillColorBuffer(colorMaskGroup.colorMask, mesh.vertices.Length); } else { newMesh.colors = FillColorBuffer(_defaultColor, mesh.vertices.Length); } } newMesh.RecalculateBounds(); newMeshes.Add(mesh, newMesh); } } // ==================== // BUILD ATLAS MATERIAL // ==================== Material atlasMaterial = new Material(_defaultShader); string atlasMaterialPath = string.Format(MATERIAL_FILE_PATTERN, _materialsFolder, _atlasName); AssetDatabase.DeleteAsset(atlasMaterialPath); AssetDatabase.CreateAsset(atlasMaterial, atlasMaterialPath); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); atlasMaterial = (Material)AssetDatabase.LoadAssetAtPath(atlasMaterialPath, typeof(Material)); atlasMaterial.mainTexture = atlasTexture; // =============== // SAVE NEW MESHES // =============== if (_cleanOutputFolder) { CleanUpFolder("Assets/" + _outputFolder); CleanUpFolder("Assets/" + _meshesFolder); } foreach (KeyValuePair <GameObject, HashSet <MeshFilter> > prefabMeshFilters in meshFiltersPerPrefab) { GameObject prefab = prefabMeshFilters.Key; HashSet <MeshFilter> meshFilters = prefabMeshFilters.Value; if (_combineChildMeshes) { MeshFilter meshFilter; meshFilter = prefab.GetComponent <MeshFilter> (); Mesh sharedMesh = MergeAll(meshFilters, meshFilter, newMeshes); foreach (MeshFilter meshFilter2 in meshFilters) { if (meshFilter2 != meshFilter) { DestroyImmediate(meshFilter2.gameObject); } } if (meshFilter == null) { meshFilter = prefab.AddComponent <MeshFilter> (); } meshFilter.sharedMesh = sharedMesh; Renderer renderer; if ((renderer = FindRenderer(prefab)) == null) { renderer = prefab.AddComponent <MeshRenderer> (); } renderer.sharedMaterial = atlasMaterial; AssetDatabase.CreateAsset(sharedMesh, string.Format(COMBINED_MESH_FILE_PATTERN, _meshesFolder, Guid.NewGuid().ToString())); } else { foreach (MeshFilter meshFilter in meshFilters) { Mesh newMesh = newMeshes [meshFilter.sharedMesh]; meshFilter.sharedMesh = newMesh; FindRenderer(meshFilter.gameObject).sharedMaterial = atlasMaterial; AssetDatabase.CreateAsset(newMesh, string.Format(NEW_MESH_FILE_PATTERN, _meshesFolder, newMesh.name, Guid.NewGuid().ToString())); } } UnityEngine.Object newPrefab = PrefabUtility.CreateEmptyPrefab(string.Format(PREFAB_FILE_PATTERN, _outputFolder, prefab.name)); PrefabUtility.ReplacePrefab(prefab, newPrefab, ReplacePrefabOptions.ConnectToPrefab); DestroyImmediate(prefab); } // =============== // SAVE ATLAS FILE // =============== TextureAtlas textureAtlas = new TextureAtlas(); textureAtlas.name = _atlasName; textureAtlas.size = size; textureAtlas.texturePath = atlasTexturePath; textureAtlas.atlasRects = atlasRects; textureAtlas.Save(string.Format(ATLAS_FILE_PATTERN, _atlasesFolder, _atlasName)); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); } catch (Exception e) { Debug.LogException(e); foreach (GameObject prefab in prefabs) { DestroyImmediate(prefab); } } }