//float _maxTimePerFrameForCoroutine; public IEnumerator CombineTexturesIntoAtlasesCoroutine(ProgressUpdateDelegate progressInfo, AtlasesAndRects resultAtlasesAndRects, Material resultMaterial, List <GameObject> objsToMesh, List <Material> allowedMaterialsFilter, EditorMethodsInterface textureEditorMethods = null, CombineTexturesIntoAtlasesCoroutineResult coroutineResult = null, float maxTimePerFrame = .01f, List <AtlasPackingResult> packingResults = null, bool onlyPackRects = false, bool splitAtlasWhenPackingIfTooBig = false) { coroutineResult.success = true; coroutineResult.isFinished = false; if (maxTimePerFrame <= 0f) { Debug.LogError("maxTimePerFrame must be a value greater than zero"); coroutineResult.isFinished = true; yield break; } //_maxTimePerFrameForCoroutine = maxTimePerFrame; yield return(_CombineTexturesIntoAtlases(progressInfo, coroutineResult, resultAtlasesAndRects, resultMaterial, objsToMesh, allowedMaterialsFilter, textureEditorMethods, packingResults, onlyPackRects, splitAtlasWhenPackingIfTooBig)); coroutineResult.isFinished = true; yield break; }
/// <summary> /// 合并贴图形成纹理图集 /// </summary> public bool CombineTexturesIntoAtlases(ProgressUpdateDelegate progressInfo, AtlasesAndRects resultAtlasesAndRects, Material resultMaterial, List <GameObject> objsToMesh, List <Material> allowedMaterialsFilter, EditorMethodsInterface textureEditorMethods = null, List <AtlasPackingResult> packingResults = null, bool onlyPackRects = false, bool splitAtlasWhenPackingIfTooBig = false) { CombineTexturesIntoAtlasesCoroutineResult result = new CombineTexturesIntoAtlasesCoroutineResult(); RunCorutineWithoutPause( _CombineTexturesIntoAtlases( progressInfo, result, resultAtlasesAndRects, resultMaterial, objsToMesh, allowedMaterialsFilter, textureEditorMethods, packingResults, onlyPackRects, splitAtlasWhenPackingIfTooBig ), 0); if (result.success == false) { Debug.LogError("Failed to generate atlases."); } return(result.success); }
// 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)); }
/// <summary> /// Creates the atlases.创建图集 /// saveAtlasesAsAssets 创建图集并保存至项目资源目录,或者内存中 /// editorMethods 贴图格式编辑器方法 /// </summary> public AtlasesAndRects[] CreateAtlases(ProgressUpdateDelegate progressInfo, bool saveAtlasesAsAssets = false, EditorMethodsInterface editorMethods = null) { AtlasesAndRects[] resultAtlasesAndRects = null; try { _coroutineResult = new CreateAtlasesCoroutineResult(); TextureCombineHandler.RunCorutineWithoutPause( CreateAtlasesCoroutine(progressInfo, _coroutineResult, saveAtlasesAsAssets, editorMethods, 1000f), 0); if (_coroutineResult.success && textureBakeResults != null) { resultAtlasesAndRects = this.OnCombinedTexturesCoroutineAtlasesAndRects; } } catch (Exception e) { Debug.LogError(e); } finally { if (saveAtlasesAsAssets) { //Atlases were saved to project so we don't need these ones if (resultAtlasesAndRects != null) { for (int j = 0; j < resultAtlasesAndRects.Length; j++) { AtlasesAndRects mAndA = resultAtlasesAndRects[j]; if (mAndA != null && mAndA.atlases != null) { for (int i = 0; i < mAndA.atlases.Length; i++) { if (mAndA.atlases[i] != null) { if (editorMethods != null) { editorMethods.Destroy(mAndA.atlases[i]); } else { MeshBakerUtility.Destroy(mAndA.atlases[i]); } } } } } } } } return(resultAtlasesAndRects); }
void unpackMat2RectMap(TextureBakeResults tbr) { List <Material> ms = new List <Material>(); List <MaterialAndUVRect> mss = new List <MaterialAndUVRect>(); List <Rect> rs = new List <Rect>(); for (int i = 0; i < OnCombinedTexturesCoroutineAtlasesAndRects.Length; i++) { AtlasesAndRects newMesh = OnCombinedTexturesCoroutineAtlasesAndRects[i]; List <MaterialAndUVRect> map = newMesh.originMatToRect_map; if (map != null) { for (int j = 0; j < map.Count; j++) { mss.Add(map[j]); ms.Add(map[j].material); rs.Add(map[j].atlasRect); } } } //tbr.version = MB2_TextureBakeResults.VERSION; tbr.materialsAndUVRects = mss.ToArray(); }
IEnumerator _CombineTexturesIntoAtlases(ProgressUpdateDelegate progressInfo, CombineTexturesIntoAtlasesCoroutineResult result, AtlasesAndRects resultAtlasesAndRects, Material resultMaterial, List <GameObject> objsToMesh, List <Material> allowedMaterialsFilter, EditorMethodsInterface textureEditorMethods, List <AtlasPackingResult> atlasPackingResult, bool onlyPackRects, bool splitAtlasWhenPackingIfTooBig) { try { _temporaryTextures.Clear(); MaterialPropTexture.readyToBuildAtlases = false; // ---- 0.合并材质前回调 if (textureEditorMethods != null) { textureEditorMethods.Clear(); textureEditorMethods.OnPreTextureBake(); } // ---- 1.合并材质参数校验 if (objsToMesh == null || objsToMesh.Count == 0) { Debug.LogError("没有游戏物体参与合并"); result.success = false; yield break; } if (_atlasPadding < 0) { Debug.LogError("Atlas padding 必须大于等于零"); result.success = false; yield break; } if (_maxTilingBakeSize < 2 || _maxTilingBakeSize > 4096) { Debug.LogError("无效Tilling尺寸的值Invalid value for max tiling bake size."); result.success = false; yield break; } for (int i = 0; i < objsToMesh.Count; i++) { Material[] ms = MeshBakerUtility.GetGOMaterials(objsToMesh[i]); for (int j = 0; j < ms.Length; j++) { Material m = ms[j]; if (m == null) { Debug.LogError("游戏物体" + objsToMesh[i] + " 材质为空 "); result.success = false; yield break; } } } if (_fixOutOfBoundsUVs && (_packingAlgorithm == PackingAlgorithmEnum.MeshBakerTexturePacker_Horizontal || _packingAlgorithm == PackingAlgorithmEnum.MeshBakerTexturePacker_Vertical)) { Debug.LogWarning("合并算法为 MeshBakerTexturePacker_Horizontal 或 MeshBakerTexturePacker_Vertical,建议不打开 Consider Mesh UVs 选项"); } if (progressInfo != null) { progressInfo("Collecting textures for " + objsToMesh.Count + " meshes.", .01f); } // ---- 2.创建材质合并管线数据 TexturePipelineData data = CreatePipelineData(resultMaterial, new List <ShaderTextureProperty>(), objsToMesh, allowedMaterialsFilter, new List <MaterialPropTexturesSet>()); // ---- 3.将材质的 shader 各参数信息写入管线数据中 if (!TextureCombinerPipeline._CollectPropertyNames(data)) { result.success = false; yield break; } // ---- 4.加载 Texture 混合器 data.nonTexturePropertyBlender.LoadTextureBlendersIfNeeded(data.resultMaterial); // ---- 5.选择本地合并,或运行时合并 if (onlyPackRects) { yield return(__RunTexturePackerOnly(result, data, splitAtlasWhenPackingIfTooBig, textureEditorMethods, atlasPackingResult)); } else { yield return(__CombineTexturesIntoAtlases(progressInfo, result, resultAtlasesAndRects, data, splitAtlasWhenPackingIfTooBig, textureEditorMethods)); } } finally { // ---- 6.删除缓存,合并材质完成回调 _destroyAllTemporaryTextures(); if (textureEditorMethods != null) { textureEditorMethods.RestoreReadFlagsAndFormats(progressInfo); textureEditorMethods.OnPostTextureBake(); } } }
/// <summary> /// Texture 合并管线第 3 步,创建 Atlas 并保存资源 /// </summary> /// <returns></returns> internal static IEnumerator __Step3_BuildAndSaveAtlasesAndStoreResults(ProgressUpdateDelegate progressInfo, CombineTexturesIntoAtlasesCoroutineResult result, TexturePipelineData data, TextureCombineHandler combiner, ITextureCombinerPacker packer, AtlasPackingResult atlasPackingResult, EditorMethodsInterface textureEditorMethods, AtlasesAndRects resultAtlasesAndRects) { //run the garbage collector to free up as much memory as possible before bake to reduce MissingReferenceException problems GC.Collect(); Texture2D[] atlases = new Texture2D[data.numAtlases]; //StringBuilder report = GenerateReport(data); //创建图集 yield return(packer.CreateAtlases(progressInfo, data, combiner, atlasPackingResult, atlases, textureEditorMethods)); data.nonTexturePropertyBlender.AdjustNonTextureProperties(data.resultMaterial, data.texPropertyNames, data.distinctMaterialTextures, textureEditorMethods); if (data.distinctMaterialTextures.Count > 0) { data.distinctMaterialTextures[0].AdjustResultMaterialNonTextureProperties(data.resultMaterial, data.texPropertyNames); } //结果报告 //if (progressInfo != null) // progressInfo("Building Report", .7f); ////report on atlases created //StringBuilder atlasMessage = new StringBuilder(); //atlasMessage.AppendLine("---- Atlases ------"); //for (int i = 0; i < data.numAtlases; i++) //{ // if (atlases[i] != null) // { // atlasMessage.AppendLine("Created Atlas For: " + data.texPropertyNames[i].name + " h=" + atlases[i].height + " w=" + atlases[i].width); // } // else if (!_ShouldWeCreateAtlasForThisProperty(i, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor)) // { // atlasMessage.AppendLine("Did not create atlas for " + data.texPropertyNames[i].name + " because all source textures were null."); // } //} //report.Append(atlasMessage.ToString()); List <MaterialAndUVRect> mat2rect_map = new List <MaterialAndUVRect>(); for (int i = 0; i < data.distinctMaterialTextures.Count; i++) { MaterialPropTexturesSet texSet = data.distinctMaterialTextures[i]; List <MatAndTransformToMerged> mats = texSet.matsAndGOs.mats; Rect allPropsUseSameTiling_encapsulatingSamplingRect; Rect propsUseDifferntTiling_obUVRect; texSet.GetRectsForTextureBakeResults(out allPropsUseSameTiling_encapsulatingSamplingRect, out propsUseDifferntTiling_obUVRect); for (int j = 0; j < mats.Count; j++) { Rect allPropsUseSameTiling_sourceMaterialTiling = texSet.GetMaterialTilingRectForTextureBakerResults(j); MaterialAndUVRect key = new MaterialAndUVRect( mats[j].mat, atlasPackingResult.rects[i], texSet.allTexturesUseSameMatTiling, allPropsUseSameTiling_sourceMaterialTiling, allPropsUseSameTiling_encapsulatingSamplingRect, propsUseDifferntTiling_obUVRect, texSet.tilingTreatment, mats[j].objName); if (!mat2rect_map.Contains(key)) { mat2rect_map.Add(key); } } } resultAtlasesAndRects.atlases = atlases; // one per texture on result shader resultAtlasesAndRects.texPropertyNames = ShaderTextureProperty.GetNames(data.texPropertyNames); // one per texture on source shader resultAtlasesAndRects.originMatToRect_map = mat2rect_map; if (progressInfo != null) { progressInfo("Restoring Texture Formats & Read Flags", .8f); } combiner._destroyAllTemporaryTextures(); if (textureEditorMethods != null) { textureEditorMethods.RestoreReadFlagsAndFormats(progressInfo); } //if (report != null) // Debug.Log(report.ToString()); yield break; }
/// <summary> /// 创建贴图 Atlas 协程 /// </summary> /// <returns></returns> public IEnumerator CreateAtlasesCoroutine(ProgressUpdateDelegate progressInfo, CreateAtlasesCoroutineResult coroutineResult, bool saveAtlasesAsAssets = false, EditorMethodsInterface editorMethods = null, float maxTimePerFrame = .01f) { OnCombinedTexturesCoroutineAtlasesAndRects = null; //--- 1、合并前检测 if (maxTimePerFrame <= 0f) { Debug.LogError("maxTimePerFrame must be a value greater than zero"); coroutineResult.isFinished = true; yield break; } //验证等级 ValidationLevel vl = Application.isPlaying ? ValidationLevel.quick : ValidationLevel.robust; //验证 if (!DoCombinedValidate(this, ObjsToCombineTypes.dontCare, null, vl)) { coroutineResult.isFinished = true; yield break; } //合并为多材质验证 if (_doMultiMaterial && !_ValidateResultMaterials()) { coroutineResult.isFinished = true; yield break; } else if (!_doMultiMaterial) { //合并为单独材质 if (_resultMaterial == null) { Debug.LogError("Combined Material is null please create and assign a result material."); coroutineResult.isFinished = true; yield break; } Shader targShader = _resultMaterial.shader; for (int i = 0; i < objsToMesh.Count; i++) { Material[] ms = MeshBakerUtility.GetGOMaterials(objsToMesh[i]); for (int j = 0; j < ms.Length; j++) { Material m = ms[j]; if (m != null && m.shader != targShader) { Debug.LogWarning("游戏物体" + objsToMesh[i] + " 没有使用 shader " + targShader + " it may not have the required textures. " + "If not small solid color textures will be generated."); } } } } TextureCombineHandler combiner = CreateAndConfigureTextureCombiner(); combiner.saveAtlasesAsAssets = saveAtlasesAsAssets; ////--- 2、初始化存储合并结果的数据结构 int numResults = 1; if (_doMultiMaterial) { numResults = resultMaterials.Length; } OnCombinedTexturesCoroutineAtlasesAndRects = new AtlasesAndRects[numResults]; for (int i = 0; i < OnCombinedTexturesCoroutineAtlasesAndRects.Length; i++) { OnCombinedTexturesCoroutineAtlasesAndRects[i] = new AtlasesAndRects(); } //--- 3、开始合并材质(单个,多个) for (int i = 0; i < OnCombinedTexturesCoroutineAtlasesAndRects.Length; i++) { Material resMatToPass; List <Material> sourceMats; if (_doMultiMaterial) { sourceMats = resultMaterials[i].sourceMaterials; resMatToPass = resultMaterials[i].combinedMaterial; combiner.fixOutOfBoundsUVs = resultMaterials[i].considerMeshUVs; } else { resMatToPass = _resultMaterial; sourceMats = null; } //TextureHandler 材质合并协程结果 CombineTexturesIntoAtlasesCoroutineResult coroutineResult2 = new CombineTexturesIntoAtlasesCoroutineResult(); yield return(combiner.CombineTexturesIntoAtlasesCoroutine(progressInfo, OnCombinedTexturesCoroutineAtlasesAndRects[i], resMatToPass, objsToMesh, sourceMats, editorMethods, coroutineResult2, maxTimePerFrame)); coroutineResult.success = coroutineResult2.success; if (!coroutineResult.success) { coroutineResult.isFinished = true; yield break; } } //--- 4、TextureBakeResults 保存合并结果 unpackMat2RectMap(textureBakeResults); textureBakeResults.doMultiMaterial = _doMultiMaterial; if (_doMultiMaterial) { textureBakeResults.resultMaterials = resultMaterials; } else { MultiMaterial[] resMats = new MultiMaterial[1]; resMats[0] = new MultiMaterial(); resMats[0].combinedMaterial = _resultMaterial; resMats[0].considerMeshUVs = _fixOutOfBoundsUVs; resMats[0].sourceMaterials = new List <Material>(); for (int i = 0; i < textureBakeResults.materialsAndUVRects.Length; i++) { resMats[0].sourceMaterials.Add(textureBakeResults.materialsAndUVRects[i].material); } textureBakeResults.resultMaterials = resMats; } //--- 5、传递合并结果到 MeshCombiner MeshBakerCommon[] mb = GetComponentsInChildren <MeshBakerCommon>(); for (int i = 0; i < mb.Length; i++) { mb[i].textureBakeResults = textureBakeResults; } coroutineResult.isFinished = true; //--- 6、合并材质结束回调 if (coroutineResult.success && onBuiltAtlasesSuccess != null) { onBuiltAtlasesSuccess(); } if (!coroutineResult.success && onBuiltAtlasesFail != null) { onBuiltAtlasesFail(); } }