/// <summary> /// 计算合并贴图 Atlas Rect /// </summary> /// <param name="data"></param> /// <param name="doMultiAtlas"></param> /// <returns></returns> public static AtlasPackingResult[] CalculateAtlasRectanglesStatic(TexturePipelineData data, bool doMultiAtlas) { List <Vector2> imageSizes = new List <Vector2>(); for (int i = 0; i < data.distinctMaterialTextures.Count; i++) { imageSizes.Add(new Vector2(data.distinctMaterialTextures[i].idealWidth, data.distinctMaterialTextures[i].idealHeight)); } TexturePacker tp = CreateTexturePacker(data._packingAlgorithm); tp.atlasMustBePowerOfTwo = data._meshBakerTexturePackerForcePowerOfTwo; List <AtlasPadding> paddings = new List <AtlasPadding>(); for (int i = 0; i < imageSizes.Count; i++) { AtlasPadding padding = new AtlasPadding(); padding.topBottom = data._atlasPadding; padding.leftRight = data._atlasPadding; if (data._packingAlgorithm == PackingAlgorithmEnum.MeshBakerTexturePacker_Horizontal) { padding.leftRight = 0; } if (data._packingAlgorithm == PackingAlgorithmEnum.MeshBakerTexturePacker_Vertical) { padding.topBottom = 0; } paddings.Add(padding); } return(tp.GetRects(imageSizes, paddings, data._maxAtlasWidth, data._maxAtlasHeight, doMultiAtlas)); }
public AtlasPackingResult[] CalculateAtlasRectangles(TexturePipelineData data, bool doMultiAtlas) { Debug.Assert(data.IsOnlyOneTextureInAtlasReuseTextures()); Debug.Log("Only one image per atlas. Will re-use original texture"); AtlasPackingResult[] packerRects = new AtlasPackingResult[1]; AtlasPadding[] paddings = new AtlasPadding[] { new AtlasPadding(data._atlasPadding) }; packerRects[0] = new AtlasPackingResult(paddings); packerRects[0].rects = new Rect[1]; packerRects[0].srcImgIdxs = new int[] { 0 }; packerRects[0].rects[0] = new Rect(0f, 0f, 1f, 1f); MaterialPropTexture dmt = null; if (data.distinctMaterialTextures[0].ts.Length > 0) { dmt = data.distinctMaterialTextures[0].ts[0]; } if (dmt == null || dmt.isNull) { packerRects[0].atlasX = 16; packerRects[0].atlasY = 16; packerRects[0].usedW = 16; packerRects[0].usedH = 16; } else { packerRects[0].atlasX = dmt.width; packerRects[0].atlasY = dmt.height; packerRects[0].usedW = dmt.width; packerRects[0].usedH = dmt.height; } return(packerRects); }
//normalize atlases so that that rects are 0 to 1 public void normalizeRects(AtlasPackingResult rr, AtlasPadding padding) { for (int i = 0; i < rr.rects.Length; i++) { rr.rects[i].x = (rr.rects[i].x + padding.leftRight) / rr.atlasX; rr.rects[i].y = (rr.rects[i].y + padding.topBottom) / rr.atlasY; rr.rects[i].width = (rr.rects[i].width - padding.leftRight * 2) / rr.atlasX; rr.rects[i].height = (rr.rects[i].height - padding.topBottom * 2) / rr.atlasY; } }
public override AtlasPackingResult[] GetRects(List <Vector2> imgWidthHeights, int maxDimensionX, int maxDimensionY, int atPadding) { List <AtlasPadding> padding = new List <AtlasPadding>(); for (int i = 0; i < imgWidthHeights.Count; i++) { AtlasPadding p = new AtlasPadding(); p.leftRight = p.topBottom = atPadding; padding.Add(p); } return(GetRects(imgWidthHeights, padding, maxDimensionX, maxDimensionY, false)); }
public override AtlasPackingResult[] GetRects(List <Vector2> imgWidthHeights, int maxDimensionX, int maxDimensionY, int padding) { List <AtlasPadding> paddings = new List <AtlasPadding>(); for (int i = 0; i < imgWidthHeights.Count; i++) { AtlasPadding p = new AtlasPadding(); if (packingOrientation == TexturePackingOrientation.horizontal) { p.leftRight = 0; p.topBottom = 8; } else { p.leftRight = 8; p.topBottom = 0; } paddings.Add(p); } return(GetRects(imgWidthHeights, paddings, maxDimensionX, maxDimensionY, false)); }
internal static IEnumerator CopyScaledAndTiledToAtlas(MaterialPropTexture source, MaterialPropTexturesSet sourceMaterial, ShaderTextureProperty shaderPropertyName, DRect srcSamplingRect, int targX, int targY, int targW, int targH, AtlasPadding padding, Color[][] atlasPixels, bool isNormalMap, TexturePipelineData data, TextureCombineHandler combiner, ProgressUpdateDelegate progressInfo = null) { //HasFinished = false; Texture2D t = source.GetTexture2D(); Debug.Log(string.Format("CopyScaledAndTiledToAtlas: {0} inAtlasX={1} inAtlasY={2} inAtlasW={3} inAtlasH={4} paddX={5} paddY={6} srcSamplingRect={7}", t, targX, targY, targW, targH, padding.leftRight, padding.topBottom, srcSamplingRect)); float newWidth = targW; float newHeight = targH; float scx = (float)srcSamplingRect.width; float scy = (float)srcSamplingRect.height; float ox = (float)srcSamplingRect.x; float oy = (float)srcSamplingRect.y; int w = (int)newWidth; int h = (int)newHeight; if (data._considerNonTextureProperties) { t = combiner._createTextureCopy(shaderPropertyName.name, t); t = data.nonTexturePropertyBlender.TintTextureWithTextureCombiner(t, sourceMaterial, shaderPropertyName); } for (int i = 0; i < w; i++) { if (progressInfo != null && w > 0) { progressInfo("CopyScaledAndTiledToAtlas " + (((float)i / (float)w) * 100f).ToString("F0"), .2f); } for (int j = 0; j < h; j++) { float u = i / newWidth * scx + ox; float v = j / newHeight * scy + oy; atlasPixels[targY + j][targX + i] = t.GetPixelBilinear(u, v); } } //bleed the border colors into the padding for (int i = 0; i < w; i++) { for (int j = 1; j <= padding.topBottom; j++) { //top margin atlasPixels[(targY - j)][targX + i] = atlasPixels[(targY)][targX + i]; //bottom margin atlasPixels[(targY + h - 1 + j)][targX + i] = atlasPixels[(targY + h - 1)][targX + i]; } } for (int j = 0; j < h; j++) { for (int i = 1; i <= padding.leftRight; i++) { //left margin atlasPixels[(targY + j)][targX - i] = atlasPixels[(targY + j)][targX]; //right margin atlasPixels[(targY + j)][targX + w + i - 1] = atlasPixels[(targY + j)][targX + w - 1]; } } //corners for (int i = 1; i <= padding.leftRight; i++) { for (int j = 1; j <= padding.topBottom; j++) { atlasPixels[(targY - j)][targX - i] = atlasPixels[targY][targX]; atlasPixels[(targY + h - 1 + j)][targX - i] = atlasPixels[(targY + h - 1)][targX]; atlasPixels[(targY + h - 1 + j)][targX + w + i - 1] = atlasPixels[(targY + h - 1)][targX + w - 1]; atlasPixels[(targY - j)][targX + w + i - 1] = atlasPixels[targY][targX + w - 1]; yield return(null); } yield return(null); } yield break; }
/* * Packed rects may exceed atlas size and require scaling * When scaling want pixel perfect fit in atlas. Corners of rects should exactly align with pixel grid * Padding should be subtracted from pixel perfect rect to create pixel perfect square * TODO this doesn't handle each rectangle having different padding */ internal bool ScaleAtlasToFitMaxDim(Vector2 rootWH, List <ImageAreaInAtlas> images, int maxDimensionX, int maxDimensionY, AtlasPadding padding, int minImageSizeX, int minImageSizeY, int masterImageSizeX, int masterImageSizeY, ref int outW, ref int outH, out float padX, out float padY, out int newMinSizeX, out int newMinSizeY) { newMinSizeX = minImageSizeX; newMinSizeY = minImageSizeY; bool redoPacking = false; // the atlas may be packed larger than the maxDimension. If so then the atlas needs to be scaled down to fit padX = (float)padding.leftRight / (float)outW; //padding needs to be pixel perfect in size if (rootWH.x > maxDimensionX) { padX = (float)padding.leftRight / (float)maxDimensionX; float scaleFactor = (float)maxDimensionX / (float)rootWH.x; Debug.LogWarning("Packing exceeded atlas width shrinking to " + scaleFactor); for (int i = 0; i < images.Count; i++) { ImageAreaInAtlas im = images[i]; if (im.w * scaleFactor < masterImageSizeX) { //check if small images will be rounded too small. If so need to redo packing forcing a larger min size Debug.Log("Small images are being scaled to zero. Will need to redo packing with larger minTexSizeX."); redoPacking = true; newMinSizeX = Mathf.CeilToInt(minImageSizeX / scaleFactor); } int right = (int)((im.x + im.w) * scaleFactor); im.x = (int)(scaleFactor * im.x); im.w = right - im.x; } outW = maxDimensionX; } padY = (float)padding.topBottom / (float)outH; if (rootWH.y > maxDimensionY) { //float minSizeY = ((float)minImageSizeY + 1) / maxDimension; padY = (float)padding.topBottom / (float)maxDimensionY; float scaleFactor = (float)maxDimensionY / (float)rootWH.y; Debug.LogWarning("Packing exceeded atlas height shrinking to " + scaleFactor); for (int i = 0; i < images.Count; i++) { ImageAreaInAtlas im = images[i]; if (im.h * scaleFactor < masterImageSizeY) { //check if small images will be rounded too small. If so need to redo packing forcing a larger min size Debug.Log("Small images are being scaled to zero. Will need to redo packing with larger minTexSizeY."); redoPacking = true; newMinSizeY = Mathf.CeilToInt(minImageSizeY / scaleFactor); } int bottom = (int)((im.y + im.h) * scaleFactor); im.y = (int)(scaleFactor * im.y); im.h = bottom - im.y; } outH = maxDimensionY; } return(redoPacking); }
public void InitializeAtlasPadding(ref AtlasPadding padding, int paddingValue) { padding.topBottom = 0; padding.leftRight = paddingValue; }
private static AtlasPackingResult MergeAtlasPackingResultStackBonA(AtlasPackingResult a, AtlasPackingResult b, int maxWidthDim, int maxHeightDim, bool stretchBToAtlasWidth, IPipeline pipeline) { Debug.Assert(a.usedW == a.atlasX); Debug.Assert(a.usedH == a.atlasY); Debug.Assert(b.usedW == b.atlasX); Debug.Assert(b.usedH == b.atlasY); Debug.Assert(a.usedW <= maxWidthDim, a.usedW + " " + maxWidthDim); Debug.Assert(a.usedH <= maxHeightDim, a.usedH + " " + maxHeightDim); Debug.Assert(b.usedH <= maxHeightDim); Debug.Assert(b.usedW <= maxWidthDim, b.usedW + " " + maxWidthDim); Rect AatlasToFinal; Rect BatlasToFinal; // first calc height scale and offset int atlasX; int atlasY; pipeline.MergeAtlasPackingResultStackBonAInternal(a, b, out AatlasToFinal, out BatlasToFinal, stretchBToAtlasWidth, maxWidthDim, maxHeightDim, out atlasX, out atlasY); Rect[] newRects = new Rect[a.rects.Length + b.rects.Length]; AtlasPadding[] paddings = new AtlasPadding[a.rects.Length + b.rects.Length]; int[] srcImgIdxs = new int[a.rects.Length + b.rects.Length]; Array.Copy(a.padding, paddings, a.padding.Length); Array.Copy(b.padding, 0, paddings, a.padding.Length, b.padding.Length); Array.Copy(a.srcImgIdxs, srcImgIdxs, a.srcImgIdxs.Length); Array.Copy(b.srcImgIdxs, 0, srcImgIdxs, a.srcImgIdxs.Length, b.srcImgIdxs.Length); Array.Copy(a.rects, newRects, a.rects.Length); for (int i = 0; i < a.rects.Length; i++) { Rect r = a.rects[i]; r.x = AatlasToFinal.x + r.x * AatlasToFinal.width; r.y = AatlasToFinal.y + r.y * AatlasToFinal.height; r.width *= AatlasToFinal.width; r.height *= AatlasToFinal.height; Debug.Assert(r.max.x <= 1f); Debug.Assert(r.max.y <= 1f); Debug.Assert(r.min.x >= 0f); Debug.Assert(r.min.y >= 0f); newRects[i] = r; srcImgIdxs[i] = a.srcImgIdxs[i]; } for (int i = 0; i < b.rects.Length; i++) { Rect r = b.rects[i]; r.x = BatlasToFinal.x + r.x * BatlasToFinal.width; r.y = BatlasToFinal.y + r.y * BatlasToFinal.height; r.width *= BatlasToFinal.width; r.height *= BatlasToFinal.height; Debug.Assert(r.max.x <= 1f); Debug.Assert(r.max.y <= 1f); Debug.Assert(r.min.x >= 0f); Debug.Assert(r.min.y >= 0f); newRects[a.rects.Length + i] = r; srcImgIdxs[a.rects.Length + i] = b.srcImgIdxs[i]; } AtlasPackingResult res = new AtlasPackingResult(paddings); res.atlasX = atlasX; res.atlasY = atlasY; res.padding = paddings; res.rects = newRects; res.srcImgIdxs = srcImgIdxs; res.CalcUsedWidthAndHeight(); return(res); }
public override AtlasPackingResult[] CalculateAtlasRectangles(TexturePipelineData data, bool doMultiAtlas) { Debug.Assert(!data.IsOnlyOneTextureInAtlasReuseTextures()); Debug.Assert(data._packingAlgorithm != PackingAlgorithmEnum.UnitysPackTextures, "Unity texture packer cannot be used"); IPipeline pipeline; if (_atlasDirection == AtlasDirection.horizontal) { pipeline = new HorizontalPipeline(); } else { pipeline = new VerticalPipeline(); } //int maxAtlasWidth = data._maxAtlasWidth; //int maxAtlasHeight = data._maxAtlasHeight; if (_atlasDirection == AtlasDirection.horizontal) { if (!data._useMaxAtlasWidthOverride) { // need to get the width of the atlas without mesh uvs considered int maxWidth = 2; for (int i = 0; i < data.distinctMaterialTextures.Count; i++) { MaterialPropTexturesSet ts = data.distinctMaterialTextures[i]; int w; if (data._fixOutOfBoundsUVs) { Vector2 rawHeightWidth = ts.GetMaxRawTextureHeightWidth(); w = (int)rawHeightWidth.x; } else { w = ts.idealWidth; } if (ts.idealWidth > maxWidth) { maxWidth = w; } } Debug.Log("Calculated max atlas width: " + maxWidth); data._maxAtlasWidth = maxWidth; } } else { if (!data._useMaxAtlasHeightOverride) { int maxHeight = 2; for (int i = 0; i < data.distinctMaterialTextures.Count; i++) { MaterialPropTexturesSet ts = data.distinctMaterialTextures[i]; int h; if (data._fixOutOfBoundsUVs) { Vector2 rawHeightWidth = ts.GetMaxRawTextureHeightWidth(); h = (int)rawHeightWidth.y; } else { h = ts.idealHeight; } if (ts.idealHeight > maxHeight) { maxHeight = h; } } Debug.Log("Calculated max atlas height: " + maxHeight); data._maxAtlasHeight = maxHeight; } } //split the list of distinctMaterialTextures into two bins List <MaterialPropTexturesSet> horizontalVerticalDistinctMaterialTextures = new List <MaterialPropTexturesSet>(); List <MaterialPropTexturesSet> regularTextures = new List <MaterialPropTexturesSet>(); for (int i = 0; i < data.distinctMaterialTextures.Count; i++) { pipeline.SortTexSetIntoBins(data.distinctMaterialTextures[i], horizontalVerticalDistinctMaterialTextures, regularTextures, data._maxAtlasWidth, data._maxAtlasHeight); } Debug.Log(String.Format("Splitting list of distinctMaterialTextures numHorizontalVertical={0} numRegular={1} maxAtlasWidth={2} maxAtlasHeight={3}", horizontalVerticalDistinctMaterialTextures.Count, regularTextures.Count, data._maxAtlasWidth, data._maxAtlasHeight)); //pack one bin with the horizontal vertical texture packer. TexturePacker tp; PackingAlgorithmEnum packingAlgorithm; AtlasPackingResult[] packerRectsHorizontalVertical; if (horizontalVerticalDistinctMaterialTextures.Count > 0) { packingAlgorithm = pipeline.GetPackingAlg(); List <Vector2> imageSizesHorizontalVertical = new List <Vector2>(); for (int i = 0; i < horizontalVerticalDistinctMaterialTextures.Count; i++) { horizontalVerticalDistinctMaterialTextures[i].SetTilingTreatmentAndAdjustEncapsulatingSamplingRect(pipeline.GetEdge2EdgeTreatment()); imageSizesHorizontalVertical.Add(new Vector2(horizontalVerticalDistinctMaterialTextures[i].idealWidth, horizontalVerticalDistinctMaterialTextures[i].idealHeight)); } tp = CreateTexturePacker(packingAlgorithm); tp.atlasMustBePowerOfTwo = false; List <AtlasPadding> paddingsHorizontalVertical = new List <AtlasPadding>(); for (int i = 0; i < imageSizesHorizontalVertical.Count; i++) { AtlasPadding padding = new AtlasPadding(); pipeline.InitializeAtlasPadding(ref padding, data._atlasPadding); paddingsHorizontalVertical.Add(padding); } packerRectsHorizontalVertical = tp.GetRects(imageSizesHorizontalVertical, paddingsHorizontalVertical, data._maxAtlasWidth, data._maxAtlasHeight, false); Debug.Log(String.Format("Packed {0} textures with edgeToEdge tiling into an atlas of size {1} by {2} usedW {3} usedH {4}", horizontalVerticalDistinctMaterialTextures.Count, packerRectsHorizontalVertical[0].atlasX, packerRectsHorizontalVertical[0].atlasY, packerRectsHorizontalVertical[0].usedW, packerRectsHorizontalVertical[0].usedH)); } else { packerRectsHorizontalVertical = new AtlasPackingResult[0]; } //pack other bin with regular texture packer AtlasPackingResult[] packerRectsRegular; if (regularTextures.Count > 0) { packingAlgorithm = PackingAlgorithmEnum.MeshBakerTexturePacker; List <Vector2> imageSizesRegular = new List <Vector2>(); for (int i = 0; i < regularTextures.Count; i++) { imageSizesRegular.Add(new Vector2(regularTextures[i].idealWidth, regularTextures[i].idealHeight)); } tp = CreateTexturePacker(PackingAlgorithmEnum.MeshBakerTexturePacker); tp.atlasMustBePowerOfTwo = false; List <AtlasPadding> paddingsRegular = new List <AtlasPadding>(); for (int i = 0; i < imageSizesRegular.Count; i++) { AtlasPadding padding = new AtlasPadding(); padding.topBottom = data._atlasPadding; padding.leftRight = data._atlasPadding; paddingsRegular.Add(padding); } int atlasRegularMaxWidth, atlasRegularMaxHeight; int usedHorizontalVertWidth = 0, usedHorizontalVertHeight = 0; if (packerRectsHorizontalVertical.Length > 0) { usedHorizontalVertHeight = packerRectsHorizontalVertical[0].atlasY; usedHorizontalVertWidth = packerRectsHorizontalVertical[0].atlasX; } pipeline.GetExtraRoomForRegularAtlas(usedHorizontalVertWidth, usedHorizontalVertHeight, data._maxAtlasWidth, data._maxAtlasHeight, out atlasRegularMaxWidth, out atlasRegularMaxHeight); packerRectsRegular = tp.GetRects(imageSizesRegular, paddingsRegular, atlasRegularMaxWidth, atlasRegularMaxHeight, false); Debug.Log(String.Format("Packed {0} textures without edgeToEdge tiling into an atlas of size {1} by {2} usedW {3} usedH {4}", regularTextures.Count, packerRectsRegular[0].atlasX, packerRectsRegular[0].atlasY, packerRectsRegular[0].usedW, packerRectsRegular[0].usedH)); } else { packerRectsRegular = new AtlasPackingResult[0]; } AtlasPackingResult result = null; if (packerRectsHorizontalVertical.Length == 0 && packerRectsRegular.Length == 0) { Debug.Assert(false, "Should never have reached this."); return(null); } else if (packerRectsHorizontalVertical.Length > 0 && packerRectsRegular.Length > 0) { result = MergeAtlasPackingResultStackBonA(packerRectsHorizontalVertical[0], packerRectsRegular[0], data._maxAtlasWidth, data._maxAtlasHeight, true, pipeline); } else if (packerRectsHorizontalVertical.Length > 0) { result = packerRectsHorizontalVertical[0]; } else if (packerRectsRegular.Length > 0) { result = packerRectsRegular[0]; } Debug.Assert(data.distinctMaterialTextures.Count == result.rects.Length); //We re-ordered the distinctMaterial textures so replace the list with the new reordered one horizontalVerticalDistinctMaterialTextures.AddRange(regularTextures); data.distinctMaterialTextures = horizontalVerticalDistinctMaterialTextures; AtlasPackingResult[] results; if (result != null) { results = new AtlasPackingResult[] { result } } ; else { results = new AtlasPackingResult[0]; } return(results); }
public ImageAreaInAtlas(int id, int tw, int th, AtlasPadding padding, int minImageSizeX, int minImageSizeY) { imgId = id; w = Mathf.Max(tw + padding.leftRight * 2, minImageSizeX); h = Mathf.Max(th + padding.topBottom * 2, minImageSizeY); }