IEnumerator _CombineTexturesIntoAtlases(ProgressUpdateDelegate progressInfo, CombineTexturesIntoAtlasesCoroutineResult result, MB_AtlasesAndRects resultAtlasesAndRects, Material resultMaterial, List <GameObject> objsToMesh, List <Material> allowedMaterialsFilter, MB2_EditorMethodsInterface textureEditorMethods, List <AtlasPackingResult> atlasPackingResult, bool onlyPackRects, bool splitAtlasWhenPackingIfTooBig) { System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); sw.Start(); try { _temporaryTextures.Clear(); MeshBakerMaterialTexture.readyToBuildAtlases = false; if (textureEditorMethods != null) { textureEditorMethods.Clear(); textureEditorMethods.OnPreTextureBake(); } if (objsToMesh == null || objsToMesh.Count == 0) { Debug.LogError("No meshes to combine. Please assign some meshes to combine."); result.success = false; yield break; } if (_atlasPadding < 0) { Debug.LogError("Atlas padding must be zero or greater."); result.success = false; yield break; } if (_maxTilingBakeSize < 2 || _maxTilingBakeSize > 4096) { Debug.LogError("Invalid value for max tiling bake size."); result.success = false; yield break; } for (int i = 0; i < objsToMesh.Count; i++) { Material[] ms = MB_Utility.GetGOMaterials(objsToMesh[i]); for (int j = 0; j < ms.Length; j++) { Material m = ms[j]; if (m == null) { Debug.LogError("Game object " + objsToMesh[i] + " has a null material"); result.success = false; yield break; } } } if (progressInfo != null) { progressInfo("Collecting textures for " + objsToMesh.Count + " meshes.", .01f); } MB3_TextureCombinerPipeline.TexturePipelineData data = LoadPipelineData(resultMaterial, new List <ShaderTextureProperty>(), objsToMesh, allowedMaterialsFilter, new List <MB_TexSet>()); if (!MB3_TextureCombinerPipeline._CollectPropertyNames(data, LOG_LEVEL)) { result.success = false; yield break; } if (_fixOutOfBoundsUVs && (_packingAlgorithm == MB2_PackingAlgorithmEnum.MeshBakerTexturePacker_Horizontal || _packingAlgorithm == MB2_PackingAlgorithmEnum.MeshBakerTexturePacker_Vertical)) { if (LOG_LEVEL >= MB2_LogLevel.info) { Debug.LogWarning("'Consider Mesh UVs' is enabled but packing algorithm is MeshBakerTexturePacker_Horizontal or MeshBakerTexturePacker_Vertical. It is recommended to use these packers without using 'Consider Mesh UVs'"); } } data.nonTexturePropertyBlender.LoadTextureBlendersIfNeeded(data.resultMaterial); if (onlyPackRects) { yield return(__RunTexturePackerOnly(result, data, splitAtlasWhenPackingIfTooBig, textureEditorMethods, atlasPackingResult)); } else { yield return(__CombineTexturesIntoAtlases(progressInfo, result, resultAtlasesAndRects, data, splitAtlasWhenPackingIfTooBig, textureEditorMethods)); } /* * } catch (MissingReferenceException mrex){ * Debug.LogError("Creating atlases failed a MissingReferenceException was thrown. This is normally only happens when trying to create very large atlases and Unity is running out of Memory. Try changing the 'Texture Packer' to a different option, it may work with an alternate packer. This error is sometimes intermittant. Try baking again."); * Debug.LogError(mrex); * } catch (Exception ex){ * Debug.LogError(ex);*/ } finally { _destroyAllTemporaryTextures(); _restoreProceduralMaterials(); if (textureEditorMethods != null) { textureEditorMethods.RestoreReadFlagsAndFormats(progressInfo); textureEditorMethods.OnPostTextureBake(); } if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("===== Done creating atlases for " + resultMaterial + " Total time to create atlases " + sw.Elapsed.ToString()); } } //result.success = success; }
bool _combineTexturesIntoAtlases(ProgressUpdateDelegate progressInfo, MB_AtlasesAndRects resultAtlasesAndRects, Material resultMaterial, List<GameObject> objsToMesh, List<Material> allowedMaterialsFilter, MB2_EditorMethodsInterface textureEditorMethods){ bool success = false; try{ _temporaryTextures.Clear(); if (textureEditorMethods != null) textureEditorMethods.Clear(); if (objsToMesh == null || objsToMesh.Count == 0){ Debug.LogError("No meshes to combine. Please assign some meshes to combine."); return false; } if (atlasPadding < 0){ Debug.LogError("Atlas padding must be zero or greater."); return false; } if (maxTilingBakeSize < 2 || maxTilingBakeSize > 4096){ Debug.LogError("Invalid value for max tiling bake size."); return false; } if (progressInfo != null) progressInfo("Collecting textures for " + objsToMesh.Count + " meshes.", .01f); List<string> texPropertyNames = new List<string>(); if (!_collectPropertyNames(resultMaterial, texPropertyNames)){ return false; } success = __combineTexturesIntoAtlases(progressInfo,resultAtlasesAndRects, resultMaterial, texPropertyNames, objsToMesh,allowedMaterialsFilter, textureEditorMethods); } catch (MissingReferenceException mrex){ Debug.LogError("Creating atlases failed a MissingReferenceException was thrown. This is normally only happens when trying to create very large atlases and Unity is running out of Memory. Try changing the 'Texture Packer' to a different option, it may work with an alternate packer. This error is sometimes intermittant. Try baking again."); Debug.LogError(mrex); } catch (Exception ex){ Debug.LogError(ex); } finally { _destroyTemporaryTextures(); if (textureEditorMethods != null) textureEditorMethods.SetReadFlags(progressInfo); } return success; }
public static IEnumerator _CreateAtlasesCoroutineSingleResultMaterial(int resMatIdx, MB_TextureArrayResultMaterial bakedMatsAndSlicesResMat, MB_MultiMaterialTexArray resMatConfig, List <GameObject> objsToMesh, MB3_TextureCombiner combiner, MB_TextureArrayFormatSet[] textureArrayOutputFormats, MB_MultiMaterialTexArray[] resultMaterialsTexArray, List <ShaderTextureProperty> customShaderProperties, ProgressUpdateDelegate progressInfo, MB3_TextureCombiner.CreateAtlasesCoroutineResult coroutineResult, bool saveAtlasesAsAssets = false, MB2_EditorMethodsInterface editorMethods = null, float maxTimePerFrame = .01f) { MB2_LogLevel LOG_LEVEL = combiner.LOG_LEVEL; if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("Baking atlases for result material " + resMatIdx + " num slices:" + resMatConfig.slices.Count); } // Each result material can be one set of slices per textureProperty. Each slice can be an atlas. // Create atlases for each slice. List <MB3_TextureCombiner.TemporaryTexture> generatedTemporaryAtlases = new List <MB3_TextureCombiner.TemporaryTexture>(); { combiner.saveAtlasesAsAssets = false; // Don't want generated atlas slices to be assets List <MB_TexArraySlice> slicesConfig = resMatConfig.slices; for (int sliceIdx = 0; sliceIdx < slicesConfig.Count; sliceIdx++) { Material resMatToPass = null; List <MB_TexArraySliceRendererMatPair> srcMatAndObjPairs = slicesConfig[sliceIdx].sourceMaterials; if (LOG_LEVEL >= MB2_LogLevel.trace) { Debug.Log(" Baking atlases for result material:" + resMatIdx + " slice:" + sliceIdx); } resMatToPass = resMatConfig.combinedMaterial; combiner.fixOutOfBoundsUVs = slicesConfig[sliceIdx].considerMeshUVs; MB3_TextureCombiner.CombineTexturesIntoAtlasesCoroutineResult coroutineResult2 = new MB3_TextureCombiner.CombineTexturesIntoAtlasesCoroutineResult(); MB_AtlasesAndRects sliceAtlasesAndRectOutput = bakedMatsAndSlicesResMat.slices[sliceIdx]; List <Material> usedMats = new List <Material>(); slicesConfig[sliceIdx].GetAllUsedMaterials(usedMats); yield return(combiner.CombineTexturesIntoAtlasesCoroutine(progressInfo, sliceAtlasesAndRectOutput, resMatToPass, slicesConfig[sliceIdx].GetAllUsedRenderers(objsToMesh), usedMats, editorMethods, coroutineResult2, maxTimePerFrame, onlyPackRects: false, splitAtlasWhenPackingIfTooBig: false)); coroutineResult.success = coroutineResult2.success; if (!coroutineResult.success) { coroutineResult.isFinished = true; yield break; } // Track which slices are new generated texture instances. Atlases could be original texture assets (one tex per atlas) or temporary texture instances in memory that will need to be destroyed. { for (int texPropIdx = 0; texPropIdx < sliceAtlasesAndRectOutput.atlases.Length; texPropIdx++) { Texture2D atlas = sliceAtlasesAndRectOutput.atlases[texPropIdx]; if (atlas != null) { bool atlasWasASourceTexture = false; for (int srcMatIdx = 0; srcMatIdx < srcMatAndObjPairs.Count; srcMatIdx++) { Material srcMat = srcMatAndObjPairs[srcMatIdx].sourceMaterial; if (srcMat.HasProperty(sliceAtlasesAndRectOutput.texPropertyNames[texPropIdx]) && srcMat.GetTexture(sliceAtlasesAndRectOutput.texPropertyNames[texPropIdx]) == atlas) { atlasWasASourceTexture = true; break; } } if (!atlasWasASourceTexture) { generatedTemporaryAtlases.Add(new MB3_TextureCombiner.TemporaryTexture(sliceAtlasesAndRectOutput.texPropertyNames[texPropIdx], atlas)); } } } } // end visit slices Debug.Assert(combiner._getNumTemporaryTextures() == 0, "Combiner should have no temporary textures."); } combiner.saveAtlasesAsAssets = saveAtlasesAsAssets; // Restore original setting. } // Generated atlas textures are temporary for texture arrays. They exist only in memory. Need to be cleaned up after we create slices. for (int i = 0; i < generatedTemporaryAtlases.Count; i++) { combiner.AddTemporaryTexture(generatedTemporaryAtlases[i]); } List <ShaderTextureProperty> texPropertyNames = new List <ShaderTextureProperty>(); MB3_TextureCombinerPipeline._CollectPropertyNames(texPropertyNames, customShaderProperties, resMatConfig.combinedMaterial, LOG_LEVEL); // The slices are built from different source-material-lists. Each slice can have different sets of texture properties missing (nulls). // Build a master list of texture properties. bool[] hasTexForProperty = MB_TextureArrays.DetermineWhichPropertiesHaveTextures(bakedMatsAndSlicesResMat.slices); List <Texture2D> temporaryTextureAssets = new List <Texture2D>(); try { MB_MultiMaterialTexArray resMaterial = resMatConfig; Dictionary <string, MB_TexArrayForProperty> resTexArraysByProperty = new Dictionary <string, MB_TexArrayForProperty>(); { // Initialize so I don't need to check if properties exist later. for (int propIdx = 0; propIdx < texPropertyNames.Count; propIdx++) { if (hasTexForProperty[propIdx]) { resTexArraysByProperty[texPropertyNames[propIdx].name] = new MB_TexArrayForProperty(texPropertyNames[propIdx].name, new MB_TextureArrayReference[textureArrayOutputFormats.Length]); } } } MB3_TextureCombinerNonTextureProperties textureBlender = null; textureBlender = new MB3_TextureCombinerNonTextureProperties(LOG_LEVEL, combiner.considerNonTextureProperties); textureBlender.LoadTextureBlendersIfNeeded(resMatConfig.combinedMaterial); textureBlender.AdjustNonTextureProperties(resMatConfig.combinedMaterial, texPropertyNames, editorMethods); // Vist each TextureFormatSet for (int texFormatSetIdx = 0; texFormatSetIdx < textureArrayOutputFormats.Length; texFormatSetIdx++) { MB_TextureArrayFormatSet textureArrayFormatSet = textureArrayOutputFormats[texFormatSetIdx]; editorMethods.Clear(); MB_TextureArrays.TexturePropertyData texPropertyData = new MB_TextureArrays.TexturePropertyData(); MB_TextureArrays.FindBestSizeAndMipCountAndFormatForTextureArrays(texPropertyNames, combiner.maxAtlasSize, textureArrayFormatSet, bakedMatsAndSlicesResMat.slices, texPropertyData); // Create textures we might need to create if they don't exist. { for (int propIdx = 0; propIdx < hasTexForProperty.Length; propIdx++) { if (hasTexForProperty[propIdx]) { TextureFormat format = texPropertyData.formats[propIdx]; int numSlices = bakedMatsAndSlicesResMat.slices.Length; int targetWidth = (int)texPropertyData.sizes[propIdx].x; int targetHeight = (int)texPropertyData.sizes[propIdx].y; for (int sliceIdx = 0; sliceIdx < numSlices; sliceIdx++) { if (bakedMatsAndSlicesResMat.slices[sliceIdx].atlases[propIdx] == null) { // Can only setSolidColor on truecolor textures. First create a texture in trucolor format Texture2D sliceTex = new Texture2D(targetWidth, targetHeight, TextureFormat.ARGB32, texPropertyData.doMips[propIdx]); Color col = textureBlender.GetColorForTemporaryTexture(resMatConfig.slices[sliceIdx].sourceMaterials[0].sourceMaterial, texPropertyNames[propIdx]); MB_Utility.setSolidColor(sliceTex, col); // Now create a copy of this texture in target format. bakedMatsAndSlicesResMat.slices[sliceIdx].atlases[propIdx] = editorMethods.CreateTemporaryAssetCopy(texPropertyNames[propIdx], sliceTex, targetWidth, targetHeight, format, LOG_LEVEL); temporaryTextureAssets.Add(bakedMatsAndSlicesResMat.slices[sliceIdx].atlases[propIdx]); MB_Utility.Destroy(sliceTex); } } } } } if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("Converting source textures to readable formats."); } if (MB_TextureArrays.ConvertTexturesToReadableFormat(texPropertyData, bakedMatsAndSlicesResMat.slices, hasTexForProperty, texPropertyNames, combiner, LOG_LEVEL, temporaryTextureAssets, editorMethods)) { // We now have a set of slices (one per textureProperty). Build these into Texture2DArray's. if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("Creating texture arrays"); } if (LOG_LEVEL >= MB2_LogLevel.info) { Debug.Log("THERE MAY BE ERRORS IN THE CONSOLE ABOUT 'Rebuilding mipmaps ... not supported'. THESE ARE PROBABLY FALSE POSITIVES AND CAN BE IGNORED."); } Texture2DArray[] textureArrays = MB_TextureArrays.CreateTextureArraysForResultMaterial(texPropertyData, texPropertyNames, bakedMatsAndSlicesResMat.slices, hasTexForProperty, combiner, LOG_LEVEL); // Now have texture arrays for a result material, for all props. Save it. for (int propIdx = 0; propIdx < textureArrays.Length; propIdx++) { if (hasTexForProperty[propIdx]) { MB_TextureArrayReference texRef = new MB_TextureArrayReference(textureArrayFormatSet.name, textureArrays[propIdx]); resTexArraysByProperty[texPropertyNames[propIdx].name].formats[texFormatSetIdx] = texRef; if (saveAtlasesAsAssets) { editorMethods.SaveTextureArrayToAssetDatabase(textureArrays[propIdx], textureArrayFormatSet.GetFormatForProperty(texPropertyNames[propIdx].name), bakedMatsAndSlicesResMat.slices[0].texPropertyNames[propIdx], propIdx, resMaterial.combinedMaterial); } } } } } // end vist format set resMaterial.textureProperties = new List <MB_TexArrayForProperty>(); foreach (MB_TexArrayForProperty val in resTexArraysByProperty.Values) { resMaterial.textureProperties.Add(val); } } catch (Exception e) { Debug.LogError(e.Message + "\n" + e.StackTrace.ToString()); coroutineResult.isFinished = true; coroutineResult.success = false; } finally { editorMethods.RestoreReadFlagsAndFormats(progressInfo); combiner._destroyAllTemporaryTextures(); for (int i = 0; i < temporaryTextureAssets.Count; i++) { editorMethods.DestroyAsset(temporaryTextureAssets[i]); } temporaryTextureAssets.Clear(); } }