//Fills distinctMaterialTextures and usedObjsToMesh //If allowedMaterialsFilter is empty then all materials on allObjsToMesh will be collected and usedObjsToMesh will be same as allObjsToMesh //else only materials in allowedMaterialsFilter will be included and usedObjsToMesh will be objs that use those materials. bool __Step1_CollectDistinctMatTexturesAndUsedObjects(List<GameObject> allObjsToMesh, List<Material> allowedMaterialsFilter, List<string> texPropertyNames, MB2_EditorMethodsInterface textureEditorMethods, List<MB_TexSet> distinctMaterialTextures, //Will be populated List<GameObject> usedObjsToMesh) //Will be populated, is a subset of allObjsToMesh { // Collect distinct list of textures to combine from the materials on objsToCombine bool outOfBoundsUVs = false; for (int i = 0; i < allObjsToMesh.Count; i++){ GameObject obj = allObjsToMesh[i]; if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Collecting textures for object " + obj); if (obj == null){ Debug.LogError("The list of objects to mesh contained nulls."); return false; } Mesh sharedMesh = MB_Utility.GetMesh(obj); if (sharedMesh == null){ Debug.LogError("Object " + obj.name + " in the list of objects to mesh has no mesh."); return false; } Material[] sharedMaterials = MB_Utility.GetGOMaterials(obj); if (sharedMaterials == null){ Debug.LogError("Object " + obj.name + " in the list of objects has no materials."); return false; } for(int matIdx = 0; matIdx < sharedMaterials.Length; matIdx++){ Material mat = sharedMaterials[matIdx]; //check if this material is in the list of source materaials if (allowedMaterialsFilter != null && !allowedMaterialsFilter.Contains(mat)){ continue; } Rect uvBounds = new Rect(); bool mcOutOfBoundsUVs = MB_Utility.hasOutOfBoundsUVs(sharedMesh,ref uvBounds,matIdx); outOfBoundsUVs = outOfBoundsUVs || mcOutOfBoundsUVs; if (mat.name.Contains("(Instance)")){ Debug.LogError("The sharedMaterial on object " + obj.name + " has been 'Instanced'. This was probably caused by a script accessing the meshRender.material property in the editor. " + " The material to UV Rectangle mapping will be incorrect. To fix this recreate the object from its prefab or re-assign its material from the correct asset."); return false; } if (fixOutOfBoundsUVs){ if (!MB_Utility.validateOBuvsMultiMaterial(sharedMaterials)){ if (LOG_LEVEL >= MB2_LogLevel.warn) Debug.LogWarning("Object " + obj.name + " uses the same material on multiple submeshes. This may generate strange resultAtlasesAndRects especially when used with fix out of bounds uvs. Try duplicating the material."); } } //collect textures scale and offset for each texture in objects material MeshBakerMaterialTexture[] mts = new MeshBakerMaterialTexture[texPropertyNames.Count]; for (int j = 0; j < texPropertyNames.Count; j++){ Texture2D tx = null; Vector2 scale = Vector2.one; Vector2 offset = Vector2.zero; Vector2 obUVscale = Vector2.one; Vector2 obUVoffset = Vector2.zero; if (mat.HasProperty(texPropertyNames[j])){ Texture txx = mat.GetTexture(texPropertyNames[j]); if (txx != null){ if (txx is Texture2D){ tx = (Texture2D) txx; TextureFormat f = tx.format; bool isNormalMap = false; if (!Application.isPlaying && textureEditorMethods != null) isNormalMap = textureEditorMethods.IsNormalMap(tx); if ((f == TextureFormat.ARGB32 || f == TextureFormat.RGBA32 || f == TextureFormat.BGRA32 || f == TextureFormat.RGB24 || f == TextureFormat.Alpha8) && !isNormalMap) //DXT5 does not work { //good } else { //TRIED to copy texture using tex2.SetPixels(tex1.GetPixels()) but bug in 3.5 means DTX1 and 5 compressed textures come out skewed //MB2_Log.Log(MB2_LogLevel.warn,obj.name + " in the list of objects to mesh uses Texture "+tx.name+" uses format " + f + " that is not in: ARGB32, RGBA32, BGRA32, RGB24, Alpha8 or DXT. These formats cannot be resized. MeshBaker will create duplicates."); //tx = createTextureCopy(tx); if (!Application.isPlaying){ //Debug.LogWarning("Object " + obj.name + " in the list of objects to mesh uses Texture "+tx.name+" uses format " + f + " that is not in: ARGB32, RGBA32, BGRA32, RGB24, Alpha8 or DXT. These textures cannot be resized. Try changing texture format. If format says 'compressed' try changing it to 'truecolor'"); if (textureEditorMethods != null) textureEditorMethods.AddTextureFormat(tx, isNormalMap); tx = (Texture2D) mat.GetTexture(texPropertyNames[j]); } else { Debug.LogError("Object " + obj.name + " in the list of objects to mesh uses Texture "+tx.name+" uses format " + f + " that is not in: ARGB32, RGBA32, BGRA32, RGB24, Alpha8 or DXT. These textures cannot be resized at runtime. Try changing texture format. If format says 'compressed' try changing it to 'truecolor'" ); return false; } } } else { Debug.LogError("Object " + obj.name + " in the list of objects to mesh uses a Texture that is not a Texture2D. Cannot build atlases."); return false; } } offset = mat.GetTextureOffset(texPropertyNames[j]); scale = mat.GetTextureScale(texPropertyNames[j]); } if (tx == null){ if (LOG_LEVEL >= MB2_LogLevel.warn) Debug.LogWarning("No texture selected for " + texPropertyNames[j] + " in object " + allObjsToMesh[i].name + ". A 2x2 clear texture will be generated and used in the atlas."); } if (mcOutOfBoundsUVs){ obUVscale = new Vector2(uvBounds.width,uvBounds.height); obUVoffset = new Vector2(uvBounds.x,uvBounds.y); } mts[j] = new MeshBakerMaterialTexture(tx,offset,scale,obUVoffset,obUVscale); } //Add to distinct set of textures if not already there MB_TexSet setOfTexs = new MB_TexSet(mts); MB_TexSet setOfTexs2 = distinctMaterialTextures.Find(x => x.IsEqual(setOfTexs,fixOutOfBoundsUVs)); if (setOfTexs2 != null){ setOfTexs = setOfTexs2; } else { distinctMaterialTextures.Add(setOfTexs); } if (!setOfTexs.mats.Contains(mat)){ setOfTexs.mats.Add(mat); } if (!setOfTexs.gos.Contains(obj)){ setOfTexs.gos.Add(obj); if (!usedObjsToMesh.Contains(obj)) usedObjsToMesh.Add(obj); } } } return true; }
//Fills distinctMaterialTextures and usedObjsToMesh //If allowedMaterialsFilter is empty then all materials on allObjsToMesh will be collected and usedObjsToMesh will be same as allObjsToMesh //else only materials in allowedMaterialsFilter will be included and usedObjsToMesh will be objs that use those materials. bool __Step1_CollectDistinctMatTexturesAndUsedObjects(List<GameObject> allObjsToMesh, List<Material> allowedMaterialsFilter, List<ShaderTextureProperty> texPropertyNames, MB2_EditorMethodsInterface textureEditorMethods, List<MB_TexSet> distinctMaterialTextures, //Will be populated List<GameObject> usedObjsToMesh) //Will be populated, is a subset of allObjsToMesh { System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); sw.Start(); // Collect distinct list of textures to combine from the materials on objsToCombine bool outOfBoundsUVs = false; Dictionary<int,MB_Utility.MeshAnalysisResult[]> meshAnalysisResultsCache = new Dictionary<int, MB_Utility.MeshAnalysisResult[]>(); //cache results for (int i = 0; i < allObjsToMesh.Count; i++){ GameObject obj = allObjsToMesh[i]; if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Collecting textures for object " + obj); if (obj == null){ Debug.LogError("The list of objects to mesh contained nulls."); return false; } Mesh sharedMesh = MB_Utility.GetMesh(obj); if (sharedMesh == null){ Debug.LogError("Object " + obj.name + " in the list of objects to mesh has no mesh."); return false; } Material[] sharedMaterials = MB_Utility.GetGOMaterials(obj); if (sharedMaterials == null){ Debug.LogError("Object " + obj.name + " in the list of objects has no materials."); return false; } //analyze mesh or grab cached result of previous analysis MB_Utility.MeshAnalysisResult[] mar; if (!meshAnalysisResultsCache.TryGetValue(sharedMesh.GetInstanceID(),out mar)){ mar = new MB_Utility.MeshAnalysisResult[sharedMesh.subMeshCount]; for (int j = 0; j < sharedMesh.subMeshCount; j++){ Rect outOfBoundsUVRect = new Rect(); MB_Utility.hasOutOfBoundsUVs(sharedMesh,ref outOfBoundsUVRect,ref mar[j], j); } meshAnalysisResultsCache.Add(sharedMesh.GetInstanceID(),mar); } for(int matIdx = 0; matIdx < sharedMaterials.Length; matIdx++){ Material mat = sharedMaterials[matIdx]; //check if this material is in the list of source materaials if (allowedMaterialsFilter != null && !allowedMaterialsFilter.Contains(mat)){ continue; } //Rect uvBounds = mar[matIdx].uvRect; outOfBoundsUVs = outOfBoundsUVs || mar[matIdx].hasOutOfBoundsUVs; if (mat.name.Contains("(Instance)")){ Debug.LogError("The sharedMaterial on object " + obj.name + " has been 'Instanced'. This was probably caused by a script accessing the meshRender.material property in the editor. " + " The material to UV Rectangle mapping will be incorrect. To fix this recreate the object from its prefab or re-assign its material from the correct asset."); return false; } if (_fixOutOfBoundsUVs){ if (!MB_Utility.AreAllSharedMaterialsDistinct(sharedMaterials)){ if (LOG_LEVEL >= MB2_LogLevel.warn) Debug.LogWarning("Object " + obj.name + " uses the same material on multiple submeshes. This may generate strange resultAtlasesAndRects especially when used with fix out of bounds uvs. Try duplicating the material."); } } //collect textures scale and offset for each texture in objects material MeshBakerMaterialTexture[] mts = new MeshBakerMaterialTexture[texPropertyNames.Count]; for (int j = 0; j < texPropertyNames.Count; j++){ Texture2D tx = null; Vector2 scale = Vector2.one; Vector2 offset = Vector2.zero; Vector2 obUVscale = Vector2.one; Vector2 obUVoffset = Vector2.zero; Color colorIfNoTexture = Color.clear; Color tintColor = GetColorIfNoTexture(mat,texPropertyNames[j]); if (mat.HasProperty(texPropertyNames[j].name)){ Texture txx = mat.GetTexture(texPropertyNames[j].name); if (txx != null){ if (txx is Texture2D){ tx = (Texture2D) txx; TextureFormat f = tx.format; bool isNormalMap = false; if (!Application.isPlaying && textureEditorMethods != null) isNormalMap = textureEditorMethods.IsNormalMap(tx); if ((f == TextureFormat.ARGB32 || f == TextureFormat.RGBA32 || f == TextureFormat.BGRA32 || f == TextureFormat.RGB24 || f == TextureFormat.Alpha8) && !isNormalMap) //DXT5 does not work { //good } else { //TRIED to copy texture using tex2.SetPixels(tex1.GetPixels()) but bug in 3.5 means DTX1 and 5 compressed textures come out skewed //MB2_Log.Log(MB2_LogLevel.warn,obj.name + " in the list of objects to mesh uses Texture "+tx.name+" uses format " + f + " that is not in: ARGB32, RGBA32, BGRA32, RGB24, Alpha8 or DXT. These formats cannot be resized. MeshBaker will create duplicates."); //tx = createTextureCopy(tx); if (Application.isPlaying && _packingAlgorithm != MB2_PackingAlgorithmEnum.MeshBakerTexturePacker_Fast) { Debug.LogError("Object " + obj.name + " in the list of objects to mesh uses Texture "+tx.name+" uses format " + f + " that is not in: ARGB32, RGBA32, BGRA32, RGB24, Alpha8 or DXT. These textures cannot be resized at runtime. Try changing texture format. If format says 'compressed' try changing it to 'truecolor'" ); return false; } else { //only want to do this if we are saving the atlases to project if (textureEditorMethods != null && (_packingAlgorithm != MB2_PackingAlgorithmEnum.MeshBakerTexturePacker_Fast || isNormalMap)){ textureEditorMethods.AddTextureFormat(tx, isNormalMap); } tx = (Texture2D) mat.GetTexture(texPropertyNames[j].name); } } } else { Debug.LogError("Object " + obj.name + " in the list of objects to mesh uses a Texture that is not a Texture2D. Cannot build atlases."); return false; } } else { //has texture property but no texture try to set a resonable color from the other texture properties colorIfNoTexture = tintColor; } offset = mat.GetTextureOffset(texPropertyNames[j].name); scale = mat.GetTextureScale(texPropertyNames[j].name); } else { colorIfNoTexture = tintColor; } if (mar[matIdx].hasOutOfBoundsUVs){ obUVscale = new Vector2(mar[matIdx].uvRect.width,mar[matIdx].uvRect.height); obUVoffset = new Vector2(mar[matIdx].uvRect.x,mar[matIdx].uvRect.y); } mts[j] = new MeshBakerMaterialTexture(tx,offset,scale,obUVoffset,obUVscale,colorIfNoTexture,tintColor); } //Add to distinct set of textures if not already there MB_TexSet setOfTexs = new MB_TexSet(mts); MB_TexSet setOfTexs2 = distinctMaterialTextures.Find(x => x.IsEqual(setOfTexs,_fixOutOfBoundsUVs)); if (setOfTexs2 != null){ setOfTexs = setOfTexs2; } else { distinctMaterialTextures.Add(setOfTexs); } if (!setOfTexs.mats.Contains(mat)){ setOfTexs.mats.Add(mat); } if (!setOfTexs.gos.Contains(obj)){ setOfTexs.gos.Add(obj); if (!usedObjsToMesh.Contains(obj)) usedObjsToMesh.Add(obj); } } } if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log ("Total time Step1_CollectDistinctTextures " + (sw.ElapsedMilliseconds).ToString("f5")); return true; }