public MB3_TextureCombinerMerging(bool considerNonTextureProps, MB3_TextureCombinerNonTextureProperties resultMaterialTexBlender, bool fixObUVs, MB2_LogLevel logLevel) { LOG_LEVEL = logLevel; _considerNonTextureProperties = considerNonTextureProps; resultMaterialTextureBlender = resultMaterialTexBlender; fixOutOfBoundsUVs = fixObUVs; }
// The two texture sets are equal if they are using the same // textures/color properties for each map and have the same // tiling for each of those color properties internal bool IsEqual(object obj, bool fixOutOfBoundsUVs, MB3_TextureCombinerNonTextureProperties resultMaterialTextureBlender) { if (!(obj is MB_TexSet)) { return(false); } MB_TexSet other = (MB_TexSet)obj; if (other.ts.Length != ts.Length) { return(false); } else { for (int i = 0; i < ts.Length; i++) { if (ts[i].matTilingRect != other.ts[i].matTilingRect) { return(false); } if (!ts[i].AreTexturesEqual(other.ts[i])) { return(false); } if (!resultMaterialTextureBlender.NonTexturePropertiesAreEqual(matsAndGOs.mats[0].mat, other.matsAndGOs.mats[0].mat)) { return(false); } } //IMPORTANT don't use Vector2 != Vector2 because it is only acurate to about 5 decimal places //this can lead to tiled rectangles that can't accept rectangles. if (fixOutOfBoundsUVs && (obUVoffset.x != other.obUVoffset.x || obUVoffset.y != other.obUVoffset.y)) { return(false); } if (fixOutOfBoundsUVs && (obUVscale.x != other.obUVscale.x || obUVscale.y != other.obUVscale.y)) { return(false); } return(true); } }
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; }
public bool AllTexturesAreSameForMerge(MB_TexSet other, bool considerNonTextureProperties, MB3_TextureCombinerNonTextureProperties resultMaterialTextureBlender) { if (other.ts.Length != ts.Length) { return false; } else { if (!other.allTexturesUseSameMatTiling || !allTexturesUseSameMatTiling) { return false; } // must use same set of textures int idxOfFirstNoneNull = -1; for (int i = 0; i < ts.Length; i++) { if (!ts[i].AreTexturesEqual(other.ts[i])) return false; if (idxOfFirstNoneNull == -1 && !ts[i].isNull) { idxOfFirstNoneNull = i; } if (considerNonTextureProperties) { if (!resultMaterialTextureBlender.NonTexturePropertiesAreEqual(matsAndGOs.mats[0].mat, other.matsAndGOs.mats[0].mat)) { return false; } } } if (idxOfFirstNoneNull != -1) { //check that all textures are the same. Have already checked all tiling is same for (int i = 0; i < ts.Length; i++) { if (!ts[i].AreTexturesEqual(other.ts[i])) { return false; } } } return true; } }
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 NonTexturePropertiesBlendProps(MB3_TextureCombinerNonTextureProperties textureProperties, TextureBlender resultMats) { resultMaterialTextureBlender = resultMats; _textureProperties = textureProperties; }
public NonTexturePropertiesDontBlendProps(MB3_TextureCombinerNonTextureProperties textureProperties) { _textureProperties = textureProperties; }
public bool AllTexturesAreSameForMerge(MB_TexSet other, /*bool considerTintColor*/ bool considerNonTextureProperties, MB3_TextureCombinerNonTextureProperties resultMaterialTextureBlender) { if (other.ts.Length != ts.Length) { return(false); } else { if (!other.allTexturesUseSameMatTiling || !allTexturesUseSameMatTiling) { return(false); } // must use same set of textures int idxOfFirstNoneNull = -1; for (int i = 0; i < ts.Length; i++) { if (!ts[i].AreTexturesEqual(other.ts[i])) { return(false); } if (idxOfFirstNoneNull == -1 && !ts[i].isNull) { idxOfFirstNoneNull = i; } if (considerNonTextureProperties) { if (resultMaterialTextureBlender != null) { if (!resultMaterialTextureBlender.NonTexturePropertiesAreEqual(matsAndGOs.mats[0].mat, other.matsAndGOs.mats[0].mat)) { return(false); } } } } if (idxOfFirstNoneNull != -1) { //check that all textures are the same. Have already checked all tiling is same for (int i = 0; i < ts.Length; i++) { if (!ts[i].AreTexturesEqual(other.ts[i])) { return(false); } } //========================================================= // OLD check less strict //When comparting two sets of textures (main, bump, spec ...) A and B that have different scales & offsets.They can share if: // - the scales of each texPropertyName (main, bump ...) are the same ratio: ASmain / BSmain = ASbump / BSbump = ASspec / BSspec // - the offset of A to B in uv space is the same for each texPropertyName: // offset = final - initial = OA / SB - OB must be the same /* * MeshBakerMaterialTexture ma = ts[idxOfFirstNoneNull]; * MeshBakerMaterialTexture mb = other.ts[idxOfFirstNoneNull]; * //construct a rect that will ratio and offset * DRect r1 = new DRect( (ma.matTilingRect.x / mb.matTilingRect.width - mb.matTilingRect.x), * (ma.matTilingRect.y / mb.matTilingRect.height - mb.matTilingRect.y), * (mb.matTilingRect.width / ma.matTilingRect.width), * (mb.matTilingRect.height / ma.matTilingRect.height)); * for (int i = 0; i < ts.Length; i++) * { * if (ts[i].t != null) * { * ma = ts[i]; * mb = other.ts[i]; * DRect r2 = new DRect( (ma.matTilingRect.x / mb.matTilingRect.width - mb.matTilingRect.x), * (ma.matTilingRect.y / mb.matTilingRect.height - mb.matTilingRect.y), * (mb.matTilingRect.width / ma.matTilingRect.width), * (mb.matTilingRect.height / ma.matTilingRect.height)); * if (Math.Abs(r2.x - r1.x) > 10e-10f) return false; * if (Math.Abs(r2.y - r1.y) > 10e-10f) return false; * if (Math.Abs(r2.width - r1.width) > 10e-10f) return false; * if (Math.Abs(r2.height - r1.height) > 10e-10f) return false; * } * } */ } return(true); } }
public MB3_TextureCombinerMerging(bool considerNonTextureProps, MB3_TextureCombinerNonTextureProperties resultMaterialTexBlender, bool fixObUVs) { _considerNonTextureProperties = considerNonTextureProps; resultMaterialTextureBlender = resultMaterialTexBlender; fixOutOfBoundsUVs = fixObUVs; }