TextureImportSettings CheckTextureImportSettings(Texture2D texture) { TextureImportSettings importSettings; #if UNITY_EDITOR string path = AssetDatabase.GetAssetPath(texture); // Check if textures settings has already been setted up if (importedTextures.ContainsKey(texture.GetInstanceID())) { importSettings = importedTextures[texture.GetInstanceID()]; if (!importSettings.isNormal) { return(importSettings); } } else { importSettings = new TextureImportSettings(); } TextureImporter textureImporter = AssetImporter.GetAtPath(path) as TextureImporter; if (textureImporter != null) { if (!textureImporter.isReadable) { textureImporter.isReadable = true; AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate); } #if UNITY_2017_1_OR_NEWER if (textureImporter.textureType == TextureImporterType.NormalMap) { textureImporter.textureType = TextureImporterType.Default; AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate); importSettings.isNormal = true; } #endif } else { try { texture.GetPixel(0, 0); } catch { importSettings.isReadable = false; Logger.Instance.AddLog("SuperCombiner", "The texture '" + texture.name + "' has a format not handled by Unity, the result in atlas may be inconsistent.", Logger.LogLevel.LOG_WARNING); } } #else importSettings = new TextureImportSettings(); #endif importSettings.isReadable = true; if (!importedTextures.ContainsKey(texture.GetInstanceID())) { importedTextures.Add(texture.GetInstanceID(), importSettings); } return(importSettings); }
/// <summary> /// Returns the texture that will be put in the atlas. /// This texture may differs from original texture in case of tiling, or if texture needs to be resized /// </summary> /// <param name="texture"></param> /// <param name="materialUVBounds"></param> /// <param name="meshUVBounds"></param> /// <param name="mat"></param> /// <param name="textureInAtlasSize"></param> /// <param name="targetTextureSize"></param> /// <param name="isMainTexture"></param> /// <returns></returns> private Texture2D CopyTexture(Texture2D texture, Rect materialUVBounds, Rect meshUVBounds, Material mat, Vector3 textureInAtlasSize, Vector2 targetTextureSize, bool isMainTexture) { int xSens = (int)Mathf.Sign(materialUVBounds.width); int ySens = (int)Mathf.Sign(materialUVBounds.height); float repeatX = Mathf.Abs(materialUVBounds.width); float repeatY = Mathf.Abs(materialUVBounds.height); Color mainColor = Color.white; if (mat.HasProperty("_Color")) { mainColor = mat.color; } bool hasUVoutOfBound = false; if (repeatX != 1 || repeatY != 1 || materialUVBounds.position != Vector2.zero) { hasUVoutOfBound = true; } // Check Texture import settings TextureImportSettings importSettings = CheckTextureImportSettings(texture); // If an error occured, return a simple white texture if (!importSettings.isReadable) { Logger.Instance.AddLog("SuperCombiner", "The format of texture '" + texture.name + "' is not handled by Unity. Try manually setting 'Read/Write Enabled' parameter to true or converting this texture into a known format.", Logger.LogLevel.LOG_ERROR); return(CreateColoredTexture2D((int)textureInAtlasSize.x, (int)textureInAtlasSize.y, Color.white)); } // Get a copy of the original texture so that it remains intact Texture2D uncompressedTexture = new Texture2D(texture.width, texture.height, TextureFormat.RGBA32, false); uncompressedTexture.name = texture.name; // Copy original pixels /!\ Only possible if the texture could be red correctly uncompressedTexture.SetPixels(texture.GetPixels()); if (texture.width != (int)targetTextureSize.x || texture.height != (int)targetTextureSize.y) { // Scale the texture to it's max size so that all textures from this _material share the same texture size TextureScale.Bilinear(uncompressedTexture, (int)targetTextureSize.x, (int)targetTextureSize.y); Logger.Instance.AddLog("SuperCombiner", "Texture '" + texture.name + "' will be scaled from " + GetStringTextureSize(texture.width, texture.height) + " to " + GetStringTextureSize(targetTextureSize.x, targetTextureSize.y) + " to match the size of the other textures in _material '" + mat.name + "'", Logger.LogLevel.LOG_WARNING); } // Create a new Texture2D which will contain the adjusted texture tilled and scaled Texture2D copy = new Texture2D((int)textureInAtlasSize.x, (int)textureInAtlasSize.y, uncompressedTexture.format, false); copy.name = texture.name; // If the tiled texture exceeds the maximum texture size, we have to shrink the texture if (textureInAtlasSize.z != 1 && textureInAtlasSize.z > 0) { TextureScale.Bilinear(uncompressedTexture, uncompressedTexture.width / (int)textureInAtlasSize.z, uncompressedTexture.height / (int)textureInAtlasSize.z); } if (hasUVoutOfBound) { if (Mathf.Abs(textureInAtlasSize.x - uncompressedTexture.width) > 1 || Mathf.Abs(textureInAtlasSize.y - uncompressedTexture.height) > 1) { Logger.Instance.AddLog("SuperCombiner", "Texture '" + texture.name + "' is being tiled in the atlas because mesh using it has UVs out of [0, 1] bound. The tiled size is " + GetStringTextureSize(textureInAtlasSize.x, textureInAtlasSize.y) + "."); } // If UVs are out of [0, 1] bound we have to duplicate the texture int xOffset = (int)(meshUVBounds.xMin * uncompressedTexture.width * mat.mainTextureScale.x + mat.mainTextureOffset.x * uncompressedTexture.width); int yOffset = (int)(meshUVBounds.yMin * uncompressedTexture.height * mat.mainTextureScale.y + mat.mainTextureOffset.y * uncompressedTexture.height); int i = 0, j = 0; if (xSens < 0 || ySens < 0 || ((!mainColor.Equals(Color.white)) && isMainTexture)) { for (i = 0; i < copy.width; i++) { for (j = 0; j < copy.height; j++) { copy.SetPixel(i, j, uncompressedTexture.GetPixel(xSens * (i + xOffset) % uncompressedTexture.width, ySens * (j + yOffset) % uncompressedTexture.height) * mainColor); } } } else { int blockWidth = 0, blockHeight = 0; while (i < copy.width) { int posx = (xSens * (i + xOffset) % uncompressedTexture.width + uncompressedTexture.width) % uncompressedTexture.width; blockWidth = (i + uncompressedTexture.width <= copy.width) ? uncompressedTexture.width : copy.width - i; if (posx + blockWidth > uncompressedTexture.width) { blockWidth = uncompressedTexture.width - posx; } while (j < copy.height) { int posy = (ySens * (j + yOffset) % uncompressedTexture.height + uncompressedTexture.height) % uncompressedTexture.height; blockHeight = (j + uncompressedTexture.height <= copy.height) ? uncompressedTexture.height : copy.height - j; if (posy + blockHeight > uncompressedTexture.height) { blockHeight = uncompressedTexture.height - posy; } copy.SetPixels(i, j, blockWidth, blockHeight, uncompressedTexture.GetPixels(posx, posy, blockWidth, blockHeight)); j += blockHeight; } j = 0; i += blockWidth; } } } else { if (mainColor.Equals(Color.white) || !isMainTexture) { // UVs are all inside [0, 1] bound, so we can fast copy this texture copy.LoadRawTextureData(uncompressedTexture.GetRawTextureData()); } else { for (int i = 0; i < copy.width; i++) { for (int j = 0; j < copy.height; j++) { copy.SetPixel(i, j, uncompressedTexture.GetPixel(i, j) * mainColor); } } } } return(copy); }