//a material can appear more than once in an atlas if using fixOutOfBoundsUVs. //in this case need to use the UV rect of the mesh to find the correct rectangle. public bool TryMapMaterialToUVRect(Material mat, Mesh m, int submeshIdx, int idxInResultMats, MB3_MeshCombinerSingle.MeshChannelsCache meshChannelCache, Dictionary <int, MB_Utility.MeshAnalysisResult[]> meshAnalysisCache, out Rect rectInAtlas, //out Rect subrectInAtlasMatTiling, out Rect encapsulatingRect, out Rect sourceMaterialTilingOut, ref String errorMsg, MB2_LogLevel logLevel) { if (tbr.materialsAndUVRects.Length == 0 && tbr.materials.Length > 0) { errorMsg = "The 'Texture Bake Result' needs to be re-baked to be compatible with this version of Mesh Baker. Please re-bake using the MB3_TextureBaker."; rectInAtlas = new Rect(); //subrectInAtlasMatTiling = new Rect(); encapsulatingRect = new Rect(); sourceMaterialTilingOut = new Rect(); return(false); } if (mat == null) { rectInAtlas = new Rect(); //subrectInAtlasMatTiling = new Rect(); encapsulatingRect = new Rect(); sourceMaterialTilingOut = new Rect(); errorMsg = String.Format("Mesh {0} Had no material on submesh {1} cannot map to a material in the atlas", m.name, submeshIdx); return(false); } if (submeshIdx >= m.subMeshCount) { errorMsg = "Submesh index is greater than the number of submeshes"; rectInAtlas = new Rect(); //subrectInAtlasMatTiling = new Rect(); encapsulatingRect = new Rect(); sourceMaterialTilingOut = new Rect(); return(false); } //find the first index of this material int idx = -1; for (int i = 0; i < matsAndSrcUVRect.Length; i++) { if (mat == matsAndSrcUVRect[i].material) { idx = i; break; } } // if couldn't find material if (idx == -1) { rectInAtlas = new Rect(); //subrectInAtlasMatTiling = new Rect(); encapsulatingRect = new Rect(); sourceMaterialTilingOut = new Rect(); errorMsg = String.Format("Material {0} could not be found in the Texture Bake Result", mat.name); return(false); } if (!tbr.resultMaterials[idxInResultMats].considerMeshUVs) { if (numTimesMatAppearsInAtlas[idx] != 1) { Debug.LogError("There is a problem with this TextureBakeResults. FixOutOfBoundsUVs is false and a material appears more than once."); } rectInAtlas = matsAndSrcUVRect[idx].atlasRect; //subrectInAtlasMatTiling = matsAndSrcUVRect[idx].atlasSubrectMaterialOnly; encapsulatingRect = matsAndSrcUVRect[idx].samplingEncapsulatinRect; sourceMaterialTilingOut = matsAndSrcUVRect[idx].sourceMaterialTiling; return(true); } else { //todo what if no UVs //Find UV rect in source mesh MB_Utility.MeshAnalysisResult[] mar; if (!meshAnalysisCache.TryGetValue(m.GetInstanceID(), out mar)) { mar = new MB_Utility.MeshAnalysisResult[m.subMeshCount]; for (int j = 0; j < m.subMeshCount; j++) { Vector2[] uvss = meshChannelCache.GetUv0Raw(m); MB_Utility.hasOutOfBoundsUVs(uvss, m, ref mar[j], j); } meshAnalysisCache.Add(m.GetInstanceID(), mar); } //this could be a mesh that was not used in the texture baking that has huge UV tiling too big for the rect that was baked //find a record that has an atlas uvRect capable of containing this bool found = false; if (logLevel >= MB2_LogLevel.trace) { Debug.Log(String.Format("Trying to find a rectangle in atlas capable of holding tiled sampling rect for mesh {0} using material {1} meshUVrect={2}", m, mat, mar[submeshIdx].uvRect.ToString("f5"))); } for (int i = idx; i < matsAndSrcUVRect.Length; i++) { if (matsAndSrcUVRect[i].material == mat) { if (IsMeshAndMaterialRectEnclosedByAtlasRect(mar[submeshIdx].uvRect, matsAndSrcUVRect[i].sourceMaterialTiling, matsAndSrcUVRect[i].samplingEncapsulatinRect, logLevel)) { if (logLevel >= MB2_LogLevel.trace) { Debug.Log("Found rect in atlas capable of containing tiled sampling rect for mesh " + m + " at idx=" + i); } idx = i; found = true; break; } } } if (found) { rectInAtlas = matsAndSrcUVRect[idx].atlasRect; //subrectInAtlasMatTiling = matsAndSrcUVRect[idx].atlasSubrectMaterialOnly; encapsulatingRect = matsAndSrcUVRect[idx].samplingEncapsulatinRect; sourceMaterialTilingOut = matsAndSrcUVRect[idx].sourceMaterialTiling; return(true); } else { rectInAtlas = new Rect(); //subrectInAtlasMatTiling = new Rect(); encapsulatingRect = new Rect(); sourceMaterialTilingOut = new Rect(); errorMsg = String.Format("Could not find a tiled rectangle in the atlas capable of containing the uv and material tiling on mesh {0} for material {1}", m.name, mat); return(false); } } }
//a material can appear more than once in an atlas if using fixOutOfBoundsUVs. //in this case need to use the UV rect of the mesh to find the correct rectangle. public bool TryMapMaterialToUVRect(Material mat, Mesh m, int submeshIdx, MB3_MeshCombinerSingle.MeshChannelsCache meshChannelCache, Dictionary <int, MB_Utility.MeshAnalysisResult[]> meshAnalysisCache, out Rect rectInAtlas, out Rect subrectInAtlasMatTiling, ref String errorMsg) { if (tbr.materialsAndUVRects.Length == 0 && tbr.materials.Length > 0) { errorMsg = "The 'Material Bake Result' needs to be re-baked to be compatible with this version of Mesh Baker. Please re-bake using the MB3_TextureBaker."; rectInAtlas = new Rect(); subrectInAtlasMatTiling = new Rect(); return(false); } if (mat == null) { rectInAtlas = new Rect(); subrectInAtlasMatTiling = new Rect(); errorMsg = String.Format("Mesh {0} Had no material on submesh {1} cannot map to a material in the atlas", m.name, submeshIdx); return(false); } if (submeshIdx >= m.subMeshCount) { errorMsg = "Submesh index is greater than the number of submeshes"; rectInAtlas = new Rect(); subrectInAtlasMatTiling = new Rect(); return(false); } //find the first index of this material int idx = -1; for (int i = 0; i < matsAndSrcUVRect.Length; i++) { if (mat == matsAndSrcUVRect[i].material) { idx = i; break; } } // if couldn't find material if (idx == -1) { rectInAtlas = new Rect(); subrectInAtlasMatTiling = new Rect(); errorMsg = String.Format("Material {0} could not be found in the Material Bake Result", mat.name); return(false); } if (!tbr.fixOutOfBoundsUVs) { if (numTimesMatAppearsInAtlas[idx] != 1) { Debug.LogError("There is a problem with this TextureBakeResults. FixOutOfBoundsUVs is false and a material appears more than once."); } rectInAtlas = matsAndSrcUVRect[idx].atlasRect; subrectInAtlasMatTiling = matsAndSrcUVRect[idx].atlasSubrectMaterialOnly; return(true); } else { //todo what if no UVs //Find UV rect in source mesh MB_Utility.MeshAnalysisResult[] mar; if (!meshAnalysisCache.TryGetValue(m.GetInstanceID(), out mar)) { mar = new MB_Utility.MeshAnalysisResult[m.subMeshCount]; for (int j = 0; j < m.subMeshCount; j++) { Vector2[] uvss = meshChannelCache.GetUv0Raw(m); MB_Utility.hasOutOfBoundsUVs(uvss, m, ref mar[j], j); } meshAnalysisCache.Add(m.GetInstanceID(), mar); } //this could be a mesh that was not used in the texture baking that has huge UV tiling too big for the rect that was baked //find a record that has an atlas uvRect capable of containing this bool found = false; for (int i = idx; i < matsAndSrcUVRect.Length; i++) { if (matsAndSrcUVRect[i].material == mat) { //calculate what the UV rect in the atlas would be if we combined the material tiling of this rect with the UV tiling of this submesh Rect potentialRect = new Rect(); Rect uvR = mar[submeshIdx].uvRect; Rect matR = matsAndSrcUVRect[i].atlasSubrectMaterialOnly; potentialRect = MB3_UVTransformUtility.CombineTransforms(ref matR, ref uvR); //MB3_UVTransformUtility.Canonicalize(ref potentialRect); // test to see if this would fit in what was baked in the atlas Rect rr = new Rect(0f, 0f, 1f, 1f); if (MB3_UVTransformUtility.RectContains(ref rr, ref potentialRect)) { idx = i; found = true; break; } } } if (found) { rectInAtlas = matsAndSrcUVRect[idx].atlasRect; subrectInAtlasMatTiling = matsAndSrcUVRect[idx].atlasSubrectMaterialOnly; return(true); } else { rectInAtlas = new Rect(); subrectInAtlasMatTiling = new Rect(); errorMsg = String.Format("Could not find a tiled rectangle in the atlas capable of containing the uv and material tiling on mesh {0}", m.name); return(false); } } }