public override AtlasPackingResult[] CalculateAtlasRectangles(MB3_TextureCombinerPipeline.TexturePipelineData data, bool doMultiAtlas, MB2_LogLevel LOG_LEVEL) { Debug.Assert(!data.OnlyOneTextureInAtlasReuseTextures()); Debug.Assert(data._packingAlgorithm != MB2_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++) { MB_TexSet 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; } } if (LOG_LEVEL >= MB2_LogLevel.debug) { 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++) { MB_TexSet 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; } } if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("Calculated max atlas height: " + maxHeight); } data._maxAtlasHeight = maxHeight; } } //split the list of distinctMaterialTextures into two bins List <MB_TexSet> horizontalVerticalDistinctMaterialTextures = new List <MB_TexSet>(); List <MB_TexSet> regularTextures = new List <MB_TexSet>(); for (int i = 0; i < data.distinctMaterialTextures.Count; i++) { pipeline.SortTexSetIntoBins(data.distinctMaterialTextures[i], horizontalVerticalDistinctMaterialTextures, regularTextures, data._maxAtlasWidth, data._maxAtlasHeight); } if (LOG_LEVEL >= MB2_LogLevel.debug) { 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. MB2_TexturePacker tp; MB2_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 = MB3_TextureCombinerPipeline.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); } tp.LOG_LEVEL = MB2_LogLevel.trace; packerRectsHorizontalVertical = tp.GetRects(imageSizesHorizontalVertical, paddingsHorizontalVertical, data._maxAtlasWidth, data._maxAtlasHeight, false); if (LOG_LEVEL >= MB2_LogLevel.trace) { 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 = MB2_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 = MB3_TextureCombinerPipeline.CreateTexturePacker(MB2_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); if (LOG_LEVEL >= MB2_LogLevel.debug) { 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); }
// This should only be called after regular merge so that rects have been correctly setup. public void MergeDistinctMaterialTexturesThatWouldExceedMaxAtlasSizeAndCalcMaterialSubrects(List <MB_TexSet> distinctMaterialTextures, int maxAtlasSize) { if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("MergeDistinctMaterialTexturesThatWouldExceedMaxAtlasSizeAndCalcMaterialSubrects num atlas rects" + distinctMaterialTextures.Count); } Debug.Assert(_HasBeenInitialized, "MergeOverlappingDistinctMaterialTexturesAndCalcMaterialSubrects must be called before MergeDistinctMaterialTexturesThatWouldExceedMaxAtlasSizeAndCalcMaterialSubrects"); int numMerged = 0; List <int> MarkedForDeletion = new List <int>(); for (int i = 0; i < distinctMaterialTextures.Count; i++) { MB_TexSet tx2 = distinctMaterialTextures[i]; for (int j = i + 1; j < distinctMaterialTextures.Count; j++) { MB_TexSet tx1 = distinctMaterialTextures[j]; if (tx1.AllTexturesAreSameForMerge(tx2, _considerNonTextureProperties, resultMaterialTextureBlender)) { //Check if the size of the rect in the atlas would be greater than max atlas size. DRect encapsulatingRectMerged = new DRect(); int idxOfFirstNotNull = -1; for (int propIdx = 0; propIdx < tx2.ts.Length; propIdx++) { if (!tx2.ts[propIdx].isNull) { if (idxOfFirstNotNull == -1) { idxOfFirstNotNull = propIdx; } } } DRect encapsulatingRect1 = new DRect(); DRect encapsulatingRect2 = new DRect(); if (idxOfFirstNotNull != -1) { // only in here if all properties use the same tiling so don't need to worry about which propIdx we are dealing with //Get the rect that encapsulates all material and UV tiling for materials and meshes in tx1 encapsulatingRect1 = tx1.matsAndGOs.mats[0].samplingRectMatAndUVTiling; for (int matIdx = 1; matIdx < tx1.matsAndGOs.mats.Count; matIdx++) { DRect tmpSsamplingRectMatAndUVTilingTx1 = tx1.matsAndGOs.mats[matIdx].samplingRectMatAndUVTiling; encapsulatingRect1 = MB3_UVTransformUtility.GetEncapsulatingRectShifted(ref encapsulatingRect1, ref tmpSsamplingRectMatAndUVTilingTx1); } //same for tx2 encapsulatingRect2 = tx2.matsAndGOs.mats[0].samplingRectMatAndUVTiling; for (int matIdx = 1; matIdx < tx2.matsAndGOs.mats.Count; matIdx++) { DRect tmpSsamplingRectMatAndUVTilingTx2 = tx2.matsAndGOs.mats[matIdx].samplingRectMatAndUVTiling; encapsulatingRect2 = MB3_UVTransformUtility.GetEncapsulatingRectShifted(ref encapsulatingRect2, ref tmpSsamplingRectMatAndUVTilingTx2); } encapsulatingRectMerged = MB3_UVTransformUtility.GetEncapsulatingRectShifted(ref encapsulatingRect1, ref encapsulatingRect2); } else { encapsulatingRectMerged = new DRect(0f, 0f, 1f, 1f); } Vector2 maxHeightWidth = tx1.GetMaxRawTextureHeightWidth(); if (encapsulatingRectMerged.width * maxHeightWidth.x > maxAtlasSize || encapsulatingRectMerged.height * maxHeightWidth.y > maxAtlasSize) { // merge tx2 into tx1 numMerged++; StringBuilder sb = null; if (LOG_LEVEL >= MB2_LogLevel.info) { sb = new StringBuilder(); sb.AppendFormat("About To Merge:\n TextureSet1 {0}\n TextureSet2 {1}\n", tx1.GetDescription(), tx2.GetDescription()); if (LOG_LEVEL >= MB2_LogLevel.trace) { for (int matIdx = 0; matIdx < tx1.matsAndGOs.mats.Count; matIdx++) { sb.AppendFormat("tx1 Mat {0} matAndMeshUVRect {1} fullSamplingRect {2}\n", tx1.matsAndGOs.mats[matIdx].mat, tx1.matsAndGOs.mats[matIdx].samplingRectMatAndUVTiling, tx1.ts[0].GetEncapsulatingSamplingRect()); } for (int matIdx = 0; matIdx < tx2.matsAndGOs.mats.Count; matIdx++) { sb.AppendFormat("tx2 Mat {0} matAndMeshUVRect {1} fullSamplingRect {2}\n", tx2.matsAndGOs.mats[matIdx].mat, tx2.matsAndGOs.mats[matIdx].samplingRectMatAndUVTiling, tx2.ts[0].GetEncapsulatingSamplingRect()); } } } //copy game objects over for (int k = 0; k < tx2.matsAndGOs.gos.Count; k++) { if (!tx1.matsAndGOs.gos.Contains(tx2.matsAndGOs.gos[k])) { tx1.matsAndGOs.gos.Add(tx2.matsAndGOs.gos[k]); } } //copy materials over from tx2 to tx1 for (int matIdx = 0; matIdx < tx2.matsAndGOs.mats.Count; matIdx++) { tx1.matsAndGOs.mats.Add(tx2.matsAndGOs.mats[matIdx]); } tx1.SetEncapsulatingSamplingRectWhenMergingTexSets(encapsulatingRectMerged); if (!MarkedForDeletion.Contains(i)) { MarkedForDeletion.Add(i); } if (LOG_LEVEL >= MB2_LogLevel.debug) { if (LOG_LEVEL >= MB2_LogLevel.trace) { sb.AppendFormat("=== After Merge TextureSet {0}\n", tx1.GetDescription()); for (int matIdx = 0; matIdx < tx1.matsAndGOs.mats.Count; matIdx++) { sb.AppendFormat("tx1 Mat {0} matAndMeshUVRect {1} fullSamplingRect {2}\n", tx1.matsAndGOs.mats[matIdx].mat, tx1.matsAndGOs.mats[matIdx].samplingRectMatAndUVTiling, tx1.ts[0].GetEncapsulatingSamplingRect()); } //Integrity check that sampling rects fit into enapsulating rects if (MB3_MeshBakerRoot.DO_INTEGRITY_CHECKS) { if (MB3_MeshBakerRoot.DO_INTEGRITY_CHECKS) { DoIntegrityCheckMergedEncapsulatingSamplingRects(distinctMaterialTextures); } } } Debug.Log(sb.ToString()); } break; } else { if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log(string.Format("Considered merging {0} and {1} but there was not enough overlap. It is more efficient to bake these to separate rectangles.", tx1.GetDescription() + encapsulatingRect1, tx2.GetDescription() + encapsulatingRect2)); } } } } } //remove distinctMaterialTextures that were merged for (int j = MarkedForDeletion.Count - 1; j >= 0; j--) { distinctMaterialTextures.RemoveAt(MarkedForDeletion[j]); } MarkedForDeletion.Clear(); if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log(string.Format("MergeDistinctMaterialTexturesThatWouldExceedMaxAtlasSizeAndCalcMaterialSubrects complete merged {0} now have {1}", numMerged, distinctMaterialTextures.Count)); } if (MB3_MeshBakerRoot.DO_INTEGRITY_CHECKS) { DoIntegrityCheckMergedEncapsulatingSamplingRects(distinctMaterialTextures); } }