/// <summary> /// Creates for materials on renderer. /// </summary> /// <returns>Generates an MB2_TextureBakeResult that can be used if all objects to be combined use the same material. /// Returns a MB2_TextureBakeResults that will map all materials used by renderer r to /// the rectangle 0,0..1,1 in the atlas.</returns> /// <param name="r">The red component.</param> public static MB2_TextureBakeResults CreateForMaterialsOnRenderer(Renderer r) { MB2_TextureBakeResults tbr = (MB2_TextureBakeResults)ScriptableObject.CreateInstance(typeof(MB2_TextureBakeResults)); //Material[] ms = r.sharedMaterials; //MB_MaterialAndUVRect[] mss = new MB_MaterialAndUVRect[r.sharedMaterials.Length]; List <MB_MaterialAndUVRect> mss = new List <MB_MaterialAndUVRect>(); Material[] ms; for (int i = 0; i < r.sharedMaterials.Length; i++) { if (r.sharedMaterials[i] != null) { MB_MaterialAndUVRect matAndUVRect = new MB_MaterialAndUVRect(r.sharedMaterials[i], new Rect(0f, 0f, 1f, 1f), new Rect(0f, 0f, 1f, 1f), new Rect(0f, 0f, 1f, 1f), new Rect(0f, 0f, 1f, 1f), r.name); if (!mss.Contains(matAndUVRect)) { mss.Add(matAndUVRect); } } } if (r.sharedMaterials.Length > 1) { tbr.prefabUVRects = new Rect[mss.Count]; tbr.materials = ms = new Material[mss.Count]; tbr.resultMaterials = new MB_MultiMaterial[mss.Count]; for (int i = 0; i < mss.Count; i++) { ms[i] = mss[i].material; tbr.prefabUVRects[i] = new Rect(0f, 0f, 1f, 1f); tbr.resultMaterials[i] = new MB_MultiMaterial(); List <Material> sourceMats = new List <Material>(); sourceMats.Add(ms[i]); tbr.resultMaterials[i].sourceMaterials = sourceMats; tbr.resultMaterials[i].combinedMaterial = ms[i]; } tbr.doMultiMaterial = true; } else { tbr.doMultiMaterial = false; tbr.prefabUVRects = new Rect[] { new Rect(0f, 0f, 1f, 1f) }; tbr.materials = ms = new Material[] { mss[0].material }; tbr.resultMaterial = mss[0].material; tbr.resultMaterials = new MB_MultiMaterial[] { new MB_MultiMaterial() }; List <Material> sourceMats = new List <Material>(); sourceMats.Add(ms[0]); tbr.resultMaterials[0].sourceMaterials = sourceMats; tbr.resultMaterials[0].combinedMaterial = mss[0].material; } tbr.materialsAndUVRects = mss.ToArray(); tbr.fixOutOfBoundsUVs = false; return(tbr); }
public override bool Equals(object obj) { if (!(obj is MB_MaterialAndUVRect)) { return(false); } MB_MaterialAndUVRect b = (MB_MaterialAndUVRect)obj; return(material == b.material && allPropsUseSameTiling_samplingEncapsulatinRect == b.allPropsUseSameTiling_samplingEncapsulatinRect && allPropsUseSameTiling_sourceMaterialTiling == b.allPropsUseSameTiling_sourceMaterialTiling && allPropsUseSameTiling == b.allPropsUseSameTiling && propsUseDifferntTiling_srcUVsamplingRect == b.propsUseDifferntTiling_srcUVsamplingRect); }
//Rect[] uvRectInAtlas; public Material2AtlasRectangleMapper(MB2_TextureBakeResults res) { tbr = res; matsAndSrcUVRect = res.materialsAndUVRects; //uvRectInAtlas = res.prefabUVRects; //allMatsAreUnique = true; //backward compatibility. this may be an old TextureBakeResult which has no materialsAndUVRects if so then build it now if (matsAndSrcUVRect == null || matsAndSrcUVRect.Length == 0) { matsAndSrcUVRect = new MB_MaterialAndUVRect[res.materials.Length]; for (int i = 0; i < res.materials.Length; i++) { matsAndSrcUVRect[i] = new MB_MaterialAndUVRect(res.materials[i], res.prefabUVRects[i], new Rect(0f, 0f, 1f, 1f)); } res.materialsAndUVRects = matsAndSrcUVRect; } //count the number of times a material appears in the atlas. used for fast lookup numTimesMatAppearsInAtlas = new int[matsAndSrcUVRect.Length]; for (int i = 0; i < matsAndSrcUVRect.Length; i++) { if (numTimesMatAppearsInAtlas[i] > 1) { continue; } int count = 1; for (int j = i + 1; j < matsAndSrcUVRect.Length; j++) { if (matsAndSrcUVRect[i].material == matsAndSrcUVRect[j].material) { count++; } } numTimesMatAppearsInAtlas[i] = count; if (count > 1) { //allMatsAreUnique = false; for (int j = i + 1; j < matsAndSrcUVRect.Length; j++) { if (matsAndSrcUVRect[i].material == matsAndSrcUVRect[j].material) { numTimesMatAppearsInAtlas[j] = count; } } } } }
public bool ContainsMaterial(Material m) { if (materialsAndUVRects.Length == 0) { materialsAndUVRects = new MB_MaterialAndUVRect[materials.Length]; for (int i = 0; i < materialsAndUVRects.Length; i++) { materialsAndUVRects[i] = new MB_MaterialAndUVRect(materials[i], prefabUVRects[i], new Rect(0f, 0f, 1f, 1f), new Rect(0f, 0f, 1f, 1f), new Rect(0f, 0f, 1f, 1f), ""); } } for (int i = 0; i < materialsAndUVRects.Length; i++) { if (materialsAndUVRects[i].material == m) { return(true); } } return(false); }
/// <summary> /// Creates for materials on renderer. /// </summary> /// <returns>Generates an MB2_TextureBakeResult that can be used if all objects to be combined use the same material. /// Returns a MB2_TextureBakeResults that will map all materials used by renderer r to /// the rectangle 0,0..1,1 in the atlas.</returns> /// <param name="r">The red component.</param> public static MB2_TextureBakeResults CreateForMaterialsOnRenderer(GameObject[] gos, List <Material> matsOnTargetRenderer) { HashSet <Material> fullMaterialList = new HashSet <Material>(matsOnTargetRenderer); for (int i = 0; i < gos.Length; i++) { if (gos[i] == null) { Debug.LogError(string.Format("Game object {0} in list of objects to add was null", i)); return(null); } Material[] oMats = MB_Utility.GetGOMaterials(gos[i]); if (oMats.Length == 0) { Debug.LogError(string.Format("Game object {0} in list of objects to add no renderer", i)); return(null); } for (int j = 0; j < oMats.Length; j++) { if (!fullMaterialList.Contains(oMats[j])) { fullMaterialList.Add(oMats[j]); } } } Material[] rms = new Material[fullMaterialList.Count]; fullMaterialList.CopyTo(rms); MB2_TextureBakeResults tbr = (MB2_TextureBakeResults)ScriptableObject.CreateInstance(typeof(MB2_TextureBakeResults)); //Material[] ms = rms; //MB_MaterialAndUVRect[] mss = new MB_MaterialAndUVRect[rms.Length]; List <MB_MaterialAndUVRect> mss = new List <MB_MaterialAndUVRect>(); Material[] ms; for (int i = 0; i < rms.Length; i++) { if (rms[i] != null) { MB_MaterialAndUVRect matAndUVRect = new MB_MaterialAndUVRect(rms[i], new Rect(0f, 0f, 1f, 1f), new Rect(0f, 0f, 1f, 1f), new Rect(0f, 0f, 1f, 1f), new Rect(0f, 0f, 1f, 1f), ""); if (!mss.Contains(matAndUVRect)) { mss.Add(matAndUVRect); } } } tbr.materials = ms = new Material[mss.Count]; tbr.resultMaterials = new MB_MultiMaterial[mss.Count]; for (int i = 0; i < mss.Count; i++) { ms[i] = mss[i].material; tbr.resultMaterials[i] = new MB_MultiMaterial(); List <Material> sourceMats = new List <Material>(); sourceMats.Add(mss[i].material); tbr.resultMaterials[i].sourceMaterials = sourceMats; tbr.resultMaterials[i].combinedMaterial = ms[i]; tbr.resultMaterials[i].considerMeshUVs = false; } if (rms.Length == 1) { tbr.doMultiMaterial = false; } else { tbr.doMultiMaterial = true; } tbr.materialsAndUVRects = mss.ToArray(); //tbr.fixOutOfBoundsUVs = false; return(tbr); }
/// <summary> /// A material can appear more than once in an atlas if using fixOutOfBoundsUVs. /// in this case you need to use the UV rect of the mesh to find the correct rectangle. /// If the all properties on the mat use the same tiling then /// encapsulatingRect can be larger and will include baked UV and material tiling /// If mat uses different tiling for different maps then encapsulatingRect is the uvs of /// source mesh used to bake atlas and sourceMaterialTilingOut is 0,0,1,1. This works because /// material tiling was baked into the atlas. /// </summary> public bool TryMapMaterialToUVRect(Material mat, Mesh m, int submeshIdx, int idxInResultMats, MB3_MeshCombinerSingle.MeshChannelsCache meshChannelCache, Dictionary <int, MB_Utility.MeshAnalysisResult[]> meshAnalysisCache, out MB_TextureTilingTreatment tilingTreatment, out Rect rectInAtlas, out Rect encapsulatingRectOut, out Rect sourceMaterialTilingOut, ref String errorMsg, MB2_LogLevel logLevel) { if (tbr.version < VERSION) { UpgradeToCurrentVersion(tbr); } tilingTreatment = MB_TextureTilingTreatment.unknown; if (tbr.materialsAndUVRects.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(); encapsulatingRectOut = new Rect(); sourceMaterialTilingOut = new Rect(); return(false); } if (mat == null) { rectInAtlas = new Rect(); encapsulatingRectOut = 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(); encapsulatingRectOut = 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(); encapsulatingRectOut = 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."); } MB_MaterialAndUVRect mr = matsAndSrcUVRect[idx]; rectInAtlas = mr.atlasRect; tilingTreatment = mr.tilingTreatment; encapsulatingRectOut = mr.GetEncapsulatingRect(); sourceMaterialTilingOut = mr.GetMaterialTilingRect(); 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; Rect encapsulatingRect = new Rect(0, 0, 0, 0); Rect sourceMaterialTiling = new Rect(0, 0, 0, 0); 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++) { MB_MaterialAndUVRect matAndUVrect = matsAndSrcUVRect[i]; if (matAndUVrect.material == mat) { if (matAndUVrect.allPropsUseSameTiling) { encapsulatingRect = matAndUVrect.allPropsUseSameTiling_samplingEncapsulatinRect; sourceMaterialTiling = matAndUVrect.allPropsUseSameTiling_sourceMaterialTiling; } else { encapsulatingRect = matAndUVrect.propsUseDifferntTiling_srcUVsamplingRect; sourceMaterialTiling = new Rect(0, 0, 1, 1); } if (IsMeshAndMaterialRectEnclosedByAtlasRect( matAndUVrect.tilingTreatment, mar[submeshIdx].uvRect, sourceMaterialTiling, encapsulatingRect, 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) { MB_MaterialAndUVRect mr = matsAndSrcUVRect[idx]; rectInAtlas = mr.atlasRect; tilingTreatment = mr.tilingTreatment; encapsulatingRectOut = mr.GetEncapsulatingRect(); sourceMaterialTilingOut = mr.GetMaterialTilingRect(); return(true); } else { rectInAtlas = new Rect(); encapsulatingRectOut = 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); } } }
public static void ConfigureTextureArraysFromObjsToCombine(MB3_TextureBaker mom, SerializedProperty resultMaterialsTexArrays, SerializedObject textureBaker) { if (mom.GetObjectsToCombine().Count == 0) { Debug.LogError("You need to add some objects to combine before building the texture array result materials."); return; } if (resultMaterialsTexArrays.arraySize > 0) { Debug.LogError("You already have some texture array result materials 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; } //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; } if (MB_Utility.GetMesh(go) == null) { Debug.LogError("Could not get mesh for 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; } } //Will sort into "result material" // slices Dictionary <MB3_TextureBakerEditorInternal.MultiMatSubmeshInfo, List <Slice> > shader2ResultMat_map = new Dictionary <MB3_TextureBakerEditorInternal.MultiMatSubmeshInfo, List <Slice> >(); // first pass split by shader and analyse meshes. List <GameObject> objsToCombine = mom.GetObjectsToCombine(); for (int meshIdx = 0; meshIdx < objsToCombine.Count; meshIdx++) { GameObject srcGo = objsToCombine[meshIdx]; Mesh mesh = MB_Utility.GetMesh(srcGo); Renderer r = MB_Utility.GetRenderer(srcGo); if (mom.LOG_LEVEL >= MB2_LogLevel.trace) { Debug.Log("1st Pass 'Split By Shader' Processing Mesh: " + mesh + " Num submeshes: " + r.sharedMaterials.Length); } for (int submeshIdx = 0; submeshIdx < r.sharedMaterials.Length; submeshIdx++) { if (r.sharedMaterials[submeshIdx] == null) { continue; } MB3_TextureBakerEditorInternal.MultiMatSubmeshInfo newKey = new MB3_TextureBakerEditorInternal.MultiMatSubmeshInfo(r.sharedMaterials[submeshIdx].shader, r.sharedMaterials[submeshIdx]); // Initially we fill the list of srcMaterials with garbage MB_MaterialAndUVRects. Will get proper ones when we atlas pack. MB_MaterialAndUVRect submeshMaterial = new MB_MaterialAndUVRect( r.sharedMaterials[submeshIdx], new Rect(0, 0, 0, 0), // garbage value false, //garbage value new Rect(0, 0, 0, 0), // garbage value new Rect(0, 0, 0, 0), // garbage value new Rect(0, 0, 1, 1), // garbage value MB_TextureTilingTreatment.unknown, // garbage value r.name); submeshMaterial.objectsThatUse = new List <GameObject>(); submeshMaterial.objectsThatUse.Add(r.gameObject); if (!shader2ResultMat_map.ContainsKey(newKey)) { // this is a new shader create a new result material Slice srcMaterials = new Slice { atlasRects = new List <MB_MaterialAndUVRect>(), numAtlasRects = 1, }; srcMaterials.atlasRects.Add(submeshMaterial); List <Slice> binsOfMatsThatUseShader = new List <Slice>(); binsOfMatsThatUseShader.Add(srcMaterials); if (mom.LOG_LEVEL >= MB2_LogLevel.trace) { Debug.Log(" Adding Source Material: " + submeshMaterial.material); } shader2ResultMat_map.Add(newKey, binsOfMatsThatUseShader); } else { // there is a result material that uses this shader. Add this source material Slice srcMaterials = shader2ResultMat_map[newKey][0]; // There should only be one list of source materials if (srcMaterials.atlasRects.Find(x => x.material == submeshMaterial.material) == null) { if (mom.LOG_LEVEL >= MB2_LogLevel.trace) { Debug.Log(" Adding Source Material: " + submeshMaterial.material); } srcMaterials.atlasRects.Add(submeshMaterial); } } } } int resMatCount = 0; foreach (MB3_TextureBakerEditorInternal.MultiMatSubmeshInfo resultMat in shader2ResultMat_map.Keys) { // at this point there there should be only one slice with all the source materials resMatCount++; // For each result material, all source materials are in the first slice. // We will now split these using a texture packer. Each "atlas" generated by the packer will be a slice. { // All source materials should be in the first slice at this point. List <Slice> slices = shader2ResultMat_map[resultMat]; List <Slice> newSlices = new List <Slice>(); Slice firstSlice = slices[0]; List <Material> allMatsThatUserShader = new List <Material>(); List <GameObject> objsThatUseFirstSlice = new List <GameObject>(); for (int i = 0; i < firstSlice.atlasRects.Count; i++) { allMatsThatUserShader.Add(firstSlice.atlasRects[i].material); if (!objsThatUseFirstSlice.Contains(firstSlice.atlasRects[i].objectsThatUse[0])) { objsThatUseFirstSlice.Add(firstSlice.atlasRects[i].objectsThatUse[0]); } } MB3_TextureCombiner combiner = mom.CreateAndConfigureTextureCombiner(); combiner.packingAlgorithm = MB2_PackingAlgorithmEnum.MeshBakerTexturePacker; combiner.saveAtlasesAsAssets = false; combiner.fixOutOfBoundsUVs = true; combiner.doMergeDistinctMaterialTexturesThatWouldExceedAtlasSize = true; List <AtlasPackingResult> packingResults = new List <AtlasPackingResult>(); Material tempMat = new Material(resultMat.shader); if (mom.LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("======== 2nd pass. Use atlas packer to split the first slice into multiple if it exceeds atlas size. "); } combiner.CombineTexturesIntoAtlases(null, null, tempMat, mom.GetObjectsToCombine(), allMatsThatUserShader, null, packingResults, onlyPackRects: true, splitAtlasWhenPackingIfTooBig: true); if (mom.LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("======== Completed packing with texture packer. numPackingResults: " + packingResults.Count); } newSlices.Clear(); // The texture packing just split the atlas into multiple atlases. Each atlas will become a "slice". for (int newSliceIdx = 0; newSliceIdx < packingResults.Count; newSliceIdx++) { List <MB_MaterialAndUVRect> sourceMats = new List <MB_MaterialAndUVRect>(); List <MB_MaterialAndUVRect> packedMatRects = (List <MB_MaterialAndUVRect>)packingResults[newSliceIdx].data; HashSet <Rect> distinctAtlasRects = new HashSet <Rect>(); for (int packedMatRectIdx = 0; packedMatRectIdx < packedMatRects.Count; packedMatRectIdx++) { MB_MaterialAndUVRect muvr = packedMatRects[packedMatRectIdx]; distinctAtlasRects.Add(muvr.atlasRect); { Rect encapsulatingRect = muvr.GetEncapsulatingRect(); Vector2 sizeInAtlas_px = new Vector2( packingResults[newSliceIdx].atlasX * encapsulatingRect.width, packingResults[newSliceIdx].atlasY * encapsulatingRect.height); } sourceMats.Add(muvr); } Slice slice = new Slice() { atlasRects = sourceMats, packingResult = packingResults[newSliceIdx], numAtlasRects = distinctAtlasRects.Count, }; newSlices.Add(slice); } // Replace first slice with split version. if (mom.LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("First slice exceeded atlas size splitting it into " + newSlices.Count + " slices"); } slices.RemoveAt(0); for (int i = 0; i < newSlices.Count; i++) { slices.Insert(i, newSlices[i]); } } } // build the texture array result materials if (shader2ResultMat_map.Count == 0) { Debug.LogError("Found no materials in list of objects to combine"); } mom.resultMaterialsTexArray = new MB_MultiMaterialTexArray[shader2ResultMat_map.Count]; int k = 0; foreach (MB3_TextureBakerEditorInternal.MultiMatSubmeshInfo resMatKey in shader2ResultMat_map.Keys) { List <Slice> srcSlices = shader2ResultMat_map[resMatKey]; MB_MultiMaterialTexArray mm = mom.resultMaterialsTexArray[k] = new MB_MultiMaterialTexArray(); for (int sliceIdx = 0; sliceIdx < srcSlices.Count; sliceIdx++) { Slice slice = srcSlices[sliceIdx]; MB_TexArraySlice resSlice = new MB_TexArraySlice(); List <Material> usedMats = new List <Material>(); for (int srcMatIdx = 0; srcMatIdx < slice.atlasRects.Count; srcMatIdx++) { MB_MaterialAndUVRect matAndUVRect = slice.atlasRects[srcMatIdx]; List <GameObject> objsThatUse = matAndUVRect.objectsThatUse; for (int objsThatUseIdx = 0; objsThatUseIdx < objsThatUse.Count; objsThatUseIdx++) { GameObject obj = objsThatUse[objsThatUseIdx]; if (!resSlice.ContainsMaterialAndMesh(slice.atlasRects[srcMatIdx].material, MB_Utility.GetMesh(obj))) { resSlice.sourceMaterials.Add( new MB_TexArraySliceRendererMatPair() { renderer = obj, sourceMaterial = slice.atlasRects[srcMatIdx].material } ); } } } { // Should we use considerUVs bool doConsiderUVs = false; // If there is more than one atlas rectangle in a slice then use considerUVs if (slice.numAtlasRects > 1) { doConsiderUVs = true; } else { // There is only one source material, could be: // - lots of tiling (don't want consider UVs) // - We are extracting a small part of a large atlas (want considerUVs) if (slice.packingResult.atlasX >= mom.maxAtlasSize || slice.packingResult.atlasY >= mom.maxAtlasSize) { doConsiderUVs = false; // lots of tiling } else { doConsiderUVs = true; // extracting a small part of an atlas } } resSlice.considerMeshUVs = doConsiderUVs; } mm.slices.Add(resSlice); } // Enforce integrity. If a material appears in more than one slice then all those slices must be considerUVs=true { // collect all distinct materials HashSet <Material> distinctMats = new HashSet <Material>(); Dictionary <Material, int> mat2sliceCount = new Dictionary <Material, int>(); for (int sliceIdx = 0; sliceIdx < mm.slices.Count; sliceIdx++) { for (int sliceMatIdx = 0; sliceMatIdx < mm.slices[sliceIdx].sourceMaterials.Count; sliceMatIdx++) { Material mat = mm.slices[sliceIdx].sourceMaterials[sliceMatIdx].sourceMaterial; distinctMats.Add(mat); mat2sliceCount[mat] = 0; } } // Count the number of slices that use each material. foreach (Material mat in distinctMats) { for (int sliceIdx = 0; sliceIdx < mm.slices.Count; sliceIdx++) { if (mm.slices[sliceIdx].ContainsMaterial(mat)) { mat2sliceCount[mat] = mat2sliceCount[mat] + 1; } } } // Check that considerUVs is true for any materials that appear more than once foreach (Material mat in distinctMats) { if (mat2sliceCount[mat] > 1) { for (int sliceIdx = 0; sliceIdx < mm.slices.Count; sliceIdx++) { if (mm.slices[sliceIdx].ContainsMaterial(mat)) { if (mom.LOG_LEVEL >= MB2_LogLevel.debug && mm.slices[sliceIdx].considerMeshUVs) { Debug.Log("There was a material " + mat + " that was used by more than one slice and considerUVs was false. sliceIdx:" + sliceIdx); } mm.slices[sliceIdx].considerMeshUVs = true; } } } } } // Cleanup. remove "Renderer"s from source materials that do not use considerUVs and delete extra { // put any slices with consider UVs first List <MB_TexArraySlice> newSlices = new List <MB_TexArraySlice>(); for (int sliceIdx = 0; sliceIdx < mm.slices.Count; sliceIdx++) { if (mm.slices[sliceIdx].considerMeshUVs == true) { newSlices.Add(mm.slices[sliceIdx]); } } // for any slices without considerUVs, remove "renderer" and truncate for (int sliceIdx = 0; sliceIdx < mm.slices.Count; sliceIdx++) { MB_TexArraySlice slice = mm.slices[sliceIdx]; if (slice.considerMeshUVs == false) { newSlices.Add(slice); HashSet <Material> distinctMats = slice.GetDistinctMaterials(); slice.sourceMaterials.Clear(); foreach (Material mat in distinctMats) { slice.sourceMaterials.Add(new MB_TexArraySliceRendererMatPair() { sourceMaterial = mat }); } } } mm.slices = newSlices; } string pth = AssetDatabase.GetAssetPath(mom.textureBakeResults); string baseName = Path.GetFileNameWithoutExtension(pth); string folderPath = pth.Substring(0, pth.Length - baseName.Length - 6); string matName = folderPath + baseName + "-mat" + k + ".mat"; Material existingAsset = AssetDatabase.LoadAssetAtPath <Material>(matName); if (!existingAsset) { Material newMat = new Material(Shader.Find("Standard")); // Don't try to configure the material we need the user to pick a shader that has TextureArrays AssetDatabase.CreateAsset(newMat, matName); } mm.combinedMaterial = (Material)AssetDatabase.LoadAssetAtPath(matName, typeof(Material)); k++; } MBVersionEditor.UpdateIfDirtyOrScript(textureBaker); textureBaker.Update(); }