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); }
// 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); }
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; }
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; }
/// <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); }
/// <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); }