public void CalcMatAndUVSamplingRects() { if (allTexturesUseSameMatTiling) { DRect matTiling = new DRect(0f, 0f, 1f, 1f); for (int propIdx = 0; propIdx < ts.Length; propIdx++) { if (!ts[propIdx].isNull) { matTiling = ts[propIdx].matTilingRect; } } for (int matIdx = 0; matIdx < matsAndGOs.mats.Count; matIdx++) { matsAndGOs.mats[matIdx].materialTiling = matTiling; matsAndGOs.mats[matIdx].samplingRectMatAndUVTiling = MB3_UVTransformUtility.CombineTransforms(ref matsAndGOs.mats[matIdx].obUVRectIfTilingSame, ref matTiling); //MB3_TextureCombiner.GetSourceSamplingRect(ts[matIdx], obUVoffset, obUVscale); } } else { // material tiling is different for each texture property // in this case we set the material tiling to 1 here for (int matIdx = 0; matIdx < matsAndGOs.mats.Count; matIdx++) { DRect matTiling = new DRect(0f, 0f, 1f, 1f); matsAndGOs.mats[matIdx].materialTiling = matTiling; matsAndGOs.mats[matIdx].samplingRectMatAndUVTiling = MB3_UVTransformUtility.CombineTransforms(ref matsAndGOs.mats[matIdx].obUVRectIfTilingSame, ref matTiling); //MB3_TextureCombiner.GetSourceSamplingRect(ts[matIdx], obUVoffset, obUVscale); } } }
/* * public class SamplingRectEnclosesComparer : IComparer<MatAndTransformToMerged> * { * public int Compare(MatAndTransformToMerged x, MatAndTransformToMerged y) * { * if (x.samplingRectMatAndUVTiling.Equals(y.samplingRectMatAndUVTiling)) * { * return 0; * } * else if (x.samplingRectMatAndUVTiling.Encloses(y.samplingRectMatAndUVTiling)) * { * return -1; * } * else * { * return 1; * } * } * } */ public static Rect BuildTransformMeshUV2AtlasRectB(bool considerMeshUVs, Rect _atlasRect, //this is uvRect in combined Atlas Rect _obUVRect, Rect _sourceMaterialTiling, Rect _encapsulatingRect) { DRect atlasRect = new DRect(_atlasRect); DRect obUVRect; if (considerMeshUVs) { obUVRect = new DRect(_obUVRect); //this is the uvRect in src mesh } else { obUVRect = new DRect(0.0, 0.0, 1.0, 1.0); } DRect sourceMaterialTiling = new DRect(_sourceMaterialTiling); DRect encapsulatingRectMatAndUVTiling = new DRect(_encapsulatingRect); DRect encapsulatingRectMatAndUVTilingInverse = MB3_UVTransformUtility.InverseTransform(ref encapsulatingRectMatAndUVTiling); DRect toNormalizedUVs = MB3_UVTransformUtility.InverseTransform(ref obUVRect); DRect meshFullSamplingRect = MB3_UVTransformUtility.CombineTransforms(ref obUVRect, ref sourceMaterialTiling); DRect shiftToFitInEncapsulating = MB3_UVTransformUtility.GetShiftTransformToFitBinA(ref encapsulatingRectMatAndUVTiling, ref meshFullSamplingRect); meshFullSamplingRect = MB3_UVTransformUtility.CombineTransforms(ref meshFullSamplingRect, ref shiftToFitInEncapsulating); //transform between full sample rect and encapsulating rect DRect relativeTrans = MB3_UVTransformUtility.CombineTransforms(ref meshFullSamplingRect, ref encapsulatingRectMatAndUVTilingInverse); // [transform] = [toNormalizedUVs][relativeTrans][uvSubRectInAtlas] DRect trans = MB3_UVTransformUtility.CombineTransforms(ref toNormalizedUVs, ref relativeTrans); trans = MB3_UVTransformUtility.CombineTransforms(ref trans, ref atlasRect); Rect rr = trans.GetRect(); return(rr); /* * Debug.Log("toNormalizedUVs " + toNormalizedUVs); * Debug.Log("relativeTrans " + relativeTrans); * Debug.Log("atlasRect " + atlasRect); * Debug.Log("trans " + trans); * Debug.Log("srcMatTiling " + sourceMaterialTiling); * Debug.Log("obUVRect" + obUVRect); * Debug.Log("samplingRectMatAndUVTiling" + encapsulatingRectMatAndUVTiling); */ }
public void AssignInitialValuesForMaterialTilingAndSamplingRectMatAndUVTiling(bool allTexturesUseSameMatTiling, DRect matTiling) { if (allTexturesUseSameMatTiling) { materialTiling = matTiling; } else { materialTiling = new DRect(0f, 0f, 1f, 1f); } DRect tmpMatTiling = materialTiling; DRect obUVrect = obUVRectIfTilingSame; samplingRectMatAndUVTiling = MB3_UVTransformUtility.CombineTransforms(ref obUVrect, ref tmpMatTiling); }
public void DrawRectsToMergeGizmos(Color encC, Color innerC) { DRect r = ts[0].GetEncapsulatingSamplingRect(); r.Expand(.05f); Gizmos.color = encC; Gizmos.DrawWireCube(r.center.GetVector2(), r.size); for (int i = 0; i < matsAndGOs.mats.Count; i++) { DRect rr = matsAndGOs.mats[i].samplingRectMatAndUVTiling; DRect trans = MB3_UVTransformUtility.GetShiftTransformToFitBinA(ref r, ref rr); Vector2 xy = MB3_UVTransformUtility.TransformPoint(ref trans, rr.min); rr.x = xy.x; rr.y = xy.y; //Debug.Log("r " + r + " rr" + rr); Gizmos.color = innerC; Gizmos.DrawWireCube(rr.center.GetVector2(), rr.size); } }
//assumes all materials use the same obUVrects. internal void CalcInitialFullSamplingRects(bool fixOutOfBoundsUVs) { DRect validFullSamplingRect = new Core.DRect(0, 0, 1, 1); if (fixOutOfBoundsUVs) { validFullSamplingRect = obUVrect; } for (int propIdx = 0; propIdx < ts.Length; propIdx++) { if (!ts[propIdx].isNull) { DRect matTiling = ts[propIdx].matTilingRect; DRect ruv; if (fixOutOfBoundsUVs) { ruv = obUVrect; } else { ruv = new DRect(0.0, 0.0, 1.0, 1.0); } ts[propIdx].SetEncapsulatingSamplingRect(this, MB3_UVTransformUtility.CombineTransforms(ref ruv, ref matTiling)); validFullSamplingRect = ts[propIdx].GetEncapsulatingSamplingRect(); } } //if some of the textures were null make them match the sampling of one of the other textures for (int propIdx = 0; propIdx < ts.Length; propIdx++) { if (ts[propIdx].isNull) { ts[propIdx].SetEncapsulatingSamplingRect(this, validFullSamplingRect); } } }
public void MergeOverlappingDistinctMaterialTexturesAndCalcMaterialSubrects(List <MB_TexSet> distinctMaterialTextures) { if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("MergeOverlappingDistinctMaterialTexturesAndCalcMaterialSubrects num atlas rects" + distinctMaterialTextures.Count); } int numMerged = 0; // IMPORTANT: Note that the verts stored in the mesh are NOT Normalized UV Coords. They are normalized * [UVTrans]. To get normalized UV // coords we must multiply them by [invUVTrans]. Need to do this to the verts in the mesh before we do any transforms with them. // Also check that all textures use same tiling. This is a prerequisite for merging. // Mark MB3_TexSet that are mergable (allTexturesUseSameMatTiling) for (int i = 0; i < distinctMaterialTextures.Count; i++) { MB_TexSet tx = distinctMaterialTextures[i]; int idxOfFirstNotNull = -1; bool allAreSame = true; DRect firstRect = new DRect(); for (int propIdx = 0; propIdx < tx.ts.Length; propIdx++) { if (idxOfFirstNotNull != -1) { if (!tx.ts[propIdx].isNull && firstRect != tx.ts[propIdx].matTilingRect) { allAreSame = false; } } else if (!tx.ts[propIdx].isNull) { idxOfFirstNotNull = propIdx; firstRect = tx.ts[propIdx].matTilingRect; } } if (LOG_LEVEL >= MB2_LogLevel.debug || LOG_LEVEL_TRACE_MERGE_MAT_SUBRECTS == true) { if (allAreSame) { Debug.LogFormat("TextureSet {0} allTexturesUseSameMatTiling = {1}", i, allAreSame); } else { Debug.Log(string.Format("Textures in material(s) do not all use the same material tiling. This set of textures will not be considered for merge: {0} ", tx.GetDescription())); } } if (allAreSame) { tx.SetAllTexturesUseSameMatTilingTrue(); } } for (int i = 0; i < distinctMaterialTextures.Count; i++) { MB_TexSet tx = distinctMaterialTextures[i]; for (int matIdx = 0; matIdx < tx.matsAndGOs.mats.Count; matIdx++) { if (tx.matsAndGOs.gos.Count > 0) { tx.matsAndGOs.mats[matIdx].objName = tx.matsAndGOs.gos[0].name; } else if (tx.ts[0] != null) { tx.matsAndGOs.mats[matIdx].objName = string.Format("[objWithTx:{0} atlasBlock:{1} matIdx{2}]", tx.ts[0].GetTexName(), i, matIdx); } else { tx.matsAndGOs.mats[matIdx].objName = string.Format("[objWithTx:{0} atlasBlock:{1} matIdx{2}]", "Unknown", i, matIdx); } } tx.CalcInitialFullSamplingRects(fixOutOfBoundsUVs); tx.CalcMatAndUVSamplingRects(); } _HasBeenInitialized = true; // need to calculate the srcSampleRect for the complete tiling in the atlas // for each material need to know what the subrect would be in the atlas if material UVRect was 0,0,1,1 and Merged uvRect was full tiling List <int> MarkedForDeletion = new List <int>(); for (int i = 0; i < distinctMaterialTextures.Count; i++) { MB_TexSet tx2 = distinctMaterialTextures[i]; for (int j = i + 1; j < distinctMaterialTextures.Count; j++) { MB_TexSet tx1 = distinctMaterialTextures[j]; if (tx1.AllTexturesAreSameForMerge(tx2, _considerNonTextureProperties, resultMaterialTextureBlender)) { double accumulatedAreaCombined = 0f; double accumulatedAreaNotCombined = 0f; DRect encapsulatingRectMerged = new DRect(); int idxOfFirstNotNull = -1; for (int propIdx = 0; propIdx < tx2.ts.Length; propIdx++) { if (!tx2.ts[propIdx].isNull) { if (idxOfFirstNotNull == -1) { idxOfFirstNotNull = propIdx; } } } DRect encapsulatingRect1 = new DRect(); DRect encapsulatingRect2 = new DRect(); if (idxOfFirstNotNull != -1) { // only in here if all properties use the same tiling so don't need to worry about which propIdx we are dealing with //Get the rect that encapsulates all material and UV tiling for materials and meshes in tx1 encapsulatingRect1 = tx1.matsAndGOs.mats[0].samplingRectMatAndUVTiling; for (int matIdx = 1; matIdx < tx1.matsAndGOs.mats.Count; matIdx++) { DRect tmpSsamplingRectMatAndUVTilingTx1 = tx1.matsAndGOs.mats[matIdx].samplingRectMatAndUVTiling; encapsulatingRect1 = MB3_UVTransformUtility.GetEncapsulatingRectShifted(ref encapsulatingRect1, ref tmpSsamplingRectMatAndUVTilingTx1); } //same for tx2 encapsulatingRect2 = tx2.matsAndGOs.mats[0].samplingRectMatAndUVTiling; for (int matIdx = 1; matIdx < tx2.matsAndGOs.mats.Count; matIdx++) { DRect tmpSsamplingRectMatAndUVTilingTx2 = tx2.matsAndGOs.mats[matIdx].samplingRectMatAndUVTiling; encapsulatingRect2 = MB3_UVTransformUtility.GetEncapsulatingRectShifted(ref encapsulatingRect2, ref tmpSsamplingRectMatAndUVTilingTx2); } encapsulatingRectMerged = MB3_UVTransformUtility.GetEncapsulatingRectShifted(ref encapsulatingRect1, ref encapsulatingRect2); accumulatedAreaCombined += encapsulatingRectMerged.width * encapsulatingRectMerged.height; accumulatedAreaNotCombined += encapsulatingRect1.width * encapsulatingRect1.height + encapsulatingRect2.width * encapsulatingRect2.height; } else { encapsulatingRectMerged = new DRect(0f, 0f, 1f, 1f); } //the distinct material textures may overlap. //if the area of these rectangles combined is less than the sum of these areas of these rectangles then merge these distinctMaterialTextures if (accumulatedAreaCombined < accumulatedAreaNotCombined) { // merge tx2 into tx1 numMerged++; StringBuilder sb = null; if (LOG_LEVEL >= MB2_LogLevel.info) { sb = new StringBuilder(); sb.AppendFormat("About To Merge:\n TextureSet1 {0}\n TextureSet2 {1}\n", tx1.GetDescription(), tx2.GetDescription()); if (LOG_LEVEL >= MB2_LogLevel.trace) { for (int matIdx = 0; matIdx < tx1.matsAndGOs.mats.Count; matIdx++) { sb.AppendFormat("tx1 Mat {0} matAndMeshUVRect {1} fullSamplingRect {2}\n", tx1.matsAndGOs.mats[matIdx].mat, tx1.matsAndGOs.mats[matIdx].samplingRectMatAndUVTiling, tx1.ts[0].GetEncapsulatingSamplingRect()); } for (int matIdx = 0; matIdx < tx2.matsAndGOs.mats.Count; matIdx++) { sb.AppendFormat("tx2 Mat {0} matAndMeshUVRect {1} fullSamplingRect {2}\n", tx2.matsAndGOs.mats[matIdx].mat, tx2.matsAndGOs.mats[matIdx].samplingRectMatAndUVTiling, tx2.ts[0].GetEncapsulatingSamplingRect()); } } } //copy game objects over for (int k = 0; k < tx2.matsAndGOs.gos.Count; k++) { if (!tx1.matsAndGOs.gos.Contains(tx2.matsAndGOs.gos[k])) { tx1.matsAndGOs.gos.Add(tx2.matsAndGOs.gos[k]); } } //copy materials over from tx2 to tx1 for (int matIdx = 0; matIdx < tx2.matsAndGOs.mats.Count; matIdx++) { tx1.matsAndGOs.mats.Add(tx2.matsAndGOs.mats[matIdx]); } tx1.SetEncapsulatingSamplingRectWhenMergingTexSets(encapsulatingRectMerged); if (!MarkedForDeletion.Contains(i)) { MarkedForDeletion.Add(i); } if (LOG_LEVEL >= MB2_LogLevel.debug) { if (LOG_LEVEL >= MB2_LogLevel.trace) { sb.AppendFormat("=== After Merge TextureSet {0}\n", tx1.GetDescription()); for (int matIdx = 0; matIdx < tx1.matsAndGOs.mats.Count; matIdx++) { sb.AppendFormat("tx1 Mat {0} matAndMeshUVRect {1} fullSamplingRect {2}\n", tx1.matsAndGOs.mats[matIdx].mat, tx1.matsAndGOs.mats[matIdx].samplingRectMatAndUVTiling, tx1.ts[0].GetEncapsulatingSamplingRect()); } //Integrity check that sampling rects fit into enapsulating rects if (MB3_MeshBakerRoot.DO_INTEGRITY_CHECKS) { if (MB3_MeshBakerRoot.DO_INTEGRITY_CHECKS) { DoIntegrityCheckMergedEncapsulatingSamplingRects(distinctMaterialTextures); } } } Debug.Log(sb.ToString()); } break; } else { if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log(string.Format("Considered merging {0} and {1} but there was not enough overlap. It is more efficient to bake these to separate rectangles.", tx1.GetDescription() + encapsulatingRect1, tx2.GetDescription() + encapsulatingRect2)); } } } } } //remove distinctMaterialTextures that were merged for (int j = MarkedForDeletion.Count - 1; j >= 0; j--) { distinctMaterialTextures.RemoveAt(MarkedForDeletion[j]); } MarkedForDeletion.Clear(); if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log(string.Format("MergeOverlappingDistinctMaterialTexturesAndCalcMaterialSubrects complete merged {0} now have {1}", numMerged, distinctMaterialTextures.Count)); } if (MB3_MeshBakerRoot.DO_INTEGRITY_CHECKS) { DoIntegrityCheckMergedEncapsulatingSamplingRects(distinctMaterialTextures); } }
// This should only be called after regular merge so that rects have been correctly setup. public void MergeDistinctMaterialTexturesThatWouldExceedMaxAtlasSizeAndCalcMaterialSubrects(List <MB_TexSet> distinctMaterialTextures, int maxAtlasSize) { if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("MergeDistinctMaterialTexturesThatWouldExceedMaxAtlasSizeAndCalcMaterialSubrects num atlas rects" + distinctMaterialTextures.Count); } Debug.Assert(_HasBeenInitialized, "MergeOverlappingDistinctMaterialTexturesAndCalcMaterialSubrects must be called before MergeDistinctMaterialTexturesThatWouldExceedMaxAtlasSizeAndCalcMaterialSubrects"); int numMerged = 0; List <int> MarkedForDeletion = new List <int>(); for (int i = 0; i < distinctMaterialTextures.Count; i++) { MB_TexSet tx2 = distinctMaterialTextures[i]; for (int j = i + 1; j < distinctMaterialTextures.Count; j++) { MB_TexSet tx1 = distinctMaterialTextures[j]; if (tx1.AllTexturesAreSameForMerge(tx2, _considerNonTextureProperties, resultMaterialTextureBlender)) { //Check if the size of the rect in the atlas would be greater than max atlas size. DRect encapsulatingRectMerged = new DRect(); int idxOfFirstNotNull = -1; for (int propIdx = 0; propIdx < tx2.ts.Length; propIdx++) { if (!tx2.ts[propIdx].isNull) { if (idxOfFirstNotNull == -1) { idxOfFirstNotNull = propIdx; } } } DRect encapsulatingRect1 = new DRect(); DRect encapsulatingRect2 = new DRect(); if (idxOfFirstNotNull != -1) { // only in here if all properties use the same tiling so don't need to worry about which propIdx we are dealing with //Get the rect that encapsulates all material and UV tiling for materials and meshes in tx1 encapsulatingRect1 = tx1.matsAndGOs.mats[0].samplingRectMatAndUVTiling; for (int matIdx = 1; matIdx < tx1.matsAndGOs.mats.Count; matIdx++) { DRect tmpSsamplingRectMatAndUVTilingTx1 = tx1.matsAndGOs.mats[matIdx].samplingRectMatAndUVTiling; encapsulatingRect1 = MB3_UVTransformUtility.GetEncapsulatingRectShifted(ref encapsulatingRect1, ref tmpSsamplingRectMatAndUVTilingTx1); } //same for tx2 encapsulatingRect2 = tx2.matsAndGOs.mats[0].samplingRectMatAndUVTiling; for (int matIdx = 1; matIdx < tx2.matsAndGOs.mats.Count; matIdx++) { DRect tmpSsamplingRectMatAndUVTilingTx2 = tx2.matsAndGOs.mats[matIdx].samplingRectMatAndUVTiling; encapsulatingRect2 = MB3_UVTransformUtility.GetEncapsulatingRectShifted(ref encapsulatingRect2, ref tmpSsamplingRectMatAndUVTilingTx2); } encapsulatingRectMerged = MB3_UVTransformUtility.GetEncapsulatingRectShifted(ref encapsulatingRect1, ref encapsulatingRect2); } else { encapsulatingRectMerged = new DRect(0f, 0f, 1f, 1f); } Vector2 maxHeightWidth = tx1.GetMaxRawTextureHeightWidth(); if (encapsulatingRectMerged.width * maxHeightWidth.x > maxAtlasSize || encapsulatingRectMerged.height * maxHeightWidth.y > maxAtlasSize) { // merge tx2 into tx1 numMerged++; StringBuilder sb = null; if (LOG_LEVEL >= MB2_LogLevel.info) { sb = new StringBuilder(); sb.AppendFormat("About To Merge:\n TextureSet1 {0}\n TextureSet2 {1}\n", tx1.GetDescription(), tx2.GetDescription()); if (LOG_LEVEL >= MB2_LogLevel.trace) { for (int matIdx = 0; matIdx < tx1.matsAndGOs.mats.Count; matIdx++) { sb.AppendFormat("tx1 Mat {0} matAndMeshUVRect {1} fullSamplingRect {2}\n", tx1.matsAndGOs.mats[matIdx].mat, tx1.matsAndGOs.mats[matIdx].samplingRectMatAndUVTiling, tx1.ts[0].GetEncapsulatingSamplingRect()); } for (int matIdx = 0; matIdx < tx2.matsAndGOs.mats.Count; matIdx++) { sb.AppendFormat("tx2 Mat {0} matAndMeshUVRect {1} fullSamplingRect {2}\n", tx2.matsAndGOs.mats[matIdx].mat, tx2.matsAndGOs.mats[matIdx].samplingRectMatAndUVTiling, tx2.ts[0].GetEncapsulatingSamplingRect()); } } } //copy game objects over for (int k = 0; k < tx2.matsAndGOs.gos.Count; k++) { if (!tx1.matsAndGOs.gos.Contains(tx2.matsAndGOs.gos[k])) { tx1.matsAndGOs.gos.Add(tx2.matsAndGOs.gos[k]); } } //copy materials over from tx2 to tx1 for (int matIdx = 0; matIdx < tx2.matsAndGOs.mats.Count; matIdx++) { tx1.matsAndGOs.mats.Add(tx2.matsAndGOs.mats[matIdx]); } tx1.SetEncapsulatingSamplingRectWhenMergingTexSets(encapsulatingRectMerged); if (!MarkedForDeletion.Contains(i)) { MarkedForDeletion.Add(i); } if (LOG_LEVEL >= MB2_LogLevel.debug) { if (LOG_LEVEL >= MB2_LogLevel.trace) { sb.AppendFormat("=== After Merge TextureSet {0}\n", tx1.GetDescription()); for (int matIdx = 0; matIdx < tx1.matsAndGOs.mats.Count; matIdx++) { sb.AppendFormat("tx1 Mat {0} matAndMeshUVRect {1} fullSamplingRect {2}\n", tx1.matsAndGOs.mats[matIdx].mat, tx1.matsAndGOs.mats[matIdx].samplingRectMatAndUVTiling, tx1.ts[0].GetEncapsulatingSamplingRect()); } //Integrity check that sampling rects fit into enapsulating rects if (MB3_MeshBakerRoot.DO_INTEGRITY_CHECKS) { if (MB3_MeshBakerRoot.DO_INTEGRITY_CHECKS) { DoIntegrityCheckMergedEncapsulatingSamplingRects(distinctMaterialTextures); } } } Debug.Log(sb.ToString()); } break; } else { if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log(string.Format("Considered merging {0} and {1} but there was not enough overlap. It is more efficient to bake these to separate rectangles.", tx1.GetDescription() + encapsulatingRect1, tx2.GetDescription() + encapsulatingRect2)); } } } } } //remove distinctMaterialTextures that were merged for (int j = MarkedForDeletion.Count - 1; j >= 0; j--) { distinctMaterialTextures.RemoveAt(MarkedForDeletion[j]); } MarkedForDeletion.Clear(); if (LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log(string.Format("MergeDistinctMaterialTexturesThatWouldExceedMaxAtlasSizeAndCalcMaterialSubrects complete merged {0} now have {1}", numMerged, distinctMaterialTextures.Count)); } if (MB3_MeshBakerRoot.DO_INTEGRITY_CHECKS) { DoIntegrityCheckMergedEncapsulatingSamplingRects(distinctMaterialTextures); } }