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); }
public virtual IEnumerator ConvertTexturesToReadableFormats(ProgressUpdateDelegate progressInfo, CombineTexturesIntoAtlasesCoroutineResult result, TexturePipelineData data, TextureCombineHandler combiner, EditorMethodsInterface textureEditorMethods) { Debug.Assert(!data.IsOnlyOneTextureInAtlasReuseTextures()); //MakeProceduralTexturesReadable(progressInfo, result, data, combiner, textureEditorMethods, LOG_LEVEL); for (int i = 0; i < data.distinctMaterialTextures.Count; i++) { for (int j = 0; j < data.texPropertyNames.Count; j++) { MaterialPropTexture ts = data.distinctMaterialTextures[i].ts[j]; if (!ts.isNull) { if (textureEditorMethods != null) { Texture tx = ts.GetTexture2D(); if (progressInfo != null) { progressInfo(String.Format("Convert texture {0} to readable format ", tx), .5f); } textureEditorMethods.AddTextureFormat((Texture2D)tx, data.texPropertyNames[j].isNormalMap); } } } } yield break; }
public IEnumerator ConvertTexturesToReadableFormats(ProgressUpdateDelegate progressInfo, CombineTexturesIntoAtlasesCoroutineResult result, TexturePipelineData data, TextureCombineHandler combiner, EditorMethodsInterface textureEditorMethods) { Debug.Assert(!data.IsOnlyOneTextureInAtlasReuseTextures()); yield break; }
public IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo, TexturePipelineData data, TextureCombineHandler combiner, AtlasPackingResult packedAtlasRects, Texture2D[] atlases, EditorMethodsInterface textureEditorMethods) { Debug.Assert(data.IsOnlyOneTextureInAtlasReuseTextures()); Debug.Log("Only one image per atlas. Will re-use original texture"); for (int i = 0; i < data.numAtlases; i++) { MaterialPropTexture dmt = data.distinctMaterialTextures[0].ts[i]; atlases[i] = dmt.GetTexture2D(); data.resultMaterial.SetTexture(data.texPropertyNames[i].name, atlases[i]); data.resultMaterial.SetTextureScale(data.texPropertyNames[i].name, Vector2.one); data.resultMaterial.SetTextureOffset(data.texPropertyNames[i].name, Vector2.zero); } yield break; }
/// <summary> /// 运行时图片打包 /// </summary> /// <param name="result"></param> /// <param name="data"></param> /// <param name="splitAtlasWhenPackingIfTooBig"></param> /// <param name="textureEditorMethods"></param> /// <param name="packingResult"></param> /// <returns></returns> IEnumerator __RunTexturePackerOnly(CombineTexturesIntoAtlasesCoroutineResult result, TexturePipelineData data, bool splitAtlasWhenPackingIfTooBig, EditorMethodsInterface textureEditorMethods, List <AtlasPackingResult> packingResult) { Debug.Log("__RunTexturePacker texture properties in shader:" + data.texPropertyNames.Count + " objsToMesh:" + data.allObjsToMesh.Count + " _fixOutOfBoundsUVs:" + data._fixOutOfBoundsUVs); List <GameObject> usedObjsToMesh = new List <GameObject>(); yield return(TextureCombinerPipeline.__Step1_CollectDistinctMatTexturesAndUsedObjects(null, result, data, textureEditorMethods, usedObjsToMesh)); if (!result.success) { yield break; } data.allTexturesAreNullAndSameColor = new TextureCombinerPipeline.CreateAtlasForProperty[data.texPropertyNames.Count]; yield return(TextureCombinerPipeline._Step2_CalculateIdealSizesForTexturesInAtlasAndPadding(null, result, data, textureEditorMethods)); if (!result.success) { yield break; } ITextureCombinerPacker texturePaker = TextureCombinerPipeline.CreatePacker(data.IsOnlyOneTextureInAtlasReuseTextures(), data._packingAlgorithm); // run the texture packer only AtlasPackingResult[] aprs = TextureCombinerPipeline.RunTexturePackerOnly(data, splitAtlasWhenPackingIfTooBig, texturePaker); for (int i = 0; i < aprs.Length; i++) { packingResult.Add(aprs[i]); } }
// texPropertyNames 是 resultMaterial中纹理属性的列表 // allowedMaterialsFilter 是材料列表。 没有这些材料的物体将被忽略。这由多种材质过滤器使用 // textureEditorMethods 仅封装编辑器功能,例如保存资产和跟踪纹理资产谁的格式已更改。 如果在运行时使用,则为null。 IEnumerator __CombineTexturesIntoAtlases(ProgressUpdateDelegate progressInfo, CombineTexturesIntoAtlasesCoroutineResult result, AtlasesAndRects resultAtlasesAndRects, TexturePipelineData data, bool splitAtlasWhenPackingIfTooBig, EditorMethodsInterface textureEditorMethods) { if (progressInfo != null) { progressInfo("Collecting textures ", .01f); } // --- 1、记录各合并物体的源材质的 Prop Texture 信息写入 Data.distinctMaterialTextures //每个图集(主图,凹凸等)都将有的 MaterialTextures.Count 个图像。 //每个 distinctMaterialTextures 对应一个游戏物体的某个材质,记录一组纹理,分别材质的在每个Prop图集一个。 List <GameObject> usedObjsToMesh = new List <GameObject>(); yield return(TextureCombinerPipeline.__Step1_CollectDistinctMatTexturesAndUsedObjects(progressInfo, result, data, textureEditorMethods, usedObjsToMesh)); if (!result.success) { yield break; } // --- 2、计算使每个材质属性中的多个材质的合理尺寸 yield return(TextureCombinerPipeline._Step2_CalculateIdealSizesForTexturesInAtlasAndPadding(progressInfo, result, data, textureEditorMethods)); if (!result.success) { yield break; } // --- 3、创建特定打包方式的打包器 ITextureCombinerPacker texturePaker = TextureCombinerPipeline.CreatePacker(data.IsOnlyOneTextureInAtlasReuseTextures(), data._packingAlgorithm); yield return(texturePaker.ConvertTexturesToReadableFormats(progressInfo, result, data, this, textureEditorMethods)); if (!result.success) { yield break; } // --- 4、计算各源材质在合并材质 Atlas 的排布 AtlasPackingResult[] uvRects = texturePaker.CalculateAtlasRectangles(data, splitAtlasWhenPackingIfTooBig); // --- 5、创建 Atlas 并保存 yield return(TextureCombinerPipeline.__Step3_BuildAndSaveAtlasesAndStoreResults(progressInfo, result, data, this, texturePaker, uvRects[0], textureEditorMethods, resultAtlasesAndRects)); }
public override AtlasPackingResult[] CalculateAtlasRectangles(TexturePipelineData data, bool doMultiAtlas) { Debug.Assert(!data.IsOnlyOneTextureInAtlasReuseTextures()); //with Unity texture packer we don't find the rectangles, Unity does. When packer is run return(new AtlasPackingResult[] { new AtlasPackingResult(new AtlasPadding[0]) }); }
public override IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo, TexturePipelineData data, TextureCombineHandler combiner, AtlasPackingResult packedAtlasRects, Texture2D[] atlases, EditorMethodsInterface textureEditorMethods) { Debug.Assert(!data.IsOnlyOneTextureInAtlasReuseTextures()); Rect[] uvRects = packedAtlasRects.rects; long estArea = 0; int atlasSizeX = 1; int atlasSizeY = 1; uvRects = null; for (int propIdx = 0; propIdx < data.numAtlases; propIdx++) { //----------------------- ShaderTextureProperty prop = data.texPropertyNames[propIdx]; Texture2D atlas = null; if (!TextureCombinerPipeline._ShouldWeCreateAtlasForThisProperty(propIdx, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor)) { atlas = null; } else { Debug.LogWarning("Beginning loop " + propIdx + " num temporary textures " + combiner._getNumTemporaryTextures()); TextureCombinerPackerBase.CreateTemporaryTexturesForAtlas(data.distinctMaterialTextures, combiner, propIdx, data); Texture2D[] texToPack = new Texture2D[data.distinctMaterialTextures.Count]; for (int texSetIdx = 0; texSetIdx < data.distinctMaterialTextures.Count; texSetIdx++) { MaterialPropTexturesSet txs = data.distinctMaterialTextures[texSetIdx]; int tWidth = txs.idealWidth; int tHeight = txs.idealHeight; Texture2D tx = txs.ts[propIdx].GetTexture2D(); if (progressInfo != null) { progressInfo("Adjusting for scale and offset " + tx, .01f); } if (textureEditorMethods != null) { textureEditorMethods.SetReadWriteFlag(tx, true, true); } tx = GetAdjustedForScaleAndOffset2(prop.name, txs.ts[propIdx], txs.obUVoffset, txs.obUVscale, data, combiner); //create a resized copy if necessary if (tx.width != tWidth || tx.height != tHeight) { if (progressInfo != null) { progressInfo("Resizing texture '" + tx + "'", .01f); } Debug.LogWarning("Copying and resizing texture " + prop.name + " from " + tx.width + "x" + tx.height + " to " + tWidth + "x" + tHeight); tx = combiner._resizeTexture(prop.name, (Texture2D)tx, tWidth, tHeight); } estArea += tx.width * tx.height; if (data._considerNonTextureProperties) { //combine the tintColor with the texture tx = combiner._createTextureCopy(prop.name, tx); data.nonTexturePropertyBlender.TintTextureWithTextureCombiner(tx, data.distinctMaterialTextures[texSetIdx], prop); } texToPack[texSetIdx] = tx; } if (textureEditorMethods != null) { textureEditorMethods.CheckBuildSettings(estArea); } if (Math.Sqrt(estArea) > 3500f) { Debug.LogWarning("The maximum possible atlas size is 4096. Textures may be shrunk"); } atlas = new Texture2D(1, 1, TextureFormat.ARGB32, true); if (progressInfo != null) { progressInfo("Packing texture atlas " + prop.name, .25f); } if (propIdx == 0) { if (progressInfo != null) { progressInfo("Estimated min size of atlases: " + Math.Sqrt(estArea).ToString("F0"), .1f); } Debug.Log("Estimated atlas minimum size:" + Math.Sqrt(estArea).ToString("F0")); int maxAtlasSize = 4096; uvRects = atlas.PackTextures(texToPack, data._atlasPadding, maxAtlasSize, false); Debug.Log("After pack textures atlas size " + atlas.width + " " + atlas.height); atlasSizeX = atlas.width; atlasSizeY = atlas.height; atlas.Apply(); } else { if (progressInfo != null) { progressInfo("Copying Textures Into: " + prop.name, .1f); } atlas = _copyTexturesIntoAtlas(texToPack, data._atlasPadding, uvRects, atlasSizeX, atlasSizeY, combiner); } } atlases[propIdx] = atlas; //---------------------- if (data._saveAtlasesAsAssets && textureEditorMethods != null) { textureEditorMethods.SaveAtlasToAssetDatabase(atlases[propIdx], prop, propIdx, data.resultMaterial); } data.resultMaterial.SetTextureOffset(prop.name, Vector2.zero); data.resultMaterial.SetTextureScale(prop.name, Vector2.one); combiner._destroyTemporaryTextures(prop.name); GC.Collect(); } packedAtlasRects.rects = uvRects; yield break; }
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 IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo, TexturePipelineData data, TextureCombineHandler combiner, AtlasPackingResult packedAtlasRects, Texture2D[] atlases, EditorMethodsInterface textureEditorMethods) { Debug.Assert(!data.IsOnlyOneTextureInAtlasReuseTextures()); Rect[] uvRects = packedAtlasRects.rects; int atlasSizeX = packedAtlasRects.atlasX; int atlasSizeY = packedAtlasRects.atlasY; Debug.Log("Generated atlas will be " + atlasSizeX + "x" + atlasSizeY); //create a game object GameObject renderAtlasesGO = null; try { renderAtlasesGO = new GameObject("MBrenderAtlasesGO"); AtlasPackerRenderTexture atlasRenderTexture = renderAtlasesGO.AddComponent <AtlasPackerRenderTexture>(); renderAtlasesGO.AddComponent <Camera>(); if (data._considerNonTextureProperties) { Debug.LogWarning("Blend Non-Texture Properties has limited functionality when used with Mesh Baker Texture Packer Fast."); } for (int propIdx = 0; propIdx < data.numAtlases; propIdx++) { Texture2D atlas = null; if (!TextureCombinerPipeline._ShouldWeCreateAtlasForThisProperty(propIdx, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor)) { atlas = null; Debug.Log("Not creating atlas for " + data.texPropertyNames[propIdx].name + " because textures are null and default value parameters are the same."); } else { GC.Collect(); TextureCombinerPackerBase.CreateTemporaryTexturesForAtlas(data.distinctMaterialTextures, combiner, propIdx, data); if (progressInfo != null) { progressInfo("Creating Atlas '" + data.texPropertyNames[propIdx].name + "'", .01f); } // =========== // configure it Debug.Log("About to render " + data.texPropertyNames[propIdx].name + " isNormal=" + data.texPropertyNames[propIdx].isNormalMap); atlasRenderTexture.width = atlasSizeX; atlasRenderTexture.height = atlasSizeY; atlasRenderTexture.padding = data._atlasPadding; atlasRenderTexture.rects = uvRects; atlasRenderTexture.textureSets = data.distinctMaterialTextures; atlasRenderTexture.indexOfTexSetToRender = propIdx; atlasRenderTexture.texPropertyName = data.texPropertyNames[propIdx]; atlasRenderTexture.isNormalMap = data.texPropertyNames[propIdx].isNormalMap; atlasRenderTexture.fixOutOfBoundsUVs = data._fixOutOfBoundsUVs; atlasRenderTexture.considerNonTextureProperties = data._considerNonTextureProperties; atlasRenderTexture.resultMaterialTextureBlender = data.nonTexturePropertyBlender; // call render on it atlas = atlasRenderTexture.OnRenderAtlas(combiner); // destroy it // ============= Debug.Log("Saving atlas " + data.texPropertyNames[propIdx].name + " w=" + atlas.width + " h=" + atlas.height + " id=" + atlas.GetInstanceID()); } atlases[propIdx] = atlas; if (progressInfo != null) { progressInfo("Saving atlas: '" + data.texPropertyNames[propIdx].name + "'", .04f); } if (data._saveAtlasesAsAssets && textureEditorMethods != null) { textureEditorMethods.SaveAtlasToAssetDatabase(atlases[propIdx], data.texPropertyNames[propIdx], propIdx, data.resultMaterial); } else { data.resultMaterial.SetTexture(data.texPropertyNames[propIdx].name, atlases[propIdx]); } data.resultMaterial.SetTextureOffset(data.texPropertyNames[propIdx].name, Vector2.zero); data.resultMaterial.SetTextureScale(data.texPropertyNames[propIdx].name, Vector2.one); combiner._destroyTemporaryTextures(data.texPropertyNames[propIdx].name); // need to save atlases before doing this } } catch (Exception ex) { //Debug.LogError(ex); Debug.LogException(ex); } finally { if (renderAtlasesGO != null) { MeshBakerUtility.Destroy(renderAtlasesGO); } } yield break; }
public virtual AtlasPackingResult[] CalculateAtlasRectangles(TexturePipelineData data, bool doMultiAtlas) { Debug.Assert(!data.IsOnlyOneTextureInAtlasReuseTextures()); return(TextureCombinerPackerBase.CalculateAtlasRectanglesStatic(data, doMultiAtlas)); }