// multiAtlas=true, powerOfTwo, padding=8 in X void Test1() { texturePacker = new MB2_TexturePacker(); texturePacker.doPowerOfTwoTextures = true; List <Vector2> images = new List <Vector2>(); images.Add(new Vector2(450, 200)); images.Add(new Vector2(450, 200)); images.Add(new Vector2(450, 80)); texturePacker.LOG_LEVEL = logLevel; rs = texturePacker.GetRects(images, 512, 8, true); Debug.Assert(rs.Length == 2); /* * Debug.Assert(rs[0].atlasX == 512, rs[0].atlasX); * Debug.Assert(rs[0].atlasY == 512, rs[0].atlasY); * Debug.Assert(rs[0].usedW == 466, rs[0].usedW); * Debug.Assert(rs[0].usedH == 432, rs[0].usedH); * Debug.Assert(rs[1].atlasX == 512, rs[1].atlasX); * Debug.Assert(rs[1].atlasY == 256, rs[1].atlasY); * Debug.Assert(rs[1].usedW == 466, rs[1].usedW); * Debug.Assert(rs[1].usedH == 96, rs[1].usedH); */ Debug.Log("Success! "); }
public void RunTestHarness() { texturePacker = new MB2_TexturePacker(); texturePacker.doPowerOfTwoTextures = doPowerOfTwoTextures; texturePacker.LOG_LEVEL = logLevel; rs = texturePacker.GetRects(imgsToAdd, maxDim, padding, doMultiAtlas); if (rs != null) { Debug.Log("NumAtlas= " + rs.Length); for (int i = 0; i < rs.Length; i++) { for (int j = 0; j < rs[i].rects.Length; j++) { Rect r = rs[i].rects[j]; r.x *= rs[i].atlasX; r.y *= rs[i].atlasY; r.width *= rs[i].atlasX; r.height *= rs[i].atlasY; Debug.Log(r.ToString("f5")); } Debug.Log("==============="); } res = "mxX= " + rs[0].atlasX + " mxY= " + rs[0].atlasY; } else { res = "ERROR: PACKING FAILED"; } }
// multiAtlas=true, powerOfTwo=false, padding=8 in Y void Test4() { texturePacker = new MB2_TexturePackerRegular(); texturePacker.atlasMustBePowerOfTwo = false; List <Vector2> images = new List <Vector2>(); images.Add(new Vector2(200, 450)); images.Add(new Vector2(200, 450)); images.Add(new Vector2(80, 450)); texturePacker.LOG_LEVEL = logLevel; rs = texturePacker.GetRects(images, 512, 8, true); Debug.Assert(rs.Length == 2); /* * Debug.Assert(rs[0].atlasX == 432, rs[0].atlasX); * Debug.Assert(rs[0].atlasY == 466, rs[0].atlasY); * Debug.Assert(rs[0].usedW == 432, rs[0].usedW); * Debug.Assert(rs[0].usedH == 466, rs[0].usedH); * Debug.Assert(rs[1].atlasX == 96, rs[1].atlasX); * Debug.Assert(rs[1].atlasY == 466, rs[1].atlasY); * Debug.Assert(rs[1].usedW == 96, rs[1].usedW); * Debug.Assert(rs[1].usedH == 466, rs[1].usedH); */ Debug.Log("Success! "); }
public void RunTestHarness() { if (packerType == PackerType.regular) { texturePacker = new MB2_TexturePackerRegular(); } else if (packerType == PackerType.horizontal) { MB2_TexturePackerHorizontalVert tp = new MB2_TexturePackerHorizontalVert(); tp.packingOrientation = MB2_TexturePackerHorizontalVert.TexturePackingOrientation.horizontal; texturePacker = tp; } else if (packerType == PackerType.vertical) { MB2_TexturePackerHorizontalVert tp = new MB2_TexturePackerHorizontalVert(); tp.packingOrientation = MB2_TexturePackerHorizontalVert.TexturePackingOrientation.vertical; texturePacker = tp; } texturePacker.atlasMustBePowerOfTwo = atlasMustBePowerOfTwo; texturePacker.LOG_LEVEL = logLevel; rs = texturePacker.GetRects(imgsToAdd, maxDim, padding, doMultiAtlas); if (rs != null) { Debug.Log("NumAtlas= " + rs.Length); for (int i = 0; i < rs.Length; i++) { Debug.Log("AtlasSize " + rs[i].atlasX + " mxY= " + rs[i].atlasY); for (int j = 0; j < rs[i].rects.Length; j++) { Rect r = rs[i].rects[j]; r.x *= rs[i].atlasX; r.y *= rs[i].atlasY; r.width *= rs[i].atlasX; r.height *= rs[i].atlasY; Debug.Log(r.ToString("f5")); } Vector2 offset = new Vector2((i * 1.5f) * maxDim, 0); AtlasPackingResult apr = rs[i]; Vector2 center = new Vector2(offset.x + apr.atlasX / 2, offset.y + apr.atlasY / 2); Vector2 sz = new Vector2(apr.atlasX, apr.atlasY); Debug.Log("==============="); } if (rs.Length > 0) { res = "mxX= " + rs[0].atlasX + " mxY= " + rs[0].atlasY; } } else { res = "ERROR: PACKING FAILED"; } }
public void GenerateListOfImagesToAdd() { imgsToAdd = new List <Vector2>(); for (int i = 0; i < numTex; i++) { Vector2 img = new Vector2(Mathf.RoundToInt(UnityEngine.Random.Range(min, max) * xMult), Mathf.RoundToInt(UnityEngine.Random.Range(min, max) * yMult)); if (imgsMustBePowerOfTwo) { img.x = MB2_TexturePacker.RoundToNearestPositivePowerOfTwo((int)img.x); img.y = MB2_TexturePacker.RoundToNearestPositivePowerOfTwo((int)img.y); } imgsToAdd.Add(img); } }
Rect[] __CreateAtlasesMBTexturePacker(ProgressUpdateDelegate progressInfo, int numAtlases, List<MB_TexSet> distinctMaterialTextures, List<string> texPropertyNames, Material resultMaterial, Texture2D[] atlases, MB2_EditorMethodsInterface textureEditorMethods, int _padding){ Rect[] uvRects; if (distinctMaterialTextures.Count == 1){ if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Only one image per atlas. Will re-use original texture"); uvRects = new Rect[1]; uvRects[0] = new Rect(0f,0f,1f,1f); for (int i = 0; i < numAtlases; i++){ MeshBakerMaterialTexture dmt = distinctMaterialTextures[0].ts[i]; atlases[i] = dmt.t; resultMaterial.SetTexture(texPropertyNames[i],atlases[i]); resultMaterial.SetTextureScale(texPropertyNames[i],dmt.scale); resultMaterial.SetTextureOffset(texPropertyNames[i],dmt.offset); } } else { List<Vector2> imageSizes = new List<Vector2>(); for (int i = 0; i < distinctMaterialTextures.Count; i++){ imageSizes.Add(new Vector2(distinctMaterialTextures[i].idealWidth, distinctMaterialTextures[i].idealHeight)); } MB2_TexturePacker tp = new MB2_TexturePacker(); int atlasSizeX = 1; int atlasSizeY = 1; //todo add sanity warnings for huge atlasesr int atlasMaxDimension = 4096; if (textureEditorMethods != null) atlasMaxDimension = textureEditorMethods.GetMaximumAtlasDimension(); uvRects = tp.GetRects(imageSizes,atlasMaxDimension,_padding,out atlasSizeX, out atlasSizeY); if (LOG_LEVEL >= MB2_LogLevel.info) Debug.Log("Generated atlas will be " + atlasSizeX + "x" + atlasSizeY + " (Max atlas size for platform: " + atlasMaxDimension + ")"); for (int i = 0; i < numAtlases; i++){ GC.Collect(); if (progressInfo != null) progressInfo("Creating Atlas '" + texPropertyNames[i] + "'", .01f); Color[] atlasPixels = new Color[atlasSizeX * atlasSizeY];//atlas.GetPixels(); for (int j = 0; j < atlasPixels.Length; j++) atlasPixels[j] = Color.clear; for (int j = 0; j < distinctMaterialTextures.Count; j++){ if (LOG_LEVEL >= MB2_LogLevel.trace) MB2_Log.Trace("Adding texture {0} to atlas {1}", distinctMaterialTextures[j].ts[i].t == null ? "null" : distinctMaterialTextures[j].ts[i].t.ToString(),texPropertyNames[i]); Rect r = uvRects[j]; Texture2D t = distinctMaterialTextures[j].ts[i].t; int x = Mathf.RoundToInt(r.x * atlasSizeX); int y = Mathf.RoundToInt(r.y * atlasSizeY); int ww = Mathf.RoundToInt(r.width * atlasSizeX); int hh = Mathf.RoundToInt(r.height * atlasSizeY); if (ww == 0 || hh == 0) Debug.LogError("Image in atlas has no height or width"); if (textureEditorMethods != null) textureEditorMethods.SetReadWriteFlag(t, true, true); if (progressInfo != null) progressInfo("Copying to atlas: '" + distinctMaterialTextures[j].ts[i].t + "'", .02f); CopyScaledAndTiledToAtlas(distinctMaterialTextures[j].ts[i],x,y,ww,hh,fixOutOfBoundsUVs,maxTilingBakeSize,atlasPixels,atlasSizeX,progressInfo); } if (progressInfo != null) progressInfo("Applying changes to atlas: '" + texPropertyNames[i] + "'", .03f); Texture2D atlas = new Texture2D(atlasSizeX, atlasSizeY,TextureFormat.ARGB32, true); atlas.SetPixels(atlasPixels); atlas.Apply(); if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Saving atlas " + texPropertyNames[i] + " w=" + atlas.width + " h=" + atlas.height); atlases[i] = atlas; if (progressInfo != null) progressInfo("Saving atlas: '" + texPropertyNames[i] + "'", .04f); if (saveAtlasesAsAssets && textureEditorMethods != null){ textureEditorMethods.SaveAtlasToAssetDatabase(atlases[i], texPropertyNames[i], i, resultMaterial); } else { resultMaterial.SetTexture(texPropertyNames[i], atlases[i]); } resultMaterial.SetTextureOffset(texPropertyNames[i], Vector2.zero); resultMaterial.SetTextureScale(texPropertyNames[i],Vector2.one); _destroyTemporaryTextures(); // need to save atlases before doing this } } return uvRects; }
Rect[] __CreateAtlasesMBTexturePackerFast(ProgressUpdateDelegate progressInfo, int numAtlases, List<MB_TexSet> distinctMaterialTextures, List<ShaderTextureProperty> texPropertyNames, bool[] allTexturesAreNullAndSameColor, Material resultMaterial, Texture2D[] atlases, MB2_EditorMethodsInterface textureEditorMethods, int _padding) { Rect[] uvRects; if (distinctMaterialTextures.Count == 1){ if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Only one image per atlas. Will re-use original texture"); uvRects = new Rect[1]; uvRects[0] = new Rect(0f,0f,1f,1f); for (int i = 0; i < numAtlases; i++){ MeshBakerMaterialTexture dmt = distinctMaterialTextures[0].ts[i]; atlases[i] = dmt.t; resultMaterial.SetTexture(texPropertyNames[i].name,atlases[i]); resultMaterial.SetTextureScale(texPropertyNames[i].name,dmt.scale); resultMaterial.SetTextureOffset(texPropertyNames[i].name,dmt.offset); } } else { List<Vector2> imageSizes = new List<Vector2>(); for (int i = 0; i < distinctMaterialTextures.Count; i++){ imageSizes.Add(new Vector2(distinctMaterialTextures[i].idealWidth, distinctMaterialTextures[i].idealHeight)); } MB2_TexturePacker tp = new MB2_TexturePacker(); tp.doPowerOfTwoTextures = _meshBakerTexturePackerForcePowerOfTwo; int atlasSizeX = 1; int atlasSizeY = 1; //todo add sanity warnings for huge atlasesr int atlasMaxDimension = _maxAtlasSize; //if (textureEditorMethods != null) atlasMaxDimension = textureEditorMethods.GetMaximumAtlasDimension(); uvRects = tp.GetRects(imageSizes,atlasMaxDimension,_padding,out atlasSizeX, out atlasSizeY); if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Generated atlas will be " + atlasSizeX + "x" + atlasSizeY + " (Max atlas size for platform: " + atlasMaxDimension + ")"); //create a game object GameObject renderAtlasesGO = new GameObject("MBrenderAtlasesGO"); MB3_AtlasPackerRenderTexture atlasRenderTexture = renderAtlasesGO.AddComponent<MB3_AtlasPackerRenderTexture>(); for (int i = 0; i < numAtlases; i++){ Texture2D atlas = null; if (allTexturesAreNullAndSameColor[i]){ atlas = null; if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Not creating atlas for " + texPropertyNames[i].name + " because textures are null and default value parameters are the same."); } else { GC.Collect(); if (progressInfo != null) progressInfo("Creating Atlas '" + texPropertyNames[i].name + "'", .01f); // =========== // configure it atlasRenderTexture.width = atlasSizeX; atlasRenderTexture.height = atlasSizeY; atlasRenderTexture.padding = _padding; atlasRenderTexture.rects = uvRects; atlasRenderTexture.textureSets = distinctMaterialTextures; atlasRenderTexture.indexOfTexSetToRender = 0; // call render on it atlas = atlasRenderTexture.OnRenderAtlas(); // destroy it // ============= if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Saving atlas " + texPropertyNames[i].name + " w=" + atlas.width + " h=" + atlas.height); } atlases[i] = atlas; if (progressInfo != null) progressInfo("Saving atlas: '" + texPropertyNames[i].name + "'", .04f); if (_saveAtlasesAsAssets && textureEditorMethods != null){ textureEditorMethods.SaveAtlasToAssetDatabase(atlases[i], texPropertyNames[i], i, resultMaterial); } else { resultMaterial.SetTexture(texPropertyNames[i].name, atlases[i]); } resultMaterial.SetTextureOffset(texPropertyNames[i].name, Vector2.zero); resultMaterial.SetTextureScale(texPropertyNames[i].name,Vector2.one); _destroyTemporaryTextures(); // need to save atlases before doing this } } return uvRects; }
Rect[] __CreateAtlasesMBTexturePacker(ProgressUpdateDelegate progressInfo, int numAtlases, List<MB_TexSet> distinctMaterialTextures, List<ShaderTextureProperty> texPropertyNames, bool[] allTexturesAreNullAndSameColor, Material resultMaterial, Texture2D[] atlases, MB2_EditorMethodsInterface textureEditorMethods, int _padding) { Rect[] uvRects; if (distinctMaterialTextures.Count == 1){ if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Only one image per atlas. Will re-use original texture"); uvRects = new Rect[1]; uvRects[0] = new Rect(0f,0f,1f,1f); for (int i = 0; i < numAtlases; i++){ MeshBakerMaterialTexture dmt = distinctMaterialTextures[0].ts[i]; atlases[i] = dmt.t; resultMaterial.SetTexture(texPropertyNames[i].name,atlases[i]); resultMaterial.SetTextureScale(texPropertyNames[i].name,dmt.scale); resultMaterial.SetTextureOffset(texPropertyNames[i].name,dmt.offset); } } else { List<Vector2> imageSizes = new List<Vector2>(); for (int i = 0; i < distinctMaterialTextures.Count; i++){ imageSizes.Add(new Vector2(distinctMaterialTextures[i].idealWidth, distinctMaterialTextures[i].idealHeight)); } MB2_TexturePacker tp = new MB2_TexturePacker(); tp.doPowerOfTwoTextures = _meshBakerTexturePackerForcePowerOfTwo; int atlasSizeX = 1; int atlasSizeY = 1; //todo add sanity warnings for huge atlasesr int atlasMaxDimension = _maxAtlasSize; //if (textureEditorMethods != null) atlasMaxDimension = textureEditorMethods.GetMaximumAtlasDimension(); uvRects = tp.GetRects(imageSizes,atlasMaxDimension,_padding,out atlasSizeX, out atlasSizeY); if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Generated atlas will be " + atlasSizeX + "x" + atlasSizeY + " (Max atlas size for platform: " + atlasMaxDimension + ")"); for (int i = 0; i < numAtlases; i++){ Texture2D atlas = null; if (allTexturesAreNullAndSameColor[i]){ atlas = null; if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Not creating atlas for " + texPropertyNames[i].name + " because textures are null and default value parameters are the same."); } else { GC.Collect(); if (progressInfo != null) progressInfo("Creating Atlas '" + texPropertyNames[i].name + "'", .01f); //use a jagged array because it is much more efficient in memory Color[][] atlasPixels = new Color[atlasSizeY][]; for (int j = 0; j < atlasPixels.Length; j++){ atlasPixels[j] = new Color[atlasSizeX]; } bool isNormalMap = false; if (texPropertyNames[i].isNormalMap) isNormalMap = true; // for (int j = 0; j < atlasPixels.Length; j++) { // for (int k = 0; k < atlasSizeX; k++){ // atlasPixels[j][k] = GetColorIfNoTexture( // if (isNormalMap){ // atlasPixels[j][k] = new Color(.5f,.5f,1f); //neutral bluish for normal maps // } else { // atlasPixels[j][k] = Color.clear; // } // } // } for (int j = 0; j < distinctMaterialTextures.Count; j++){ if (LOG_LEVEL >= MB2_LogLevel.trace) MB2_Log.Trace("Adding texture {0} to atlas {1}", distinctMaterialTextures[j].ts[i].t == null ? "null" : distinctMaterialTextures[j].ts[i].t.ToString(),texPropertyNames[i]); Rect r = uvRects[j]; Texture2D t = distinctMaterialTextures[j].ts[i].t; int x = Mathf.RoundToInt(r.x * atlasSizeX); int y = Mathf.RoundToInt(r.y * atlasSizeY); int ww = Mathf.RoundToInt(r.width * atlasSizeX); int hh = Mathf.RoundToInt(r.height * atlasSizeY); if (ww == 0 || hh == 0) Debug.LogError("Image in atlas has no height or width"); if (textureEditorMethods != null) textureEditorMethods.SetReadWriteFlag(t, true, true); if (progressInfo != null) progressInfo("Copying to atlas: '" + distinctMaterialTextures[j].ts[i].t + "'", .02f); CopyScaledAndTiledToAtlas(distinctMaterialTextures[j].ts[i],x,y,ww,hh,_fixOutOfBoundsUVs,_maxTilingBakeSize,atlasPixels,atlasSizeX,isNormalMap,progressInfo); } if (progressInfo != null) progressInfo("Applying changes to atlas: '" + texPropertyNames[i].name + "'", .03f); atlas = new Texture2D(atlasSizeX, atlasSizeY,TextureFormat.ARGB32, true); for (int j = 0; j < atlasPixels.Length; j++){ atlas.SetPixels(0,j,atlasSizeX,1,atlasPixels[j]); } atlas.Apply(); if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Saving atlas " + texPropertyNames[i].name + " w=" + atlas.width + " h=" + atlas.height); } atlases[i] = atlas; if (progressInfo != null) progressInfo("Saving atlas: '" + texPropertyNames[i].name + "'", .04f); if (_saveAtlasesAsAssets && textureEditorMethods != null){ textureEditorMethods.SaveAtlasToAssetDatabase(atlases[i], texPropertyNames[i], i, resultMaterial); } else { resultMaterial.SetTexture(texPropertyNames[i].name, atlases[i]); } resultMaterial.SetTextureOffset(texPropertyNames[i].name, Vector2.zero); resultMaterial.SetTextureScale(texPropertyNames[i].name,Vector2.one); _destroyTemporaryTextures(); // need to save atlases before doing this } } return uvRects; }