public static Texture2D TileTexture(Texture2D tex, Vector2 scale, Vector2 offset) { if (scale == Vector2.one && offset == Vector2.zero) { return(tex); } Texture2D canvas = new Texture2D(tex.width, tex.height, TextureFormat.ARGB32, false); Texture2D textureToTile = Utils.CopyTexture(tex, TextureFormat.ARGB32); bool invertX = false; bool invertY = false; float scaleX = scale.x == 0 ? 0.01f : scale.x; if (scaleX < 0) { scaleX *= -1; invertX = true; } float scaleY = scale.y == 0 ? 0.01f : scale.y; if (scaleY < 0) { scaleY *= -1; invertY = true; } float newSizeX = (float)tex.width / scaleX > Constants.MaxTextureSize ? Constants.MaxTextureSize : (float)tex.width / scaleX; float newSizeY = (float)tex.height / scaleY > Constants.MaxTextureSize ? Constants.MaxTextureSize : (float)tex.height / scaleY; while (true) { try { TextureScale.Point(textureToTile, Mathf.RoundToInt(newSizeX), Mathf.RoundToInt(newSizeY)); break; } catch (System.OutOfMemoryException) { //if the system we are running this into is out of memory (because of the scaling) //then reduce the tile size until there are no out of memory exceptions newSizeY *= 0.95f; newSizeX *= 0.95f; Debug.LogWarning("Tiling too small, out of memory, reducing tiled texture size..." + (newSizeX * newSizeY)); } } int offsetPixelX = (int)((offset.x % 1) * (float)textureToTile.width); int offsetPixelY = (int)((offset.y % 1) * (float)textureToTile.height); for (int i = 0; i < canvas.width; i++) { for (int j = 0; j < canvas.height; j++) { canvas.SetPixel(i, j, textureToTile.GetPixel(invertX ? (textureToTile.width - 1 - i + offsetPixelX) % textureToTile.width : (i + offsetPixelX) % textureToTile.width, invertY ? (textureToTile.height - 1 - j + offsetPixelY) % textureToTile.height : (j + offsetPixelY) % textureToTile.height)); } } canvas.Apply(); return(canvas); }
public void SaveAtlasToFile(string pathOfAtlas, List <Texture2D> texturesOfMaterial, List <Vector2> scales, List <Vector2> offsets) { isTextureReadableList.Clear(); textureFormatsUnsupported.Clear(); texturePlatforms.Clear(); textureImporterFormats.Clear(); #if !UNITY_5_5_OR_NEWER maxTexturesSizes.Clear(); #endif for (int i = 0; i < texturesOfMaterial.Count; i++) { bool textureNeedsImporting = false; //check if the texture is readable or not, in case is not readable then set it temporarly to readable in order to get the pixels. string texturePath = AssetDatabase.GetAssetPath(texturesOfMaterial[i]); if (texturePath != "") //check that the texture is not a generated texture. { TextureImporter textureImporter = (TextureImporter)AssetImporter.GetAtPath(texturePath); isTextureReadableList.Add(textureImporter.isReadable); if (!textureImporter.isReadable) { textureImporter.isReadable = true; textureNeedsImporting = true; } } else { isTextureReadableList.Add(true); //texture is a generated texture, no need to reimport } /*** make texToProcess format understandable regardless the format it comes from and save the state of the texture ***/ TextureImporter texImporter = AssetImporter.GetAtPath(texturePath) as TextureImporter; texturePlatforms.Add(""); #if UNITY_5_5_OR_NEWER textureImporterFormats.Add(TextureImporterFormat.ARGB32); #else maxTexturesSizes.Add(-1); textureImporterFormats.Add((texturePath != "") ? texImporter.textureFormat : TextureImporterFormat.ARGB32); //if the texture exists in the project settings use its format, else a readable format by default #endif bool unsupportedTextureFormat = !Utils.TextureSupported(texturesOfMaterial[i]); textureFormatsUnsupported.Add(unsupportedTextureFormat); if (unsupportedTextureFormat) { #if !UNITY_5_5_OR_NEWER //unity5.5- texImporter.textureType = TextureImporterType.Advanced; #endif #if !UNITY_5_4_OR_NEWER //since unity5.4 webplayer is not supported anymore if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.WebPlayer || EditorUserBuildSettings.activeBuildTarget == BuildTarget.WebPlayerStreamed) { texturePlatforms[i] = "Web"; } else #endif if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.iOS) { texturePlatforms[i] = "iPhone"; } else if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.Android)// || EditorUserBuildSettings.activeBuildTarget == BuildTarget.SamsungTV) { texturePlatforms[i] = "Android"; } else if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.StandaloneOSXIntel || EditorUserBuildSettings.activeBuildTarget == BuildTarget.StandaloneOSXIntel64 || EditorUserBuildSettings.activeBuildTarget == BuildTarget.StandaloneOSX || EditorUserBuildSettings.activeBuildTarget == BuildTarget.StandaloneWindows || EditorUserBuildSettings.activeBuildTarget == BuildTarget.StandaloneLinux || EditorUserBuildSettings.activeBuildTarget == BuildTarget.StandaloneLinux64 || EditorUserBuildSettings.activeBuildTarget == BuildTarget.StandaloneLinuxUniversal || EditorUserBuildSettings.activeBuildTarget == BuildTarget.StandaloneWindows64) { texturePlatforms[i] = "Standalone"; } #if UNITY_5_5_OR_NEWER TextureImporterPlatformSettings readedSettings = texImporter.GetPlatformTextureSettings(texturePlatforms[i]); readedSettings.format = TextureImporterFormat.ARGB32; texImporter.SetPlatformTextureSettings(readedSettings); #else int maxTexSize = maxTexturesSizes[i]; TextureImporterFormat texImporterFormat = textureImporterFormats[i]; texImporter.GetPlatformTextureSettings(texturePlatforms[i], out maxTexSize, out texImporterFormat); //save the values texImporter.textureFormat = TextureImporterFormat.ARGB32; maxTexturesSizes[i] = maxTexSize; textureImporterFormats[i] = texImporterFormat; texImporter.SetPlatformTextureSettings(texturePlatforms[i], maxTexturesSizes[i], TextureImporterFormat.ARGB32); //set to a readabale format #endif textureNeedsImporting = true; } if (textureNeedsImporting) { AssetDatabase.ImportAsset(texturePath, ImportAssetOptions.ForceUpdate); } /**********************************************************************************************************/ } Texture2D canvas = new Texture2D(atlasWidth, atlasHeight, TextureFormat.ARGB32, false); Color[] baseCol = new Color[atlasWidth * atlasHeight]; for (int i = 0; i < baseCol.Length; i++) { baseCol[i] = new Color(0, 0, 0, 0); } canvas.SetPixels(0, 0, atlasWidth, atlasHeight, baseCol); for (int i = 0; i < texturesOfMaterial.Count; i++) { Texture2D texToProcess = texturesOfMaterial[i]; //check that the texture has the same size than the first catched texture when atlasing (Normally is _MainTex) //if the texture size that we are processing is not the same size of the atlas, then we have to resize the texture. if (texToProcess.width != Mathf.RoundToInt(texturePositions[i].width) || texToProcess.height != Mathf.RoundToInt(texturePositions[i].height)) { texToProcess = Utils.CopyTexture(texturesOfMaterial[i], TextureFormat.ARGB32); Debug.LogWarning("Resizing texture: " + texturesOfMaterial[i].name + " from " + texToProcess.width + "x" + texToProcess.height + " to " + Mathf.RoundToInt(texturePositions[i].width) + "x" + Mathf.RoundToInt(texturePositions[i].height) + " In order to make it fit in the atlas."); TextureScale.Point(texToProcess, Mathf.RoundToInt(texturePositions[i].width), Mathf.RoundToInt(texturePositions[i].height)); } texToProcess = TileManager.TileTexture(texToProcess, scales[i], offsets[i]); Color[] texturePixels = texToProcess.GetPixels(); if (canvas == null) { Debug.LogError("ERROR: Cant bake atlas with multiple materials and an unsupported format, check README.txt on known issues for a workaround. Clear atlas to restore original objects textures"); return; } canvas.SetPixels(Mathf.RoundToInt(texturePositions[i].x), Mathf.RoundToInt(texturePositions[i].y), Mathf.RoundToInt(texturePositions[i].width), Mathf.RoundToInt(texturePositions[i].height), texturePixels); /**********************************************************************************************************/ } canvas.Apply(); byte[] bytes = canvas.EncodeToPNG(); File.WriteAllBytes(pathOfAtlas, bytes); int nextPowerOfTwoCanvasSize = Mathf.NextPowerOfTwo(canvas.width) < Constants.MaxSupportedUnityTexture ? Mathf.NextPowerOfTwo(canvas.width) : Constants.MaxSupportedUnityTexture;//calculate canvas size AssetDatabase.ImportAsset(pathOfAtlas); TextureImporter atlasTextureImporter = AssetImporter.GetAtPath(pathOfAtlas) as TextureImporter; atlasTextureImporter.maxTextureSize = nextPowerOfTwoCanvasSize;//Set the canvas size automatically /**Check if the generated atlas needs to be a normal map, if it needs to be then mark it. we check if it needs by checking texturesOfMaterial[i] importer is a normal map. if it is mark it.****/ string testTexturePath = ""; bool foundTextureInProject = false; for (int i = 0; i < texturesOfMaterial.Count; i++) { testTexturePath = AssetDatabase.GetAssetPath(texturesOfMaterial[i]); if (testTexturePath != "") //we found a texture that resides on the project view, now we can check if is a normal map { foundTextureInProject = true; break; } } if (foundTextureInProject) { TextureImporter textureImporterFlagNormalMap = AssetImporter.GetAtPath(testTexturePath) as TextureImporter; #if UNITY_5_5_OR_NEWER if (textureImporterFlagNormalMap.textureType == TextureImporterType.NormalMap) // NEW UNITY 5.5 { atlasTextureImporter.textureType = TextureImporterType.NormalMap; #else if (textureImporterFlagNormalMap.normalmap) //texture is a normal map!, lets mark our atlas as a normal mapped atlas! { atlasTextureImporter.textureType = TextureImporterType.Bump; atlasTextureImporter.normalmap = true; #endif AssetDatabase.ImportAsset(pathOfAtlas); } } else { Debug.LogWarning("Couldnt know if atlas '" + pathOfAtlas + "' was a normal map, if it was, please set it as a normal map; textures might look weird"); } /**************************************************************************************************************************************************************************************************/ //after finishing all the reading of the textures, revert the state of each of the textures processed. for (int i = 0; i < texturesOfMaterial.Count; i++) { bool textureNeedsReimporting = false; string texturePath = AssetDatabase.GetAssetPath(texturesOfMaterial[i]); //set the texture as not readable if (!isTextureReadableList[i]) { TextureImporter textureImporter = AssetImporter.GetAtPath(texturePath) as TextureImporter; textureImporter.isReadable = false; textureNeedsReimporting = true; //AssetDatabase.ImportAsset(texturePath); } if (textureFormatsUnsupported[i]) { //lets revert to the original texture format TextureImporter textureImporter = AssetImporter.GetAtPath(texturePath) as TextureImporter; #if UNITY_5_5_OR_NEWER TextureImporterPlatformSettings readedSettings = textureImporter.GetPlatformTextureSettings(texturePlatforms[i]); readedSettings.format = textureImporterFormats[i]; textureImporter.SetPlatformTextureSettings(readedSettings); #else textureImporter.textureFormat = textureImporterFormats[i]; textureImporter.SetPlatformTextureSettings(texturePlatforms[i], maxTexturesSizes[i], textureImporterFormats[i]); #endif textureNeedsReimporting = true; //AssetDatabase.ImportAsset(texturePath); } if (textureNeedsReimporting) { AssetDatabase.ImportAsset(texturePath); } } }