public Texture2D DoRenderAtlas(GameObject gameObject, int width, int height, int padding, Rect[] rss, List<MB3_TextureCombiner.MB_TexSet> textureSetss, int indexOfTexSetToRenders, bool isNormalMap, bool fixOutOfBoundsUVs, MB3_TextureCombiner texCombiner, MB2_LogLevel LOG_LEV) { this.LOG_LEVEL = LOG_LEV; this.textureSets = textureSetss; this.indexOfTexSetToRender = indexOfTexSetToRenders; this._padding = padding; this._isNormalMap = isNormalMap; this._fixOutOfBoundsUVs = fixOutOfBoundsUVs; this.combiner = texCombiner; this.rs = rss; Shader shader; if (this._isNormalMap) { shader = Shader.Find("MeshBaker/NormalMapShader"); } else { shader = Shader.Find("MeshBaker/AlbedoShader"); } if (shader == null) { UnityEngine.Debug.LogError("Could not find shader for RenderTexture. Try reimporting mesh baker"); return null; } this.mat = new Material(shader); this._destinationTexture = new RenderTexture(width, height, 24, RenderTextureFormat.ARGB32); this._destinationTexture.filterMode = FilterMode.Point; this.myCamera = gameObject.GetComponent<Camera>(); this.myCamera.orthographic = true; this.myCamera.orthographicSize = (float)(height >> 1); this.myCamera.aspect = (float)(width / height); this.myCamera.targetTexture = this._destinationTexture; this.myCamera.clearFlags = CameraClearFlags.Color; Transform component = this.myCamera.GetComponent<Transform>(); component.localPosition = new Vector3((float)width / 2f, (float)height / 2f, 3f); component.localRotation = Quaternion.Euler(0f, 180f, 180f); this._doRenderAtlas = true; if (this.LOG_LEVEL >= MB2_LogLevel.debug) { UnityEngine.Debug.Log(string.Format("Begin Camera.Render destTex w={0} h={1} camPos={2}", width, height, component.localPosition)); } this.myCamera.Render(); this._doRenderAtlas = false; MB_Utility.Destroy(this.mat); MB_Utility.Destroy(this._destinationTexture); if (this.LOG_LEVEL >= MB2_LogLevel.debug) { UnityEngine.Debug.Log("Finished Camera.Render "); } Texture2D result = this.targTex; this.targTex = null; return result; }
public Texture2D DoRenderAtlas(GameObject gameObject, int width, int height, int padding, Rect[] rss, List<MB3_TextureCombiner.MB_TexSet> textureSetss, int indexOfTexSetToRenders, bool isNormalMap, bool fixOutOfBoundsUVs, MB3_TextureCombiner texCombiner, MB2_LogLevel LOG_LEV){ LOG_LEVEL = LOG_LEV; textureSets = textureSetss; indexOfTexSetToRender = indexOfTexSetToRenders; _padding = padding; _isNormalMap = isNormalMap; _fixOutOfBoundsUVs = fixOutOfBoundsUVs; combiner = texCombiner; rs = rss; Shader s; if (_isNormalMap){ s = Shader.Find ("MeshBaker/NormalMapShader"); } else { s = Shader.Find ("MeshBaker/AlbedoShader"); } if (s == null){ Debug.LogError ("Could not find shader for RenderTexture. Try reimporting mesh baker"); return null; } mat = new Material(s); _destinationTexture = new RenderTexture(width,height,24,RenderTextureFormat.ARGB32); _destinationTexture.filterMode = FilterMode.Point; myCamera = gameObject.GetComponent<Camera>(); myCamera.orthographic = true; myCamera.orthographicSize = height >> 1; myCamera.aspect = width / height; myCamera.targetTexture = _destinationTexture; myCamera.clearFlags = CameraClearFlags.Color; Transform camTransform = myCamera.GetComponent<Transform>(); camTransform.localPosition = new Vector3(width/2.0f, height/2f, 3); camTransform.localRotation = Quaternion.Euler(0, 180, 180); _doRenderAtlas = true; if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log(string.Format ("Begin Camera.Render destTex w={0} h={1} camPos={2}", width, height, camTransform.localPosition)); //This triggers the OnRenderObject callback myCamera.Render(); _doRenderAtlas = false; MB_Utility.Destroy(mat); MB_Utility.Destroy(_destinationTexture); if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log ("Finished Camera.Render "); Texture2D tempTex = targTex; targTex = null; return tempTex; }
public IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo, MB3_TextureCombinerPipeline.TexturePipelineData data, MB3_TextureCombiner combiner, AtlasPackingResult packedAtlasRects, Texture2D[] atlases, MB2_EditorMethodsInterface textureEditorMethods, MB2_LogLevel LOG_LEVEL) { Debug.Assert(data.OnlyOneTextureInAtlasReuseTextures()); if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Only one image per atlas. Will re-use original texture"); for (int i = 0; i < data.numAtlases; i++) { MeshBakerMaterialTexture dmt = data.distinctMaterialTextures[0].ts[i]; atlases[i] = dmt.GetTexture2D(); if (data.resultType == MB2_TextureBakeResults.ResultType.atlas) { 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; }
public static void MakeProceduralTexturesReadable(ProgressUpdateDelegate progressInfo, MB3_TextureCombiner.CombineTexturesIntoAtlasesCoroutineResult result, MB3_TextureCombinerPipeline.TexturePipelineData data, MB3_TextureCombiner combiner, MB2_EditorMethodsInterface textureEditorMethods, MB2_LogLevel LOG_LEVEL) { Debug.LogError("TODO this should be done as close to textures being used as possible due to memory issues."); //make procedural materials readable /* * for (int i = 0; i < combiner._proceduralMaterials.Count; i++) * { * if (!combiner._proceduralMaterials[i].proceduralMat.isReadable) * { * combiner._proceduralMaterials[i].originalIsReadableVal = combiner._proceduralMaterials[i].proceduralMat.isReadable; * combiner._proceduralMaterials[i].proceduralMat.isReadable = true; * //textureEditorMethods.AddProceduralMaterialFormat(_proceduralMaterials[i].proceduralMat); * combiner._proceduralMaterials[i].proceduralMat.RebuildTexturesImmediately(); * } * } * //convert procedural textures to RAW format * * for (int i = 0; i < distinctMaterialTextures.Count; i++) * { * for (int j = 0; j < texPropertyNames.Count; j++) * { * if (distinctMaterialTextures[i].ts[j].IsProceduralTexture()) * { * if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Converting procedural texture to Textur2D:" + distinctMaterialTextures[i].ts[j].GetTexName() + " property:" + texPropertyNames[i]); * Texture2D txx = distinctMaterialTextures[i].ts[j].ConvertProceduralToTexture2D(_temporaryTextures); * distinctMaterialTextures[i].ts[j].t = txx; * } * } * } */ }
public abstract IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo, MB3_TextureCombinerPipeline.TexturePipelineData data, MB3_TextureCombiner combiner, AtlasPackingResult packedAtlasRects, Texture2D[] atlases, MB2_EditorMethodsInterface textureEditorMethods, MB2_LogLevel LOG_LEVEL);
/// <summary> /// Creates one texture array per texture property. /// </summary> /// <returns></returns> internal static Texture2DArray[] CreateTextureArraysForResultMaterial(TexturePropertyData texPropertyData, List <ShaderTextureProperty> masterListOfTexProperties, MB_AtlasesAndRects[] resultAtlasesAndRectSlices, bool[] hasTexForProperty, MB3_TextureCombiner combiner, MB2_LogLevel LOG_LEVEL) { Debug.Assert(texPropertyData.sizes.Length == hasTexForProperty.Length); // ASSUMPTION all slices in the same format and the same size, alpha channel and mipMapCount string[] texPropertyNames = resultAtlasesAndRectSlices[0].texPropertyNames; Debug.Assert(texPropertyNames.Length == hasTexForProperty.Length); Texture2DArray[] texArrays = new Texture2DArray[texPropertyNames.Length]; // Each texture property (_MainTex, _Bump, ...) becomes a Texture2DArray for (int propIdx = 0; propIdx < texPropertyNames.Length; propIdx++) { if (!hasTexForProperty[propIdx]) { continue; } string propName = texPropertyNames[propIdx]; int numSlices = resultAtlasesAndRectSlices.Length; int w = (int)texPropertyData.sizes[propIdx].x; int h = (int)texPropertyData.sizes[propIdx].y; int numMips = (int)texPropertyData.numMipMaps[propIdx]; TextureFormat format = texPropertyData.formats[propIdx]; bool doMipMaps = texPropertyData.doMips[propIdx]; Debug.Assert(QualitySettings.desiredColorSpace == QualitySettings.activeColorSpace, "Wanted to use color space " + QualitySettings.desiredColorSpace + " but the activeColorSpace was " + QualitySettings.activeColorSpace + " hardware may not support the desired color space."); bool isLinear = MBVersion.GetProjectColorSpace() == ColorSpace.Linear; { if (IsLinearProperty(masterListOfTexProperties, propName)) { isLinear = true; } else { isLinear = false; } } Texture2DArray texArray = new Texture2DArray(w, h, numSlices, format, doMipMaps, isLinear); if (LOG_LEVEL >= MB2_LogLevel.info) { Debug.LogFormat("Creating Texture2DArray for property: {0} w: {1} h: {2} format: {3} doMips: {4} isLinear: {5}", propName, w, h, format, doMipMaps, isLinear); } for (int sliceIdx = 0; sliceIdx < numSlices; sliceIdx++) { Debug.Assert(resultAtlasesAndRectSlices[sliceIdx].atlases.Length == texPropertyNames.Length); Debug.Assert(resultAtlasesAndRectSlices[sliceIdx].texPropertyNames[propIdx] == propName); Texture2D srcTex = resultAtlasesAndRectSlices[sliceIdx].atlases[propIdx]; if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.LogFormat("Slice: {0} texture: {1}", sliceIdx, srcTex); } bool isCopy = false; if (srcTex == null) { if (LOG_LEVEL >= MB2_LogLevel.trace) { Debug.LogFormat("Texture is null for slice: {0} creating temporary texture", sliceIdx); } // Slices might not have all textures create a dummy if needed. srcTex = combiner._createTemporaryTexture(propName, w, h, format, doMipMaps, isLinear); } Debug.Assert(srcTex.width == texArray.width, "Source texture is not the same width as the texture array '" + srcTex + " srcWidth:" + srcTex.width + " texArrayWidth:" + texArray.width); Debug.Assert(srcTex.height == texArray.height, "Source texture is not the same height as the texture array " + srcTex + " srcWidth:" + srcTex.height + " texArrayWidth:" + texArray.height); Debug.Assert(srcTex.mipmapCount == numMips, "Source texture does have not the same number of mips as the texture array: " + srcTex + " numMipsTex: " + srcTex.mipmapCount + " numMipsTexArray: " + numMips + " texDims: " + srcTex.width + "x" + srcTex.height); Debug.Assert(srcTex.format == format, "Formats should have been converted before this. Texture: " + srcTex + "Source: " + srcTex.format + " Targ: " + format); for (int mipIdx = 0; mipIdx < numMips; mipIdx++) { Graphics.CopyTexture(srcTex, 0, mipIdx, texArray, sliceIdx, mipIdx); } if (isCopy) { MB_Utility.Destroy(srcTex); } } texArray.Apply(); texArrays[propIdx] = texArray; } return(texArrays); }
public IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo, MB3_TextureCombinerPipeline.TexturePipelineData data, MB3_TextureCombiner combiner, AtlasPackingResult packedAtlasRects, Texture2D[] atlases, MB2_EditorMethodsInterface textureEditorMethods, MB2_LogLevel LOG_LEVEL) { Rect[] uvRects = packedAtlasRects.rects; if (uvRects.Length == 1) { if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("Only one image per atlas. Will re-use original texture"); } for (int i = 0; i < data.numAtlases; i++) { MeshBakerMaterialTexture 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, dmt.matTilingRect.size); data.resultMaterial.SetTextureOffset(data.texPropertyNames[i].name, dmt.matTilingRect.min); } } else { int atlasSizeX = packedAtlasRects.atlasX; int atlasSizeY = packedAtlasRects.atlasY; if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("Generated atlas will be " + atlasSizeX + "x" + atlasSizeY); } //create a game object GameObject renderAtlasesGO = null; try { renderAtlasesGO = new GameObject("MBrenderAtlasesGO"); MB3_AtlasPackerRenderTexture atlasRenderTexture = renderAtlasesGO.AddComponent <MB3_AtlasPackerRenderTexture>(); renderAtlasesGO.AddComponent <Camera>(); if (data._considerNonTextureProperties) { if (LOG_LEVEL >= MB2_LogLevel.warn) { Debug.LogWarning("Blend Non-Texture Properties has limited functionality when used with Mesh Baker Texture Packer Fast."); } } for (int i = 0; i < data.numAtlases; i++) { Texture2D atlas = null; if (!MB3_TextureCombinerPipeline._ShouldWeCreateAtlasForThisProperty(i, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor)) { atlas = null; if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("Not creating atlas for " + data.texPropertyNames[i].name + " because textures are null and default value parameters are the same."); } } else { GC.Collect(); if (progressInfo != null) { progressInfo("Creating Atlas '" + data.texPropertyNames[i].name + "'", .01f); } // =========== // configure it if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("About to render " + data.texPropertyNames[i].name + " isNormal=" + data.texPropertyNames[i].isNormalMap); } atlasRenderTexture.LOG_LEVEL = LOG_LEVEL; atlasRenderTexture.width = atlasSizeX; atlasRenderTexture.height = atlasSizeY; atlasRenderTexture.padding = data._atlasPadding; atlasRenderTexture.rects = uvRects; atlasRenderTexture.textureSets = data.distinctMaterialTextures; atlasRenderTexture.indexOfTexSetToRender = i; atlasRenderTexture.texPropertyName = data.texPropertyNames[i]; atlasRenderTexture.isNormalMap = data.texPropertyNames[i].isNormalMap; atlasRenderTexture.fixOutOfBoundsUVs = data._fixOutOfBoundsUVs; atlasRenderTexture.considerNonTextureProperties = data._considerNonTextureProperties; atlasRenderTexture.resultMaterialTextureBlender = data.nonTexturePropertyBlender; // call render on it atlas = atlasRenderTexture.OnRenderAtlas(combiner); // destroy it // ============= if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("Saving atlas " + data.texPropertyNames[i].name + " w=" + atlas.width + " h=" + atlas.height + " id=" + atlas.GetInstanceID()); } } atlases[i] = atlas; if (progressInfo != null) { progressInfo("Saving atlas: '" + data.texPropertyNames[i].name + "'", .04f); } if (data._saveAtlasesAsAssets && textureEditorMethods != null) { textureEditorMethods.SaveAtlasToAssetDatabase(atlases[i], data.texPropertyNames[i], i, data.resultMaterial); } else { data.resultMaterial.SetTexture(data.texPropertyNames[i].name, atlases[i]); } data.resultMaterial.SetTextureOffset(data.texPropertyNames[i].name, Vector2.zero); data.resultMaterial.SetTextureScale(data.texPropertyNames[i].name, Vector2.one); combiner._destroyTemporaryTextures(); // need to save atlases before doing this } } catch (Exception ex) { //Debug.LogError(ex); Debug.LogException(ex); } finally { if (renderAtlasesGO != null) { MB_Utility.Destroy(renderAtlasesGO); } } } yield break; }
private void CopyScaledAndTiledToAtlas(MB3_TextureCombiner.MeshBakerMaterialTexture source, Rect rec, int _padding, bool _fixOutOfBoundsUVs, int maxSize, bool isNormalMap) { Rect r = rec; r.x += _padding; r.y += _padding; r.width -= _padding * 2; r.height -= _padding * 2; //fill the _padding Rect srcPrTex = new Rect(); Rect targPr = new Rect(); srcPrTex.width = source.scale.x; srcPrTex.height = source.scale.y; srcPrTex.x = source.offset.x; srcPrTex.y = source.offset.y; if (_fixOutOfBoundsUVs){ srcPrTex.width *= source.obUVscale.x; srcPrTex.height *= source.obUVscale.y; srcPrTex.x += source.obUVoffset.x; srcPrTex.y += source.obUVoffset.y; } Texture tex = source.t; //main texture TextureWrapMode oldTexWrapMode = tex.wrapMode; if (srcPrTex.width == 1f && srcPrTex.height == 1f && srcPrTex.x == 0f && srcPrTex.y == 0f){ //fixes bug where there is a dark line at the edge of the texture tex.wrapMode = TextureWrapMode.Clamp; } else { tex.wrapMode = TextureWrapMode.Repeat; } Graphics.DrawTexture(r, tex, srcPrTex, 0, 0, 0, 0, mat); //TODO fill the _padding Rect srcPr = new Rect(); //top margin srcPr.x = srcPrTex.x; srcPr.y = srcPrTex.y + 1f - 1f / tex.height; srcPr.width = srcPrTex.width; srcPr.height = 1f / tex.height; targPr.x = rec.x + _padding; targPr.y = rec.y; targPr.width = r.width; targPr.height = _padding; Graphics.DrawTexture(targPr, tex, srcPr, 0, 0, 0, 0, mat); //bot margin srcPr.x = srcPrTex.x; srcPr.y = srcPrTex.y; srcPr.width = srcPrTex.width; srcPr.height = 1f / tex.height; targPr.x = rec.x + _padding; targPr.y = rec.y + r.height + _padding; targPr.width = r.width; targPr.height = _padding; Graphics.DrawTexture(targPr, tex, srcPr, 0, 0, 0, 0, mat); //left margin srcPr.x = srcPrTex.x; srcPr.y = srcPrTex.y; srcPr.width = 1f / tex.width; srcPr.height = srcPrTex.height; targPr.x = rec.x; targPr.y = rec.y + _padding; targPr.width = _padding; targPr.height = r.height; Graphics.DrawTexture(targPr, tex, srcPr, 0, 0, 0, 0, mat); //right margin srcPr.x = srcPrTex.x + 1f - 1f / tex.width; srcPr.y = srcPrTex.y; srcPr.width = 1f / tex.width; srcPr.height = srcPrTex.height; targPr.x = rec.x + r.width + _padding; targPr.y = rec.y + _padding; targPr.width = _padding; targPr.height = r.height; Graphics.DrawTexture(targPr, tex, srcPr, 0, 0, 0, 0, mat); //top left corner srcPr.x = srcPrTex.x; srcPr.y = srcPrTex.y; srcPr.width = 1f / tex.width; srcPr.height = 1f / tex.height; targPr.x = rec.x; targPr.y = rec.y; targPr.width = _padding; targPr.height = _padding; Graphics.DrawTexture(targPr, tex, srcPr, 0, 0, 0, 0, mat); tex.wrapMode = oldTexWrapMode; }
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(); } }
public IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo, MB3_TextureCombinerPipeline.TexturePipelineData data, MB3_TextureCombiner combiner, AtlasPackingResult packedAtlasRects, Texture2D[] atlases, MB2_EditorMethodsInterface textureEditorMethods, MB2_LogLevel LOG_LEVEL) { Debug.Assert(!data.OnlyOneTextureInAtlasReuseTextures()); Rect[] uvRects = packedAtlasRects.rects; int atlasSizeX = packedAtlasRects.atlasX; int atlasSizeY = packedAtlasRects.atlasY; if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("Generated atlas will be " + atlasSizeX + "x" + atlasSizeY); } int layer = data._layerTexturePackerFastV2; Debug.Assert(layer >= 0 && layer <= 32); //create a game object mesh = new Mesh(); renderAtlasesGO = null; cameraGameObject = null; try { System.Diagnostics.Stopwatch db_time_MB3_TextureCombinerPackerMeshBakerFastV2_CreateAtlases = new System.Diagnostics.Stopwatch(); db_time_MB3_TextureCombinerPackerMeshBakerFastV2_CreateAtlases.Start(); renderAtlasesGO = new GameObject("MBrenderAtlasesGO"); cameraGameObject = new GameObject("MBCameraGameObject"); MB3_AtlasPackerRenderTextureUsingMesh atlasRenderer = new MB3_AtlasPackerRenderTextureUsingMesh(); OneTimeSetup(atlasRenderer, renderAtlasesGO, cameraGameObject, atlasSizeX, atlasSizeY, data._atlasPadding, layer, LOG_LEVEL); if (data._considerNonTextureProperties && LOG_LEVEL >= MB2_LogLevel.warn) { Debug.LogWarning("Blend Non-Texture Properties has limited functionality when used with Mesh Baker Texture Packer Fast."); } List <Material> mats = new List <Material>(); for (int propIdx = 0; propIdx < data.numAtlases; propIdx++) { Texture2D atlas = null; if (!MB3_TextureCombinerPipeline._ShouldWeCreateAtlasForThisProperty(propIdx, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor)) { atlas = null; if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("Not creating atlas for " + data.texPropertyNames[propIdx].name + " because textures are null and default value parameters are the same."); } } else { if (progressInfo != null) { progressInfo("Creating Atlas '" + data.texPropertyNames[propIdx].name + "'", .01f); } // configure it if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("About to render " + data.texPropertyNames[propIdx].name + " isNormal=" + data.texPropertyNames[propIdx].isNormalMap); } // Create the mesh mats.Clear(); MB3_AtlasPackerRenderTextureUsingMesh.MeshAtlas.BuildAtlas(packedAtlasRects, data.distinctMaterialTextures, propIdx, packedAtlasRects.atlasX, packedAtlasRects.atlasY, mesh, mats, data.texPropertyNames[propIdx], data, combiner, textureEditorMethods, LOG_LEVEL); { MeshFilter mf = renderAtlasesGO.GetComponent <MeshFilter>(); mf.sharedMesh = mesh; MeshRenderer mrr = renderAtlasesGO.GetComponent <MeshRenderer>(); Material[] mrs = mats.ToArray(); mrr.sharedMaterials = mrs; } // Render atlas = atlasRenderer.DoRenderAtlas(cameraGameObject, packedAtlasRects.atlasX, packedAtlasRects.atlasY, data.texPropertyNames[propIdx].isNormalMap, data.texPropertyNames[propIdx]); { for (int i = 0; i < mats.Count; i++) { MB_Utility.Destroy(mats[i]); } mats.Clear(); } if (LOG_LEVEL >= MB2_LogLevel.debug) { 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.resultType == MB2_TextureBakeResults.ResultType.atlas) { MB3_TextureCombinerPackerRoot.SaveAtlasAndConfigureResultMaterial(data, textureEditorMethods, atlases[propIdx], data.texPropertyNames[propIdx], propIdx); } combiner._destroyTemporaryTextures(data.texPropertyNames[propIdx].name); // need to save atlases before doing this } if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.LogFormat("Timing MB3_TextureCombinerPackerMeshBakerFastV2.CreateAtlases={0}", db_time_MB3_TextureCombinerPackerMeshBakerFastV2_CreateAtlases.ElapsedMilliseconds * .001f); } } catch (Exception ex) { Debug.LogError(ex.Message + "\n" + ex.StackTrace.ToString()); } finally { if (renderAtlasesGO != null) { MB_Utility.Destroy(renderAtlasesGO); } if (cameraGameObject != null) { MB_Utility.Destroy(cameraGameObject); } if (mesh != null) { MB_Utility.Destroy(mesh); } } yield break; }
// used by Unity texture packer to handle tiled textures. // may create a new texture that has the correct tiling to handle fix out of bounds UVs internal static Texture2D GetAdjustedForScaleAndOffset2(string propertyName, MeshBakerMaterialTexture source, Vector2 obUVoffset, Vector2 obUVscale, MB3_TextureCombinerPipeline.TexturePipelineData data, MB3_TextureCombiner combiner, MB2_LogLevel LOG_LEVEL) { Texture2D sourceTex = source.GetTexture2D(); if (source.matTilingRect.x == 0f && source.matTilingRect.y == 0f && source.matTilingRect.width == 1f && source.matTilingRect.height == 1f) { if (data._fixOutOfBoundsUVs) { if (obUVoffset.x == 0f && obUVoffset.y == 0f && obUVscale.x == 1f && obUVscale.y == 1f) { return(sourceTex); //no adjustment necessary } } else { return(sourceTex); //no adjustment necessary } } Vector2 dim = MB3_TextureCombinerPipeline.GetAdjustedForScaleAndOffset2Dimensions(source, obUVoffset, obUVscale, data, LOG_LEVEL); if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.LogWarning("GetAdjustedForScaleAndOffset2: " + sourceTex + " " + obUVoffset + " " + obUVscale); } float newWidth = dim.x; float newHeight = dim.y; float scx = (float)source.matTilingRect.width; float scy = (float)source.matTilingRect.height; float ox = (float)source.matTilingRect.x; float oy = (float)source.matTilingRect.y; if (data._fixOutOfBoundsUVs) { scx *= obUVscale.x; scy *= obUVscale.y; ox = (float)(source.matTilingRect.x * obUVscale.x + obUVoffset.x); oy = (float)(source.matTilingRect.y * obUVscale.y + obUVoffset.y); } Texture2D newTex = combiner._createTemporaryTexture(propertyName, (int)newWidth, (int)newHeight, TextureFormat.ARGB32, true); for (int i = 0; i < newTex.width; i++) { for (int j = 0; j < newTex.height; j++) { float u = i / newWidth * scx + ox; float v = j / newHeight * scy + oy; newTex.SetPixel(i, j, sourceTex.GetPixelBilinear(u, v)); } } newTex.Apply(); return(newTex); }
public void CreateColoredTexToReplaceNull(string propName, int propIdx, bool considerMeshUVs, MB3_TextureCombiner combiner, Color col) { MeshBakerMaterialTexture matTex = ts[propIdx]; matTex.t = combiner._createTemporaryTexture(propName, 16, 16, TextureFormat.ARGB32, true); MB_Utility.setSolidColor(matTex.GetTexture2D(), col); }
internal static IEnumerator CopyScaledAndTiledToAtlas(MeshBakerMaterialTexture source, MB_TexSet sourceMaterial, ShaderTextureProperty shaderPropertyName, DRect srcSamplingRect, int targX, int targY, int targW, int targH, AtlasPadding padding, Color[][] atlasPixels, bool isNormalMap, MB3_TextureCombinerPipeline.TexturePipelineData data, MB3_TextureCombiner combiner, ProgressUpdateDelegate progressInfo = null, MB2_LogLevel LOG_LEVEL = MB2_LogLevel.info) { //HasFinished = false; Texture2D t = source.GetTexture2D(); if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("CopyScaledAndTiledToAtlas: " + t + " inAtlasX=" + targX + " inAtlasY=" + targY + " inAtlasW=" + targW + " inAtlasH=" + targH); } 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 (t == null) { if (LOG_LEVEL >= MB2_LogLevel.trace) { Debug.Log("No source texture creating a 16x16 texture."); } t = combiner._createTemporaryTexture(16, 16, TextureFormat.ARGB32, true); scx = 1; scy = 1; if (data._considerNonTextureProperties && data.nonTexturePropertyBlender != null) { Color col = data.nonTexturePropertyBlender.GetColorIfNoTexture(sourceMaterial.matsAndGOs.mats[0].mat, shaderPropertyName); if (LOG_LEVEL >= MB2_LogLevel.trace) { Debug.Log("Setting texture to solid color " + col); } MB_Utility.setSolidColor(t, col); } else { Color col = MB3_TextureCombinerNonTextureProperties.GetColorIfNoTexture(shaderPropertyName); MB_Utility.setSolidColor(t, col); } } if (data._considerNonTextureProperties && data.nonTexturePropertyBlender != null) { t = combiner._createTextureCopy(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); } // Debug.Log("copyandscaledatlas finished too!"); //HasFinished = true; yield break; }
private void CopyScaledAndTiledToAtlas(MB3_TextureCombiner.MeshBakerMaterialTexture source, Rect rec){ Rect r = rec; myCamera.backgroundColor = source.colorIfNoTexture; if (source.t == null){ source.t = combiner._createTemporaryTexture(16,16,TextureFormat.ARGB32, true); Debug.Log("Creating texture with color " + source.colorIfNoTexture + " isNormal" + _isNormalMap); MB_Utility.setSolidColor(source.t,source.colorIfNoTexture); } r.y = 1f - (r.y + r.height); // DrawTexture uses topLeft 0,0, Texture2D uses bottomLeft 0,0 r.x *= _destinationTexture.width; r.y *= _destinationTexture.height; r.width *= _destinationTexture.width; r.height *= _destinationTexture.height; Rect rPadded = r; rPadded.x -= _padding; rPadded.y -= _padding; rPadded.width += _padding * 2; rPadded.height += _padding * 2; Rect srcPrTex = new Rect(); Rect targPr = new Rect(); srcPrTex.width = source.scale.x; srcPrTex.height = source.scale.y; srcPrTex.x = source.offset.x; srcPrTex.y = source.offset.y; if (_fixOutOfBoundsUVs){ srcPrTex.width *= source.obUVscale.x; srcPrTex.height *= source.obUVscale.y; srcPrTex.x += source.obUVoffset.x; srcPrTex.y += source.obUVoffset.y; if (LOG_LEVEL >= MB2_LogLevel.trace) Debug.Log ("Fixing out of bounds UVs for tex " + source.t); } Texture tex = source.t; //main texture TextureWrapMode oldTexWrapMode = tex.wrapMode; if (srcPrTex.width == 1f && srcPrTex.height == 1f && srcPrTex.x == 0f && srcPrTex.y == 0f){ //fixes bug where there is a dark line at the edge of the texture tex.wrapMode = TextureWrapMode.Clamp; } else { tex.wrapMode = TextureWrapMode.Repeat; } if (LOG_LEVEL >= MB2_LogLevel.trace) Debug.Log ("DrawTexture tex=" + tex.name + " destRect=" + r + " srcRect=" + srcPrTex + " Mat=" + mat); //fill the padding first Rect srcPr = new Rect(); //top margin srcPr.x = srcPrTex.x; srcPr.y = srcPrTex.y + 1 - 1f / tex.height; srcPr.width = srcPrTex.width; srcPr.height = 1f / tex.height; targPr.x = r.x; targPr.y = rPadded.y; targPr.width = r.width; targPr.height = _padding; Graphics.DrawTexture(targPr, tex, srcPr, 0, 0, 0, 0, mat); //bot margin srcPr.x = srcPrTex.x; srcPr.y = srcPrTex.y; srcPr.width = srcPrTex.width; srcPr.height = 1f / tex.height; targPr.x = r.x; targPr.y = r.y + r.height; targPr.width = r.width; targPr.height = _padding; Graphics.DrawTexture(targPr, tex, srcPr, 0, 0, 0, 0, mat); //left margin srcPr.x = srcPrTex.x; srcPr.y = srcPrTex.y; srcPr.width = 1f / tex.width; srcPr.height = srcPrTex.height; targPr.x = rPadded.x; targPr.y = r.y; targPr.width = _padding; targPr.height = r.height; Graphics.DrawTexture(targPr, tex, srcPr, 0, 0, 0, 0, mat); //right margin srcPr.x = srcPrTex.x + 1f - 1f / tex.width; srcPr.y = srcPrTex.y; srcPr.width = 1f / tex.width; srcPr.height = srcPrTex.height; targPr.x = r.x + r.width; targPr.y = r.y; targPr.width = _padding; targPr.height = r.height; Graphics.DrawTexture(targPr, tex, srcPr, 0, 0, 0, 0, mat); //top left corner srcPr.x = srcPrTex.x; srcPr.y = srcPrTex.y + 1 - 1f / tex.height ; srcPr.width = 1f / tex.width; srcPr.height = 1f / tex.height; targPr.x = rPadded.x; targPr.y = rPadded.y; targPr.width = _padding; targPr.height = _padding; Graphics.DrawTexture(targPr, tex, srcPr, 0, 0, 0, 0, mat); //top right corner srcPr.x = srcPrTex.x + 1f - 1f / tex.width; srcPr.y = srcPrTex.y + 1 - 1f / tex.height ; srcPr.width = 1f / tex.width; srcPr.height = 1f / tex.height; targPr.x = r.x + r.width; targPr.y = rPadded.y; targPr.width = _padding; targPr.height = _padding; Graphics.DrawTexture(targPr, tex, srcPr, 0, 0, 0, 0, mat); //bot left corner srcPr.x = srcPrTex.x; srcPr.y = srcPrTex.y; srcPr.width = 1f / tex.width; srcPr.height = 1f / tex.height; targPr.x = rPadded.x; targPr.y = r.y + r.height; targPr.width = _padding; targPr.height = _padding; Graphics.DrawTexture(targPr, tex, srcPr, 0, 0, 0, 0, mat); //bot right corner srcPr.x = srcPrTex.x + 1f - 1f / tex.width; srcPr.y = srcPrTex.y ; srcPr.width = 1f / tex.width; srcPr.height = 1f / tex.height; targPr.x = r.x + r.width; targPr.y = r.y + r.height; targPr.width = _padding; targPr.height = _padding; Graphics.DrawTexture(targPr, tex, srcPr, 0, 0, 0, 0, mat); //now the texture Graphics.DrawTexture(r, tex, srcPrTex, 0, 0, 0, 0, mat); tex.wrapMode = oldTexWrapMode; }
internal static IEnumerator _CreateAtlasesCoroutineTextureArray(MB3_TextureBaker tb, MB3_TextureCombiner combiner, ProgressUpdateDelegate progressInfo, MB3_TextureBaker.CreateAtlasesCoroutineResult coroutineResult, bool saveAtlasesAsAssets = false, MB2_EditorMethodsInterface editorMethods = null, float maxTimePerFrame = .01f) { MB_TextureArrayResultMaterial[] bakedMatsAndSlices = null; // Validate the formats if (tb.textureArrayOutputFormats == null || tb.textureArrayOutputFormats.Length == 0) { Debug.LogError("No Texture Array Output Formats. There must be at least one entry."); coroutineResult.isFinished = true; yield break; } for (int i = 0; i < tb.textureArrayOutputFormats.Length; i++) { if (!tb.textureArrayOutputFormats[i].ValidateTextureImporterFormatsExistsForTextureFormats(editorMethods, i)) { Debug.LogError("Could not map the selected texture format to a Texture Importer Format. Safest options are ARGB32, or RGB24."); coroutineResult.isFinished = true; yield break; } } for (int resMatIdx = 0; resMatIdx < tb.resultMaterialsTexArray.Length; resMatIdx++) { MB_MultiMaterialTexArray textureArraySliceConfig = tb.resultMaterialsTexArray[resMatIdx]; if (textureArraySliceConfig.combinedMaterial == null) { Debug.LogError("Material is null for Texture Array Slice Configuration: " + resMatIdx + "."); coroutineResult.isFinished = true; yield break; } List <MB_TexArraySlice> slices = textureArraySliceConfig.slices; for (int sliceIdx = 0; sliceIdx < slices.Count; sliceIdx++) { for (int srcMatIdx = 0; srcMatIdx < slices[sliceIdx].sourceMaterials.Count; srcMatIdx++) { MB_TexArraySliceRendererMatPair sourceMat = slices[sliceIdx].sourceMaterials[srcMatIdx]; if (sourceMat.sourceMaterial == null) { Debug.LogError("Source material is null for Texture Array Slice Configuration: " + resMatIdx + " slice: " + sliceIdx); coroutineResult.isFinished = true; yield break; } if (slices[sliceIdx].considerMeshUVs) { if (sourceMat.renderer == null) { Debug.LogError("Renderer is null for Texture Array Slice Configuration: " + resMatIdx + " slice: " + sliceIdx + ". If considerUVs is enabled then a renderer must be supplied for each source material. The same source material can be used multiple times."); coroutineResult.isFinished = true; yield break; } } else { // TODO check for duplicate source mats. } } } } for (int resMatIdx = 0; resMatIdx < tb.resultMaterialsTexArray.Length; resMatIdx++) { MB_MultiMaterialTexArray textureArraySliceConfig = tb.resultMaterialsTexArray[resMatIdx]; } // initialize structure to store results. For texture arrays the structure is two layers deep. // First layer is resultMaterial / submesh (each result material can use a different shader) // Second layer is a set of TextureArrays for the TextureProperties on that result material. int numResultMats = tb.resultMaterialsTexArray.Length; bakedMatsAndSlices = new MB_TextureArrayResultMaterial[numResultMats]; for (int resMatIdx = 0; resMatIdx < bakedMatsAndSlices.Length; resMatIdx++) { bakedMatsAndSlices[resMatIdx] = new MB_TextureArrayResultMaterial(); int numSlices = tb.resultMaterialsTexArray[resMatIdx].slices.Count; MB_AtlasesAndRects[] slices = bakedMatsAndSlices[resMatIdx].slices = new MB_AtlasesAndRects[numSlices]; for (int j = 0; j < numSlices; j++) { slices[j] = new MB_AtlasesAndRects(); } } // Some of the slices will be atlases (more than one atlas per slice). // Do the material combining for these. First loop over the result materials (1 per submeshes). for (int resMatIdx = 0; resMatIdx < bakedMatsAndSlices.Length; resMatIdx++) { yield return(_CreateAtlasesCoroutineSingleResultMaterial(resMatIdx, bakedMatsAndSlices[resMatIdx], tb.resultMaterialsTexArray[resMatIdx], tb, combiner, progressInfo, coroutineResult, saveAtlasesAsAssets, editorMethods, maxTimePerFrame)); if (!coroutineResult.success) { yield break; } } if (coroutineResult.success) { // Save the results into the TextureBakeResults. tb.unpackMat2RectMap(bakedMatsAndSlices); tb.textureBakeResults.resultType = MB2_TextureBakeResults.ResultType.textureArray; tb.textureBakeResults.resultMaterials = new MB_MultiMaterial[0]; tb.textureBakeResults.resultMaterialsTexArray = tb.resultMaterialsTexArray; if (tb.LOG_LEVEL >= MB2_LogLevel.info) { Debug.Log("Created Texture2DArrays"); } } else { if (tb.LOG_LEVEL >= MB2_LogLevel.info) { Debug.Log("Failed to create Texture2DArrays"); } } }
/// <summary> /// Creates one texture array per texture property. /// </summary> /// <returns></returns> internal static Texture2DArray[] CreateTextureArraysForResultMaterial(TexturePropertyData texPropertyData, MB_AtlasesAndRects[] resultAtlasesAndRectSlices, bool[] hasTexForProperty, MB3_TextureCombiner combiner, MB2_LogLevel LOG_LEVEL) { Debug.Assert(texPropertyData.sizes.Length == hasTexForProperty.Length); // ASSUMPTION all slices in the same format and the same size, alpha channel and mipMapCount string[] texPropertyNames = resultAtlasesAndRectSlices[0].texPropertyNames; Debug.Assert(texPropertyNames.Length == hasTexForProperty.Length); Texture2DArray[] texArrays = new Texture2DArray[texPropertyNames.Length]; // Each texture property (_MainTex, _Bump, ...) becomes a Texture2DArray for (int propIdx = 0; propIdx < texPropertyNames.Length; propIdx++) { if (!hasTexForProperty[propIdx]) { continue; } int numSlices = resultAtlasesAndRectSlices.Length; int w = (int)texPropertyData.sizes[propIdx].x; int h = (int)texPropertyData.sizes[propIdx].y; int numMips = (int)texPropertyData.numMipMaps[propIdx]; TextureFormat format = texPropertyData.formats[propIdx]; bool doMipMaps = texPropertyData.doMips[propIdx]; Texture2DArray texArray = new Texture2DArray(w, h, numSlices, format, doMipMaps); if (LOG_LEVEL >= MB2_LogLevel.info) { Debug.LogFormat("Creating Texture2DArray for property: {0} w: {1} h: {2} format: {3} doMips: {4}", texPropertyNames[propIdx], w, h, format, doMipMaps); } for (int sliceIdx = 0; sliceIdx < numSlices; sliceIdx++) { Debug.Assert(resultAtlasesAndRectSlices[sliceIdx].atlases.Length == texPropertyNames.Length); Debug.Assert(resultAtlasesAndRectSlices[sliceIdx].texPropertyNames[propIdx] == texPropertyNames[propIdx]); Texture2D srcTex = resultAtlasesAndRectSlices[sliceIdx].atlases[propIdx]; if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.LogFormat("Slice: {0} texture: {1}", sliceIdx, srcTex); } bool isCopy = false; if (srcTex == null) { // Slices might not have all textures create a dummy if needed. srcTex = combiner._createTemporaryTexture(texPropertyNames[propIdx], w, h, format, doMipMaps); } Debug.Assert(srcTex.width == texArray.width, "Source texture is not the same width as the texture array " + srcTex); Debug.Assert(srcTex.height == texArray.height, "Source texture is not the same height as the texture array " + srcTex); Debug.Assert(srcTex.mipmapCount == numMips, "Source texture does have not the same number of mips as the texture array: " + srcTex + " numMipsTex: " + srcTex.mipmapCount + " numMipsTexArray: " + numMips + " texDims: " + srcTex.width + "x" + srcTex.height); Debug.Assert(srcTex.format == format, "Formats should have been converted before this. Texture: " + srcTex + "Source: " + srcTex.format + " Targ: " + format); for (int mipIdx = 0; mipIdx < numMips; mipIdx++) { Graphics.CopyTexture(srcTex, 0, mipIdx, texArray, sliceIdx, mipIdx); } if (isCopy) { MB_Utility.Destroy(srcTex); } } texArray.Apply(); texArrays[propIdx] = texArray; } return(texArrays); }
private void CopyScaledAndTiledToAtlas(MB3_TextureCombiner.MeshBakerMaterialTexture source, Rect rec) { Rect rect = rec; this.myCamera.backgroundColor = source.colorIfNoTexture; if (source.t == null) { source.t = this.combiner._createTemporaryTexture(16, 16, TextureFormat.ARGB32, true); UnityEngine.Debug.Log(string.Concat(new object[] { "Creating texture with color ", source.colorIfNoTexture, " isNormal", this._isNormalMap })); MB_Utility.setSolidColor(source.t, source.colorIfNoTexture); } rect.y = 1f - (rect.y + rect.height); rect.x *= (float)this._destinationTexture.width; rect.y *= (float)this._destinationTexture.height; rect.width *= (float)this._destinationTexture.width; rect.height *= (float)this._destinationTexture.height; Rect rect2 = rect; rect2.x -= (float)this._padding; rect2.y -= (float)this._padding; rect2.width += (float)(this._padding * 2); rect2.height += (float)(this._padding * 2); Rect rect3 = default(Rect); Rect screenRect = default(Rect); rect3.width = source.scale.x; rect3.height = source.scale.y; rect3.x = source.offset.x; rect3.y = source.offset.y; if (this._fixOutOfBoundsUVs) { rect3.width *= source.obUVscale.x; rect3.height *= source.obUVscale.y; rect3.x += source.obUVoffset.x; rect3.y += source.obUVoffset.y; if (this.LOG_LEVEL >= MB2_LogLevel.trace) { UnityEngine.Debug.Log("Fixing out of bounds UVs for tex " + source.t); } } Texture t = source.t; TextureWrapMode wrapMode = t.wrapMode; if (rect3.width == 1f && rect3.height == 1f && rect3.x == 0f && rect3.y == 0f) { t.wrapMode = TextureWrapMode.Clamp; } else { t.wrapMode = TextureWrapMode.Repeat; } if (this.LOG_LEVEL >= MB2_LogLevel.trace) { UnityEngine.Debug.Log(string.Concat(new object[] { "DrawTexture tex=", t.name, " destRect=", rect, " srcRect=", rect3, " Mat=", this.mat })); } Rect sourceRect = default(Rect); sourceRect.x = rect3.x; sourceRect.y = rect3.y + 1f - 1f / (float)t.height; sourceRect.width = rect3.width; sourceRect.height = 1f / (float)t.height; screenRect.x = rect.x; screenRect.y = rect2.y; screenRect.width = rect.width; screenRect.height = (float)this._padding; Graphics.DrawTexture(screenRect, t, sourceRect, 0, 0, 0, 0, this.mat); sourceRect.x = rect3.x; sourceRect.y = rect3.y; sourceRect.width = rect3.width; sourceRect.height = 1f / (float)t.height; screenRect.x = rect.x; screenRect.y = rect.y + rect.height; screenRect.width = rect.width; screenRect.height = (float)this._padding; Graphics.DrawTexture(screenRect, t, sourceRect, 0, 0, 0, 0, this.mat); sourceRect.x = rect3.x; sourceRect.y = rect3.y; sourceRect.width = 1f / (float)t.width; sourceRect.height = rect3.height; screenRect.x = rect2.x; screenRect.y = rect.y; screenRect.width = (float)this._padding; screenRect.height = rect.height; Graphics.DrawTexture(screenRect, t, sourceRect, 0, 0, 0, 0, this.mat); sourceRect.x = rect3.x + 1f - 1f / (float)t.width; sourceRect.y = rect3.y; sourceRect.width = 1f / (float)t.width; sourceRect.height = rect3.height; screenRect.x = rect.x + rect.width; screenRect.y = rect.y; screenRect.width = (float)this._padding; screenRect.height = rect.height; Graphics.DrawTexture(screenRect, t, sourceRect, 0, 0, 0, 0, this.mat); sourceRect.x = rect3.x; sourceRect.y = rect3.y + 1f - 1f / (float)t.height; sourceRect.width = 1f / (float)t.width; sourceRect.height = 1f / (float)t.height; screenRect.x = rect2.x; screenRect.y = rect2.y; screenRect.width = (float)this._padding; screenRect.height = (float)this._padding; Graphics.DrawTexture(screenRect, t, sourceRect, 0, 0, 0, 0, this.mat); sourceRect.x = rect3.x + 1f - 1f / (float)t.width; sourceRect.y = rect3.y + 1f - 1f / (float)t.height; sourceRect.width = 1f / (float)t.width; sourceRect.height = 1f / (float)t.height; screenRect.x = rect.x + rect.width; screenRect.y = rect2.y; screenRect.width = (float)this._padding; screenRect.height = (float)this._padding; Graphics.DrawTexture(screenRect, t, sourceRect, 0, 0, 0, 0, this.mat); sourceRect.x = rect3.x; sourceRect.y = rect3.y; sourceRect.width = 1f / (float)t.width; sourceRect.height = 1f / (float)t.height; screenRect.x = rect2.x; screenRect.y = rect.y + rect.height; screenRect.width = (float)this._padding; screenRect.height = (float)this._padding; Graphics.DrawTexture(screenRect, t, sourceRect, 0, 0, 0, 0, this.mat); sourceRect.x = rect3.x + 1f - 1f / (float)t.width; sourceRect.y = rect3.y; sourceRect.width = 1f / (float)t.width; sourceRect.height = 1f / (float)t.height; screenRect.x = rect.x + rect.width; screenRect.y = rect.y + rect.height; screenRect.width = (float)this._padding; screenRect.height = (float)this._padding; Graphics.DrawTexture(screenRect, t, sourceRect, 0, 0, 0, 0, this.mat); Graphics.DrawTexture(rect, t, rect3, 0, 0, 0, 0, this.mat); t.wrapMode = wrapMode; }
public IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo, MB3_TextureCombinerPipeline.TexturePipelineData data, MB3_TextureCombiner combiner, AtlasPackingResult packedAtlasRects, Texture2D[] atlases, MB2_EditorMethodsInterface textureEditorMethods, MB2_LogLevel LOG_LEVEL) { Debug.Assert(!data.OnlyOneTextureInAtlasReuseTextures()); Rect[] uvRects = packedAtlasRects.rects; int atlasSizeX = packedAtlasRects.atlasX; int atlasSizeY = packedAtlasRects.atlasY; if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("Generated atlas will be " + atlasSizeX + "x" + atlasSizeY); } //create a game object GameObject renderAtlasesGO = null; try { renderAtlasesGO = new GameObject("MBrenderAtlasesGO"); MB3_AtlasPackerRenderTexture atlasRenderTexture = renderAtlasesGO.AddComponent <MB3_AtlasPackerRenderTexture>(); renderAtlasesGO.AddComponent <Camera>(); if (data._considerNonTextureProperties && LOG_LEVEL >= MB2_LogLevel.warn) { Debug.LogError("Blend Non-Texture Properties has limited functionality when used with Mesh Baker Texture Packer Fast. If no texture is pesent, then a small texture matching the non-texture property will be created and used in the atlas. But non-texture properties will not be blended into texture."); } for (int propIdx = 0; propIdx < data.numAtlases; propIdx++) { Texture2D atlas = null; if (!MB3_TextureCombinerPipeline._ShouldWeCreateAtlasForThisProperty(propIdx, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor)) { atlas = null; if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("Not creating atlas for " + data.texPropertyNames[propIdx].name + " because textures are null and default value parameters are the same."); } } else { GC.Collect(); MB3_TextureCombinerPackerRoot.CreateTemporaryTexturesForAtlas(data.distinctMaterialTextures, combiner, propIdx, data); if (progressInfo != null) { progressInfo("Creating Atlas '" + data.texPropertyNames[propIdx].name + "'", .01f); } // =========== // configure it if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("About to render " + data.texPropertyNames[propIdx].name + " isNormal=" + data.texPropertyNames[propIdx].isNormalMap); } atlasRenderTexture.LOG_LEVEL = LOG_LEVEL; 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 // ============= if (LOG_LEVEL >= MB2_LogLevel.debug) { 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.resultType == MB2_TextureBakeResults.ResultType.atlas) { MB3_TextureCombinerPackerRoot.SaveAtlasAndConfigureResultMaterial(data, textureEditorMethods, atlases[propIdx], data.texPropertyNames[propIdx], propIdx); } combiner._destroyTemporaryTextures(data.texPropertyNames[propIdx].name); // need to save atlases before doing this } } catch (Exception ex) { //Debug.LogError(ex); Debug.LogError(ex.Message + "\n" + ex.StackTrace.ToString()); } finally { if (renderAtlasesGO != null) { MB_Utility.Destroy(renderAtlasesGO); } } yield break; }
internal static void CreateTemporaryTexturesForAtlas(List <MB_TexSet> distinctMaterialTextures, MB3_TextureCombiner combiner, int propIdx, MB3_TextureCombinerPipeline.TexturePipelineData data) { for (int texSetIdx = 0; texSetIdx < data.distinctMaterialTextures.Count; texSetIdx++) { MB_TexSet txs = data.distinctMaterialTextures[texSetIdx]; MeshBakerMaterialTexture matTex = txs.ts[propIdx]; if (matTex.isNull) { //create a small 16 x 16 texture to use in the atlas Color col = data.nonTexturePropertyBlender.GetColorForTemporaryTexture(txs.matsAndGOs.mats[0].mat, data.texPropertyNames[propIdx]); txs.CreateColoredTexToReplaceNull(data.texPropertyNames[propIdx].name, propIdx, data._fixOutOfBoundsUVs, combiner, col); } } }
internal static Texture2D _copyTexturesIntoAtlas(Texture2D[] texToPack, int padding, Rect[] rs, int w, int h, MB3_TextureCombiner combiner) { Texture2D ta = new Texture2D(w, h, TextureFormat.ARGB32, true); MB_Utility.setSolidColor(ta, Color.clear); for (int i = 0; i < rs.Length; i++) { Rect r = rs[i]; Texture2D t = texToPack[i]; Texture2D tmpTex = null; int x = Mathf.RoundToInt(r.x * w); int y = Mathf.RoundToInt(r.y * h); int ww = Mathf.RoundToInt(r.width * w); int hh = Mathf.RoundToInt(r.height * h); if (t.width != ww && t.height != hh) { tmpTex = t = MB_Utility.resampleTexture(t, ww, hh); } ta.SetPixels(x, y, ww, hh, t.GetPixels()); if (tmpTex != null) { MB_Utility.Destroy(tmpTex); } } ta.Apply(); return(ta); }
public Texture2D OnRenderAtlas(MB3_TextureCombiner combiner){ fastRenderer = new MB_TextureCombinerRenderTexture(); _doRenderAtlas = true; Texture2D atlas = fastRenderer.DoRenderAtlas(this.gameObject,width,height,padding,rects,textureSets,indexOfTexSetToRender, isNormalMap, fixOutOfBoundsUVs, combiner, LOG_LEVEL); _doRenderAtlas = false; return atlas; }
internal static void BuildAtlas( AtlasPackingResult packedAtlasRects, List <MB_TexSet> distinctMaterialTextures, int propIdx, int atlasSizeX, int atlasSizeY, Mesh m, List <Material> generatedMats, ShaderTextureProperty property, MB3_TextureCombinerPipeline.TexturePipelineData data, MB3_TextureCombiner combiner, MB2_EditorMethodsInterface textureEditorMethods, MB2_LogLevel LOG_LEVEL) { // Collect vertices and quads for mesh that we will use for the atlas. Debug.Assert(generatedMats.Count == 0, "Previous mats should have been destroyed"); generatedMats.Clear(); List <Vector3> vs = new List <Vector3>(); List <Vector2> uvs = new List <Vector2>(); // One submesh and material per texture that we are packing List <int>[] ts = new List <int> [distinctMaterialTextures.Count]; for (int i = 0; i < ts.Length; i++) { ts[i] = new List <int>(); } MeshBakerMaterialTexture.readyToBuildAtlases = true; GC.Collect(); MB3_TextureCombinerPackerRoot.CreateTemporaryTexturesForAtlas(data.distinctMaterialTextures, combiner, propIdx, data); Rect[] uvRects = packedAtlasRects.rects; for (int texSetIdx = 0; texSetIdx < distinctMaterialTextures.Count; texSetIdx++) { MB_TexSet texSet = distinctMaterialTextures[texSetIdx]; MeshBakerMaterialTexture matTex = texSet.ts[propIdx]; if (LOG_LEVEL >= MB2_LogLevel.trace) { Debug.Log(string.Format("Adding texture {0} to atlas {1} for texSet {2} srcMat {3}", matTex.GetTexName(), property.name, texSetIdx, texSet.matsAndGOs.mats[0].GetMaterialName())); } Rect r = uvRects[texSetIdx]; Texture2D t = matTex.GetTexture2D(); int x = Mathf.RoundToInt(r.x * atlasSizeX); int y = Mathf.RoundToInt(r.y * atlasSizeY); int ww = Mathf.RoundToInt(r.width * atlasSizeX); int hh = Mathf.RoundToInt(r.height * atlasSizeY); r = new Rect(x, y, ww, hh); if (ww == 0 || hh == 0) { Debug.LogError("Image in atlas has no height or width " + r); } DRect samplingRect = texSet.ts[propIdx].GetEncapsulatingSamplingRect(); Debug.Assert(!texSet.ts[propIdx].isNull, string.Format("Adding texture {0} to atlas {1} for texSet {2} srcMat {3}", matTex.GetTexName(), property.name, texSetIdx, texSet.matsAndGOs.mats[0].GetMaterialName())); AtlasPadding padding = packedAtlasRects.padding[texSetIdx]; AddNineSlicedRect(r, padding.leftRight, padding.topBottom, samplingRect.GetRect(), vs, uvs, ts[texSetIdx], t.width, t.height, t.name); Material mt = new Material(Shader.Find("MeshBaker/Unlit/UnlitWithAlpha")); bool isSavingAsANormalMapAssetThatWillBeImported = property.isNormalMap && data._saveAtlasesAsAssets; MBVersion.PipelineType pipelineType = MBVersion.DetectPipeline(); if (pipelineType == MBVersion.PipelineType.URP) { ConfigureMaterial_DefaultPipeline(mt, t, isSavingAsANormalMapAssetThatWillBeImported, LOG_LEVEL); //ConfigureMaterial_URP(mt, t, isSavingAsANormalMapAssetThatWillBeImported, LOG_LEVEL); } else if (pipelineType == MBVersion.PipelineType.HDRP) { ConfigureMaterial_DefaultPipeline(mt, t, isSavingAsANormalMapAssetThatWillBeImported, LOG_LEVEL); } else { ConfigureMaterial_DefaultPipeline(mt, t, isSavingAsANormalMapAssetThatWillBeImported, LOG_LEVEL); } generatedMats.Add(mt); } // Apply to the mesh m.Clear(); m.vertices = vs.ToArray(); m.uv = uvs.ToArray(); m.subMeshCount = ts.Length; for (int i = 0; i < m.subMeshCount; i++) { m.SetIndices(ts[i].ToArray(), MeshTopology.Triangles, i); } MeshBakerMaterialTexture.readyToBuildAtlases = false; }
public IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo, MB3_TextureCombinerPipeline.TexturePipelineData data, MB3_TextureCombiner combiner, AtlasPackingResult packedAtlasRects, Texture2D[] atlases, MB2_EditorMethodsInterface textureEditorMethods, MB2_LogLevel LOG_LEVEL) { Rect[] uvRects = packedAtlasRects.rects; if (data.distinctMaterialTextures.Count == 1 && data._fixOutOfBoundsUVs == false) { if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("Only one image per atlas. Will re-use original texture"); } uvRects = new Rect[1]; uvRects[0] = new Rect(0f, 0f, 1f, 1f); for (int i = 0; i < data.numAtlases; i++) { MeshBakerMaterialTexture 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, dmt.matTilingRect.size); data.resultMaterial.SetTextureOffset(data.texPropertyNames[i].name, dmt.matTilingRect.min); } } else { long estArea = 0; int atlasSizeX = 1; int atlasSizeY = 1; uvRects = null; for (int i = 0; i < data.numAtlases; i++) { //i is an atlas "MainTex", "BumpMap" etc... //----------------------- Texture2D atlas = null; if (!MB3_TextureCombinerPipeline._ShouldWeCreateAtlasForThisProperty(i, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor)) { atlas = null; } else { if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.LogWarning("Beginning loop " + i + " num temporary textures " + combiner._temporaryTextures.Count); } for (int j = 0; j < data.distinctMaterialTextures.Count; j++) { //j is a distinct set of textures one for each of "MainTex", "BumpMap" etc... MB_TexSet txs = data.distinctMaterialTextures[j]; int tWidth = txs.idealWidth; int tHeight = txs.idealHeight; Texture2D tx = txs.ts[i].GetTexture2D(); if (tx == null) { tx = txs.ts[i].t = combiner._createTemporaryTexture(tWidth, tHeight, TextureFormat.ARGB32, true); if (data._considerNonTextureProperties && data.nonTexturePropertyBlender != null) { Color col = data.nonTexturePropertyBlender.GetColorIfNoTexture(txs.matsAndGOs.mats[0].mat, data.texPropertyNames[i]); if (LOG_LEVEL >= MB2_LogLevel.trace) { Debug.Log("Setting texture to solid color " + col); } MB_Utility.setSolidColor(tx, col); } else { Color col = MB3_TextureCombinerNonTextureProperties.GetColorIfNoTexture(data.texPropertyNames[i]); MB_Utility.setSolidColor(tx, col); } } if (progressInfo != null) { progressInfo("Adjusting for scale and offset " + tx, .01f); } if (textureEditorMethods != null) { textureEditorMethods.SetReadWriteFlag(tx, true, true); } tx = GetAdjustedForScaleAndOffset2(txs.ts[i], txs.obUVoffset, txs.obUVscale, data, combiner, LOG_LEVEL); //create a resized copy if necessary if (tx.width != tWidth || tx.height != tHeight) { if (progressInfo != null) { progressInfo("Resizing texture '" + tx + "'", .01f); } if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.LogWarning("Copying and resizing texture " + data.texPropertyNames[i].name + " from " + tx.width + "x" + tx.height + " to " + tWidth + "x" + tHeight); } tx = combiner._resizeTexture((Texture2D)tx, tWidth, tHeight); } txs.ts[i].t = tx; } Texture2D[] texToPack = new Texture2D[data.distinctMaterialTextures.Count]; for (int j = 0; j < data.distinctMaterialTextures.Count; j++) { Texture2D tx = data.distinctMaterialTextures[j].ts[i].GetTexture2D(); estArea += tx.width * tx.height; if (data._considerNonTextureProperties) { //combine the tintColor with the texture tx = combiner._createTextureCopy(tx); data.nonTexturePropertyBlender.TintTextureWithTextureCombiner(tx, data.distinctMaterialTextures[j], data.texPropertyNames[i]); } texToPack[j] = tx; } if (textureEditorMethods != null) { textureEditorMethods.CheckBuildSettings(estArea); } if (Math.Sqrt(estArea) > 3500f) { if (LOG_LEVEL >= MB2_LogLevel.warn) { 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 " + data.texPropertyNames[i].name, .25f); } if (i == 0) { if (progressInfo != null) { progressInfo("Estimated min size of atlases: " + Math.Sqrt(estArea).ToString("F0"), .1f); } if (LOG_LEVEL >= MB2_LogLevel.info) { Debug.Log("Estimated atlas minimum size:" + Math.Sqrt(estArea).ToString("F0")); } if (data.distinctMaterialTextures.Count == 1 && data._fixOutOfBoundsUVs == false) { //don't want to force power of 2 so tiling will still work uvRects = new Rect[1] { new Rect(0f, 0f, 1f, 1f) }; atlas = _copyTexturesIntoAtlas(texToPack, data._atlasPadding, uvRects, texToPack[0].width, texToPack[0].height, combiner); } else { int maxAtlasSize = 4096; uvRects = atlas.PackTextures(texToPack, data._atlasPadding, maxAtlasSize, false); } if (LOG_LEVEL >= MB2_LogLevel.info) { 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: " + data.texPropertyNames[i].name, .1f); } atlas = _copyTexturesIntoAtlas(texToPack, data._atlasPadding, uvRects, atlasSizeX, atlasSizeY, combiner); } } atlases[i] = atlas; //---------------------- if (data._saveAtlasesAsAssets && textureEditorMethods != null) { textureEditorMethods.SaveAtlasToAssetDatabase(atlases[i], data.texPropertyNames[i], i, data.resultMaterial); } data.resultMaterial.SetTextureOffset(data.texPropertyNames[i].name, Vector2.zero); data.resultMaterial.SetTextureScale(data.texPropertyNames[i].name, Vector2.one); combiner._destroyTemporaryTextures(); // need to save atlases before doing this GC.Collect(); } } packedAtlasRects.rects = uvRects; yield break; }
public override IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo, MB3_TextureCombinerPipeline.TexturePipelineData data, MB3_TextureCombiner combiner, AtlasPackingResult packedAtlasRects, Texture2D[] atlases, MB2_EditorMethodsInterface textureEditorMethods, MB2_LogLevel LOG_LEVEL) { Rect[] uvRects = packedAtlasRects.rects; int atlasSizeX = packedAtlasRects.atlasX; int atlasSizeY = packedAtlasRects.atlasY; if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("Generated atlas will be " + atlasSizeX + "x" + atlasSizeY); } for (int propIdx = 0; propIdx < data.numAtlases; propIdx++) { Texture2D atlas = null; ShaderTextureProperty property = data.texPropertyNames[propIdx]; if (!MB3_TextureCombinerPipeline._ShouldWeCreateAtlasForThisProperty(propIdx, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor)) { atlas = null; if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("=== Not creating atlas for " + property.name + " because textures are null and default value parameters are the same."); } } else { if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("=== Creating atlas for " + property.name); } GC.Collect(); CreateTemporaryTexturesForAtlas(data.distinctMaterialTextures, combiner, propIdx, data); //use a jagged array because it is much more efficient in memory Color[][] atlasPixels = new Color[atlasSizeY][]; for (int j = 0; j < atlasPixels.Length; j++) { atlasPixels[j] = new Color[atlasSizeX]; } bool isNormalMap = false; if (property.isNormalMap) { isNormalMap = true; } for (int texSetIdx = 0; texSetIdx < data.distinctMaterialTextures.Count; texSetIdx++) { MB_TexSet texSet = data.distinctMaterialTextures[texSetIdx]; MeshBakerMaterialTexture matTex = texSet.ts[propIdx]; string s = "Creating Atlas '" + property.name + "' texture " + matTex.GetTexName(); if (progressInfo != null) { progressInfo(s, .01f); } if (LOG_LEVEL >= MB2_LogLevel.trace) { Debug.Log(string.Format("Adding texture {0} to atlas {1} for texSet {2} srcMat {3}", matTex.GetTexName(), property.name, texSetIdx, texSet.matsAndGOs.mats[0].GetMaterialName())); } Rect r = uvRects[texSetIdx]; Texture2D t = texSet.ts[propIdx].GetTexture2D(); int x = Mathf.RoundToInt(r.x * atlasSizeX); int y = Mathf.RoundToInt(r.y * atlasSizeY); int ww = Mathf.RoundToInt(r.width * atlasSizeX); int hh = Mathf.RoundToInt(r.height * atlasSizeY); if (ww == 0 || hh == 0) { Debug.LogError("Image in atlas has no height or width " + r); } if (progressInfo != null) { progressInfo(s + " set ReadWrite flag", .01f); } if (textureEditorMethods != null) { textureEditorMethods.SetReadWriteFlag(t, true, true); } if (progressInfo != null) { progressInfo(s + "Copying to atlas: '" + matTex.GetTexName() + "'", .02f); } DRect samplingRect = texSet.ts[propIdx].GetEncapsulatingSamplingRect(); Debug.Assert(!texSet.ts[propIdx].isNull, string.Format("Adding texture {0} to atlas {1} for texSet {2} srcMat {3}", matTex.GetTexName(), property.name, texSetIdx, texSet.matsAndGOs.mats[0].GetMaterialName())); yield return(CopyScaledAndTiledToAtlas(texSet.ts[propIdx], texSet, property, samplingRect, x, y, ww, hh, packedAtlasRects.padding[texSetIdx], atlasPixels, isNormalMap, data, combiner, progressInfo, LOG_LEVEL)); } yield return(data.numAtlases); if (progressInfo != null) { progressInfo("Applying changes to atlas: '" + property.name + "'", .03f); } atlas = new Texture2D(atlasSizeX, atlasSizeY, TextureFormat.ARGB32, true); for (int j = 0; j < atlasPixels.Length; j++) { atlas.SetPixels(0, j, atlasSizeX, 1, atlasPixels[j]); } atlas.Apply(); if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("Saving atlas " + property.name + " w=" + atlas.width + " h=" + atlas.height); } } atlases[propIdx] = atlas; if (progressInfo != null) { progressInfo("Saving atlas: '" + property.name + "'", .04f); } System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); sw.Start(); if (data.resultType == MB2_TextureBakeResults.ResultType.atlas) { SaveAtlasAndConfigureResultMaterial(data, textureEditorMethods, atlases[propIdx], data.texPropertyNames[propIdx], propIdx); } combiner._destroyTemporaryTextures(data.texPropertyNames[propIdx].name); } yield break; }
public IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo, MB3_TextureCombinerPipeline.TexturePipelineData data, MB3_TextureCombiner combiner, AtlasPackingResult packedAtlasRects, Texture2D[] atlases, MB2_EditorMethodsInterface textureEditorMethods, MB2_LogLevel LOG_LEVEL) { Rect[] uvRects = packedAtlasRects.rects; if (uvRects.Length == 1) { if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("Only one image per atlas. Will re-use original texture"); } for (int i = 0; i < data.numAtlases; i++) { MeshBakerMaterialTexture 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, dmt.matTilingRect.size); data.resultMaterial.SetTextureOffset(data.texPropertyNames[i].name, dmt.matTilingRect.min); } } else { int atlasSizeX = packedAtlasRects.atlasX; int atlasSizeY = packedAtlasRects.atlasY; if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("Generated atlas will be " + atlasSizeX + "x" + atlasSizeY); } for (int propIdx = 0; propIdx < data.numAtlases; propIdx++) { Texture2D atlas = null; if (!MB3_TextureCombinerPipeline._ShouldWeCreateAtlasForThisProperty(propIdx, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor)) { atlas = null; if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("=== Not creating atlas for " + data.texPropertyNames[propIdx].name + " because textures are null and default value parameters are the same."); } } else { if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("=== Creating atlas for " + data.texPropertyNames[propIdx].name); } GC.Collect(); //use a jagged array because it is much more efficient in memory Color[][] atlasPixels = new Color[atlasSizeY][]; for (int j = 0; j < atlasPixels.Length; j++) { atlasPixels[j] = new Color[atlasSizeX]; } bool isNormalMap = false; if (data.texPropertyNames[propIdx].isNormalMap) { isNormalMap = true; } for (int texSetIdx = 0; texSetIdx < data.distinctMaterialTextures.Count; texSetIdx++) { string s = "Creating Atlas '" + data.texPropertyNames[propIdx].name + "' texture " + data.distinctMaterialTextures[texSetIdx]; if (progressInfo != null) { progressInfo(s, .01f); } MB_TexSet texSet = data.distinctMaterialTextures[texSetIdx]; if (LOG_LEVEL >= MB2_LogLevel.trace) { Debug.Log(string.Format("Adding texture {0} to atlas {1}", texSet.ts[propIdx].GetTexture2D() == null ? "null" : texSet.ts[propIdx].GetTexName(), data.texPropertyNames[propIdx])); } Rect r = uvRects[texSetIdx]; Texture2D t = texSet.ts[propIdx].GetTexture2D(); int x = Mathf.RoundToInt(r.x * atlasSizeX); int y = Mathf.RoundToInt(r.y * atlasSizeY); int ww = Mathf.RoundToInt(r.width * atlasSizeX); int hh = Mathf.RoundToInt(r.height * atlasSizeY); if (ww == 0 || hh == 0) { Debug.LogError("Image in atlas has no height or width " + r); } if (progressInfo != null) { progressInfo(s + " set ReadWrite flag", .01f); } if (textureEditorMethods != null) { textureEditorMethods.SetReadWriteFlag(t, true, true); } if (progressInfo != null) { progressInfo(s + "Copying to atlas: '" + texSet.ts[propIdx].GetTexName() + "'", .02f); } DRect samplingRect = texSet.ts[propIdx].encapsulatingSamplingRect; yield return(CopyScaledAndTiledToAtlas(texSet.ts[propIdx], texSet, data.texPropertyNames[propIdx], samplingRect, x, y, ww, hh, packedAtlasRects.padding[texSetIdx], atlasPixels, isNormalMap, data, combiner, progressInfo, LOG_LEVEL)); // Debug.Log("after copyScaledAndTiledAtlas"); } yield return(data.numAtlases); if (progressInfo != null) { progressInfo("Applying changes to atlas: '" + data.texPropertyNames[propIdx].name + "'", .03f); } atlas = new Texture2D(atlasSizeX, atlasSizeY, TextureFormat.ARGB32, true); for (int j = 0; j < atlasPixels.Length; j++) { atlas.SetPixels(0, j, atlasSizeX, 1, atlasPixels[j]); } atlas.Apply(); if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("Saving atlas " + data.texPropertyNames[propIdx].name + " w=" + atlas.width + " h=" + atlas.height); } } atlases[propIdx] = atlas; if (progressInfo != null) { progressInfo("Saving atlas: '" + data.texPropertyNames[propIdx].name + "'", .04f); } System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); sw.Start(); 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(); // need to save atlases before doing this } } //data.rectsInAtlas = uvRects; // Debug.Log("finished!"); yield break; }
MB_AtlasesAndRects[] _CreateAtlases(ProgressUpdateDelegate progressInfo, bool saveAtlasesAsAssets = false, MB2_EditorMethodsInterface editorMethods=null){ //validation if (saveAtlasesAsAssets && editorMethods == null){ Debug.LogError("Error in CreateAtlases If saveAtlasesAsAssets = true then editorMethods cannot be null."); return null; } if (saveAtlasesAsAssets && !Application.isEditor){ Debug.LogError("Error in CreateAtlases If saveAtlasesAsAssets = true it must be called from the Unity Editor."); return null; } MB2_ValidationLevel vl = Application.isPlaying ? MB2_ValidationLevel.quick : MB2_ValidationLevel.robust; if (!DoCombinedValidate(this, MB_ObjsToCombineTypes.dontCare, editorMethods, vl)){ return null; } if (_doMultiMaterial && !_ValidateResultMaterials()){ return null; } else if (!_doMultiMaterial){ if (_resultMaterial == null){ Debug.LogError("Combined Material is null please create and assign a result material."); return null; } Shader targShader = _resultMaterial.shader; 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 && m.shader != targShader){ Debug.LogWarning("Game object " + objsToMesh[i] + " does not use shader " + targShader + " it may not have the required textures. If not 2x2 clear textures will be generated."); } } } } 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. Can't build atlases"); return null; } } } MB3_TextureCombiner combiner = new MB3_TextureCombiner(); combiner.LOG_LEVEL = LOG_LEVEL; combiner.atlasPadding = _atlasPadding; combiner.maxAtlasSize = _maxAtlasSize; combiner.customShaderPropNames = _customShaderProperties; combiner.fixOutOfBoundsUVs = _fixOutOfBoundsUVs; combiner.maxTilingBakeSize = _maxTilingBakeSize; combiner.packingAlgorithm = _packingAlgorithm; combiner.meshBakerTexturePackerForcePowerOfTwo = _meshBakerTexturePackerForcePowerOfTwo; combiner.resizePowerOfTwoTextures = _resizePowerOfTwoTextures; combiner.saveAtlasesAsAssets = saveAtlasesAsAssets; // if editor analyse meshes and suggest treatment if (!Application.isPlaying){ Material[] rms; if (_doMultiMaterial){ rms = new Material[resultMaterials.Length]; for (int i = 0; i < rms.Length; i++) rms[i] = resultMaterials[i].combinedMaterial; } else { rms = new Material[1]; rms[0] = _resultMaterial; } combiner.SuggestTreatment(objsToMesh, rms, combiner.customShaderPropNames); } //initialize structure to store results int numResults = 1; if (_doMultiMaterial) numResults = resultMaterials.Length; MB_AtlasesAndRects[] resultAtlasesAndRects = new MB_AtlasesAndRects[numResults]; for (int i = 0; i < resultAtlasesAndRects.Length; i++){ resultAtlasesAndRects[i] = new MB_AtlasesAndRects(); } //Do the material combining. for (int i = 0; i < resultAtlasesAndRects.Length; i++){ Material resMatToPass = null; List<Material> sourceMats = null; if (_doMultiMaterial) { sourceMats = resultMaterials[i].sourceMaterials; resMatToPass = resultMaterials[i].combinedMaterial; } else { resMatToPass = _resultMaterial; } Debug.Log("Creating atlases for result material " + resMatToPass); if(!combiner.CombineTexturesIntoAtlases(progressInfo, resultAtlasesAndRects[i], resMatToPass, objsToMesh, sourceMats, editorMethods)){ return null; } } //Save the results textureBakeResults.combinedMaterialInfo = resultAtlasesAndRects; textureBakeResults.doMultiMaterial = _doMultiMaterial; textureBakeResults.resultMaterial = _resultMaterial; textureBakeResults.resultMaterials = resultMaterials; textureBakeResults.fixOutOfBoundsUVs = combiner.fixOutOfBoundsUVs; unpackMat2RectMap(textureBakeResults); //set the texture bake resultAtlasesAndRects on the Mesh Baker component if it exists MB3_MeshBakerCommon[] mb = GetComponentsInChildren<MB3_MeshBakerCommon>(); for (int i = 0; i < mb.Length; i++){ mb[i].textureBakeResults = textureBakeResults; } if (LOG_LEVEL >= MB2_LogLevel.info) Debug.Log("Created Atlases"); return resultAtlasesAndRects; }
public override IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo, MB3_TextureCombinerPipeline.TexturePipelineData data, MB3_TextureCombiner combiner, AtlasPackingResult packedAtlasRects, Texture2D[] atlases, MB2_EditorMethodsInterface textureEditorMethods, MB2_LogLevel LOG_LEVEL) { Debug.Assert(!data.OnlyOneTextureInAtlasReuseTextures()); 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 (!MB3_TextureCombinerPipeline._ShouldWeCreateAtlasForThisProperty(propIdx, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor)) { atlas = null; } else { if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.LogWarning("Beginning loop " + propIdx + " num temporary textures " + combiner._getNumTemporaryTextures()); } MB3_TextureCombinerPackerRoot.CreateTemporaryTexturesForAtlas(data.distinctMaterialTextures, combiner, propIdx, data); Texture2D[] texToPack = new Texture2D[data.distinctMaterialTextures.Count]; for (int texSetIdx = 0; texSetIdx < data.distinctMaterialTextures.Count; texSetIdx++) { MB_TexSet 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, LOG_LEVEL); //create a resized copy if necessary if (tx.width != tWidth || tx.height != tHeight) { if (progressInfo != null) { progressInfo("Resizing texture '" + tx + "'", .01f); } if (LOG_LEVEL >= MB2_LogLevel.debug) { 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) { if (LOG_LEVEL >= MB2_LogLevel.warn) { 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); } if (LOG_LEVEL >= MB2_LogLevel.info) { Debug.Log("Estimated atlas minimum size:" + Math.Sqrt(estArea).ToString("F0")); } int maxAtlasSize = 4096; uvRects = atlas.PackTextures(texToPack, data._atlasPadding, maxAtlasSize, false); if (LOG_LEVEL >= MB2_LogLevel.info) { 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; }
internal static IEnumerator CopyScaledAndTiledToAtlas(MeshBakerMaterialTexture source, MB_TexSet sourceMaterial, ShaderTextureProperty shaderPropertyName, DRect srcSamplingRect, int targX, int targY, int targW, int targH, AtlasPadding padding, Color[][] atlasPixels, bool isNormalMap, MB3_TextureCombinerPipeline.TexturePipelineData data, MB3_TextureCombiner combiner, ProgressUpdateDelegate progressInfo = null, MB2_LogLevel LOG_LEVEL = MB2_LogLevel.info) { //HasFinished = false; Texture2D t = source.GetTexture2D(); if (LOG_LEVEL >= MB2_LogLevel.debug) { 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); } // Debug.Log("copyandscaledatlas finished too!"); //HasFinished = true; yield break; }
//posibilities // using fixOutOfBoundsUVs or not // public static void ConfigureMutiMaterialsFromObjsToCombine(MB3_TextureBaker mom, SerializedProperty resultMaterials, SerializedObject textureBaker) { if (mom.GetObjectsToCombine().Count == 0) { Debug.LogError("You need to add some objects to combine before building the multi material list."); return; } if (resultMaterials.arraySize > 0) { Debug.LogError("You already have some source to combined material mappings configured. You must remove these before doing this operation."); return; } if (mom.textureBakeResults == null) { Debug.LogError("Texture Bake Result asset must be set before using this operation."); return; } Dictionary <MultiMatSubmeshInfo, List <List <Material> > > shader2Material_map = new Dictionary <MultiMatSubmeshInfo, List <List <Material> > >(); Dictionary <Material, Mesh> obUVobject2mesh_map = new Dictionary <Material, Mesh>(); //validate that the objects to be combined are valid for (int i = 0; i < mom.GetObjectsToCombine().Count; i++) { GameObject go = mom.GetObjectsToCombine()[i]; if (go == null) { Debug.LogError("Null object in list of objects to combine at position " + i); return; } Renderer r = go.GetComponent <Renderer>(); if (r == null || (!(r is MeshRenderer) && !(r is SkinnedMeshRenderer))) { Debug.LogError("GameObject at position " + i + " in list of objects to combine did not have a renderer"); return; } if (r.sharedMaterial == null) { Debug.LogError("GameObject at position " + i + " in list of objects to combine has a null material"); return; } } //first pass put any meshes with obUVs on their own submesh if not fixing OB uvs if (mom.doMultiMaterialSplitAtlasesIfOBUVs) { for (int i = 0; i < mom.GetObjectsToCombine().Count; i++) { GameObject go = mom.GetObjectsToCombine()[i]; Mesh m = MB_Utility.GetMesh(go); MB_Utility.MeshAnalysisResult dummyMar = new MB_Utility.MeshAnalysisResult(); Renderer r = go.GetComponent <Renderer>(); for (int j = 0; j < r.sharedMaterials.Length; j++) { if (MB_Utility.hasOutOfBoundsUVs(m, ref dummyMar, j)) { if (!obUVobject2mesh_map.ContainsKey(r.sharedMaterials[j])) { Debug.LogWarning("Object " + go + " submesh " + j + " uses UVs outside the range 0,0..1,1 to generate tiling. This object has been mapped to its own submesh in the combined mesh. It can share a submesh with other objects that use different materials if you use the fix out of bounds UVs feature which will bake the tiling"); obUVobject2mesh_map.Add(r.sharedMaterials[j], m); } } } } } //second pass put other materials without OB uvs in a shader to material map for (int i = 0; i < mom.GetObjectsToCombine().Count; i++) { Renderer r = mom.GetObjectsToCombine()[i].GetComponent <Renderer>(); for (int j = 0; j < r.sharedMaterials.Length; j++) { if (!obUVobject2mesh_map.ContainsKey(r.sharedMaterials[j])) { //if not already added if (r.sharedMaterials[j] == null) { continue; } List <List <Material> > binsOfMatsThatUseShader = null; MultiMatSubmeshInfo newKey = new MultiMatSubmeshInfo(r.sharedMaterials[j].shader, r.sharedMaterials[j]); if (!shader2Material_map.TryGetValue(newKey, out binsOfMatsThatUseShader)) { binsOfMatsThatUseShader = new List <List <Material> >(); binsOfMatsThatUseShader.Add(new List <Material>()); shader2Material_map.Add(newKey, binsOfMatsThatUseShader); } if (!binsOfMatsThatUseShader[0].Contains(r.sharedMaterials[j])) { binsOfMatsThatUseShader[0].Add(r.sharedMaterials[j]); } } } } int numResMats = shader2Material_map.Count; //third pass for each shader grouping check how big the atlas would be and group into bins that would fit in an atlas if (mom.doMultiMaterialSplitAtlasesIfTooBig) { if (mom.packingAlgorithm == MB2_PackingAlgorithmEnum.UnitysPackTextures) { Debug.LogWarning("Unity texture packer does not support splitting atlases if too big. Atlases will not be split."); } else { numResMats = 0; foreach (MultiMatSubmeshInfo sh in shader2Material_map.Keys) { List <List <Material> > binsOfMatsThatUseShader = shader2Material_map[sh]; List <Material> allMatsThatUserShader = binsOfMatsThatUseShader[0];//at this point everything is in the same list binsOfMatsThatUseShader.RemoveAt(0); MB3_TextureCombiner combiner = mom.CreateAndConfigureTextureCombiner(); combiner.saveAtlasesAsAssets = false; if (allMatsThatUserShader.Count > 1) { combiner.fixOutOfBoundsUVs = mom.fixOutOfBoundsUVs; } else { combiner.fixOutOfBoundsUVs = false; } // Do the texture pack List <AtlasPackingResult> packingResults = new List <AtlasPackingResult>(); Material tempMat = new Material(sh.shader); combiner.CombineTexturesIntoAtlases(null, null, tempMat, mom.GetObjectsToCombine(), allMatsThatUserShader, null, packingResults, true); for (int i = 0; i < packingResults.Count; i++) { List <MatsAndGOs> matsData = (List <MatsAndGOs>)packingResults[i].data; List <Material> mats = new List <Material>(); for (int j = 0; j < matsData.Count; j++) { for (int kk = 0; kk < matsData[j].mats.Count; kk++) { if (!mats.Contains(matsData[j].mats[kk].mat)) { mats.Add(matsData[j].mats[kk].mat); } } } binsOfMatsThatUseShader.Add(mats); } numResMats += binsOfMatsThatUseShader.Count; } } } //build the result materials if (shader2Material_map.Count == 0 && obUVobject2mesh_map.Count == 0) { Debug.LogError("Found no materials in list of objects to combine"); } mom.resultMaterials = new MB_MultiMaterial[numResMats + obUVobject2mesh_map.Count]; string pth = AssetDatabase.GetAssetPath(mom.textureBakeResults); string baseName = Path.GetFileNameWithoutExtension(pth); string folderPath = pth.Substring(0, pth.Length - baseName.Length - 6); int k = 0; foreach (MultiMatSubmeshInfo sh in shader2Material_map.Keys) { foreach (List <Material> matsThatUse in shader2Material_map[sh]) { MB_MultiMaterial mm = mom.resultMaterials[k] = new MB_MultiMaterial(); mm.sourceMaterials = matsThatUse; if (mm.sourceMaterials.Count == 1) { mm.considerMeshUVs = false; } else { mm.considerMeshUVs = mom.fixOutOfBoundsUVs; } string matName = folderPath + baseName + "-mat" + k + ".mat"; Material newMat = new Material(Shader.Find("Diffuse")); if (matsThatUse.Count > 0 && matsThatUse[0] != null) { MB3_TextureBaker.ConfigureNewMaterialToMatchOld(newMat, matsThatUse[0]); } AssetDatabase.CreateAsset(newMat, matName); mm.combinedMaterial = (Material)AssetDatabase.LoadAssetAtPath(matName, typeof(Material)); k++; } } foreach (Material m in obUVobject2mesh_map.Keys) { MB_MultiMaterial mm = mom.resultMaterials[k] = new MB_MultiMaterial(); mm.sourceMaterials = new List <Material>(); mm.sourceMaterials.Add(m); mm.considerMeshUVs = false; string matName = folderPath + baseName + "-mat" + k + ".mat"; Material newMat = new Material(Shader.Find("Diffuse")); MB3_TextureBaker.ConfigureNewMaterialToMatchOld(newMat, m); AssetDatabase.CreateAsset(newMat, matName); mm.combinedMaterial = (Material)AssetDatabase.LoadAssetAtPath(matName, typeof(Material)); k++; } MBVersionEditor.UpdateIfDirtyOrScript(textureBaker); }
internal static bool ConvertTexturesToReadableFormat(TexturePropertyData texturePropertyData, MB_AtlasesAndRects[] resultAtlasesAndRectSlices, bool[] hasTexForProperty, List <ShaderTextureProperty> textureShaderProperties, MB3_TextureCombiner combiner, MB2_LogLevel logLevel, List <Texture2D> createdTemporaryTextureAssets, MB2_EditorMethodsInterface textureEditorMethods) { for (int propIdx = 0; propIdx < hasTexForProperty.Length; propIdx++) { if (!hasTexForProperty[propIdx]) { continue; } TextureFormat format = texturePropertyData.formats[propIdx]; if (!textureEditorMethods.TextureImporterFormatExistsForTextureFormat(format)) { Debug.LogError("Could not find target importer format matching " + format); return(false); } int numSlices = resultAtlasesAndRectSlices.Length; int targetWidth = (int)texturePropertyData.sizes[propIdx].x; int targetHeight = (int)texturePropertyData.sizes[propIdx].y; for (int sliceIdx = 0; sliceIdx < numSlices; sliceIdx++) { Texture2D sliceTex = resultAtlasesAndRectSlices[sliceIdx].atlases[propIdx]; Debug.Assert(sliceTex != null, "sliceIdx " + sliceIdx + " " + propIdx); if (sliceTex != null) { if (!MBVersion.IsTextureReadable(sliceTex)) { textureEditorMethods.SetReadWriteFlag(sliceTex, true, true); } bool isAsset = textureEditorMethods.IsAnAsset(sliceTex); if (logLevel >= MB2_LogLevel.trace) { Debug.Log("Considering format of texture: " + sliceTex + " format:" + sliceTex.format); } if ((sliceTex.width != targetWidth || sliceTex.height != targetHeight) || (!isAsset && sliceTex.format != format)) { // Do this the horrible hard way. It is only possible to resize textures in TrueColor formats, // And only possible to switch formats using the Texture importer. // Create a resized temporary texture asset in ARGB32 format. Then set its texture format and reimport resultAtlasesAndRectSlices[sliceIdx].atlases[propIdx] = textureEditorMethods.CreateTemporaryAssetCopy(textureShaderProperties[propIdx], sliceTex, targetWidth, targetHeight, format, logLevel); createdTemporaryTextureAssets.Add(resultAtlasesAndRectSlices[sliceIdx].atlases[propIdx]); } else if (sliceTex.format != format) { textureEditorMethods.ConvertTextureFormat_PlatformOverride(sliceTex, format, textureShaderProperties[propIdx].isNormalMap); } } else { } if (resultAtlasesAndRectSlices[sliceIdx].atlases[propIdx].format != format) { Debug.LogError("Could not convert texture to format " + format + ". This can happen if the target build platform in build settings does not support textures in this format." + " It may be necessary to switch the build platform in order to build texture arrays in this format."); return(false); } } } return(true); }