private bool InitBaker(string[] paths, MB3_TextureBaker textureBaker, MB3_MeshBaker meshBaker) { bool result = false; Material material = ResourcesManagerMediator. GetNoGameObjectFromResourcesManager <Material>(paths[1]); if (material == null) { Debug.LogError("加载合并材质资源失败" + paths[1]); return(result); } MB2_TextureBakeResults textureBakeResults = ResourcesManagerMediator. GetNoGameObjectFromResourcesManager <MB2_TextureBakeResults>(paths[2]); if (textureBakeResults == null) { Debug.LogError("加载MB2_TextureBakeResults资源失败" + paths[2]); return(result); } textureBaker.resultMaterial = material; textureBaker.textureBakeResults = textureBakeResults; meshBaker.textureBakeResults = textureBakeResults; result = true; return(result); }
/// <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.materials; tbr.resultMaterial = ms[0]; tbr.fixOutOfBoundsUVs = false; tbr.materials = ms; tbr.resultMaterials = new MB_MultiMaterial[ms.Length]; if (ms.Length > 1) { tbr.prefabUVRects = new Rect[ms.Length]; for (int i = 0; i < ms.Length; i++) { 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) }; } return(tbr); }
private static bool IsGoodToBake(Renderer r, MB2_TextureBakeResults tbr) { if (r == null) { return(false); } if (!(r is MeshRenderer) && !(r is SkinnedMeshRenderer)) { return(false); } Material[] mats = r.sharedMaterials; for (int i = 0; i < mats.Length; i++) { if (!tbr.ContainsMaterial(mats[i])) { Debug.LogWarning("Mesh on " + r + " uses a material " + mats[i] + " that is not in the list of materials. This mesh will not be baked. The original mesh and material will be used in the result prefab."); return(false); } } if (MB_Utility.GetMesh(r.gameObject) == null) { return(false); } return(true); }
public Material2AtlasRectangleMapper(MB2_TextureBakeResults res) { tbr = res; matsAndSrcUVRect = res.materialsAndUVRects; //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 static MB2_TextureBakeResults CreateForMaterialsOnRenderer(Renderer r) { MB2_TextureBakeResults mb2_TextureBakeResults = (MB2_TextureBakeResults)ScriptableObject.CreateInstance(typeof(MB2_TextureBakeResults)); Material[] sharedMaterials = r.sharedMaterials; mb2_TextureBakeResults.resultMaterial = sharedMaterials[0]; mb2_TextureBakeResults.fixOutOfBoundsUVs = false; mb2_TextureBakeResults.materials = sharedMaterials; mb2_TextureBakeResults.resultMaterials = new MB_MultiMaterial[sharedMaterials.Length]; if (sharedMaterials.Length > 1) { mb2_TextureBakeResults.prefabUVRects = new Rect[sharedMaterials.Length]; for (int i = 0; i < sharedMaterials.Length; i++) { mb2_TextureBakeResults.prefabUVRects[i] = new Rect(0f, 0f, 1f, 1f); mb2_TextureBakeResults.resultMaterials[i] = new MB_MultiMaterial(); List <Material> list = new List <Material>(); list.Add(sharedMaterials[i]); mb2_TextureBakeResults.resultMaterials[i].sourceMaterials = list; mb2_TextureBakeResults.resultMaterials[i].combinedMaterial = sharedMaterials[i]; } mb2_TextureBakeResults.doMultiMaterial = true; } else { mb2_TextureBakeResults.doMultiMaterial = false; mb2_TextureBakeResults.prefabUVRects = new Rect[] { new Rect(0f, 0f, 1f, 1f) }; } return(mb2_TextureBakeResults); }
public void DoIntegrityCheckMergedEncapsulatingSamplingRects(List <MB_TexSet> distinctMaterialTextures) { if (MB3_MeshBakerRoot.DO_INTEGRITY_CHECKS) { for (int i = 0; i < distinctMaterialTextures.Count; i++) { MB_TexSet tx1 = distinctMaterialTextures[i]; if (!tx1.allTexturesUseSameMatTiling) { continue; } for (int matIdx = 0; matIdx < tx1.matsAndGOs.mats.Count; matIdx++) { MatAndTransformToMerged mat = tx1.matsAndGOs.mats[matIdx]; DRect uvR = mat.obUVRectIfTilingSame; DRect matR = mat.materialTiling; if (!MB2_TextureBakeResults.IsMeshAndMaterialRectEnclosedByAtlasRect(tx1.tilingTreatment, uvR.GetRect(), matR.GetRect(), tx1.ts[0].GetEncapsulatingSamplingRect().GetRect(), MB2_LogLevel.info)) { Debug.LogErrorFormat("mesh " + tx1.matsAndGOs.mats[matIdx].objName + "\n" + " uv=" + uvR + "\n" + " mat=" + matR.GetRect().ToString("f5") + "\n" + " samplingRect=" + tx1.matsAndGOs.mats[matIdx].samplingRectMatAndUVTiling.GetRect().ToString("f4") + "\n" + " encapsulatingRect " + tx1.ts[0].GetEncapsulatingSamplingRect().GetRect().ToString("f4") + "\n"); Debug.LogErrorFormat(string.Format("Integrity check failed. " + tx1.matsAndGOs.mats[matIdx].objName + " Encapsulating sampling rect failed to contain potentialRect\n")); MB2_TextureBakeResults.IsMeshAndMaterialRectEnclosedByAtlasRect(tx1.tilingTreatment, uvR.GetRect(), matR.GetRect(), tx1.ts[0].GetEncapsulatingSamplingRect().GetRect(), MB2_LogLevel.trace); Debug.Assert(false); } } } } }
internal static IEnumerator FindRuntimeMaterialsFromAddresses(MB2_TextureBakeResults textureBakeResult, MB2_TextureBakeResults.CoroutineResult isComplete) { if (_MBVersion == null) { _MBVersion = _CreateMBVersionConcrete(); } yield return(_MBVersion.FindRuntimeMaterialsFromAddresses(textureBakeResult, isComplete)); }
private void UpgradeToCurrentVersion(MB2_TextureBakeResults tbr) { if (tbr.version < 3252) { for (int i = 0; i < tbr.materialsAndUVRects.Length; i++) { tbr.materialsAndUVRects[i].allPropsUseSameTiling = true; } } }
protected virtual bool _CreateTemporaryTextrueBakeResult(GameObject[] gos, List <Material> matsOnTargetRenderer) { if (GetNumObjectsInCombined() > 0) { Debug.LogError("Can't add objects if there are already objects in combined mesh when 'Texture Bake Result' is not set. Perhaps enable 'Clear Buffers After Bake'"); return(false); } _usingTemporaryTextureBakeResult = true; _textureBakeResults = MB2_TextureBakeResults.CreateForMaterialsOnRenderer(gos, matsOnTargetRenderer); return(true); }
/// <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); }
//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; } } } } }
protected virtual bool _CheckIfAllObjsToAddUseSameMaterialsAndCreateTemporaryTextrueBakeResult(GameObject[] gos) { _usingTemporaryTextureBakeResult = false; Renderer r = MB_Utility.GetRenderer(gos[0]); if (r != null) { Material[] mats = MB_Utility.GetGOMaterials(gos[0]); 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(false); } Material[] oMats = MB_Utility.GetGOMaterials(gos[i]); if (oMats == null) { Debug.LogError(string.Format("Game object {0} in list of objects to add no renderer", i)); return(false); } for (int j = 0; j < oMats.Length; j++) { bool found = false; for (int k = 0; k < mats.Length; k++) { if (oMats[j] == mats[k]) { found = true; break; } } if (found == false) { Debug.LogError(string.Format("Material Bake Result is null and game object {0} in list of objects to add did not have a subset of the materials in on the first object. You need to bake textures or all objects must have a subset of materials on the first object.", i)); return(false); } } } _usingTemporaryTextureBakeResult = true; _textureBakeResults = MB2_TextureBakeResults.CreateForMaterialsOnRenderer(r); return(true); } return(false); }
void unpackMat2RectMap(MB2_TextureBakeResults results) { List <Material> ms = new List <Material>(); List <Rect> rs = new List <Rect>(); for (int i = 0; i < results.combinedMaterialInfo.Length; i++) { MB_AtlasesAndRects newMesh = results.combinedMaterialInfo[i]; Dictionary <Material, Rect> map = newMesh.mat2rect_map; foreach (Material m in map.Keys) { ms.Add(m); rs.Add(map[m]); } } results.materials = ms.ToArray(); results.prefabUVRects = rs.ToArray(); }
private void unpackMat2RectMap(MB2_TextureBakeResults resultAtlasesAndRects) { List <Material> list = new List <Material>(); List <Rect> list2 = new List <Rect>(); for (int i = 0; i < resultAtlasesAndRects.combinedMaterialInfo.Length; i++) { MB_AtlasesAndRects mb_AtlasesAndRects = resultAtlasesAndRects.combinedMaterialInfo[i]; Dictionary <Material, Rect> mat2rect_map = mb_AtlasesAndRects.mat2rect_map; foreach (Material material in mat2rect_map.Keys) { list.Add(material); list2.Add(mat2rect_map[material]); } } resultAtlasesAndRects.materials = list.ToArray(); resultAtlasesAndRects.prefabUVRects = list2.ToArray(); }
/* * MB_AtlasesAndRects[] _CreateAtlases(ProgressUpdateDelegate progressInfo, bool saveAtlasesAsAssets = false, MB2_EditorMethodsInterface editorMethods = null) * { * //validation * if (saveAtlasesAsAssets && editorMethods == null) * { * Debug.LogError("Error in CreateAtlases If saveAtlasesAsAssets = true then editorMethods cannot be null."); * return null; * } * if (saveAtlasesAsAssets && !Application.isEditor) * { * Debug.LogError("Error in CreateAtlases If saveAtlasesAsAssets = true it must be called from the Unity Editor."); * return null; * } * MB2_ValidationLevel vl = Application.isPlaying ? MB2_ValidationLevel.quick : MB2_ValidationLevel.robust; * if (!DoCombinedValidate(this, MB_ObjsToCombineTypes.dontCare, editorMethods, vl)) * { * return null; * } * if (_doMultiMaterial && !_ValidateResultMaterials()) * { * return null; * } * else if (!_doMultiMaterial) * { * if (_resultMaterial == null) * { * Debug.LogError("Combined Material is null please create and assign a result material."); * return null; * } * Shader targShader = _resultMaterial.shader; * for (int i = 0; i < objsToMesh.Count; i++) * { * Material[] ms = MB_Utility.GetGOMaterials(objsToMesh[i]); * for (int j = 0; j < ms.Length; j++) * { * Material m = ms[j]; * if (m != null && m.shader != targShader) * { * Debug.LogWarning("Game object " + objsToMesh[i] + " does not use shader " + targShader + " it may not have the required textures. If not small solid color textures will be generated."); * } * * } * } * } * * for (int i = 0; i < objsToMesh.Count; i++) * { * Material[] ms = MB_Utility.GetGOMaterials(objsToMesh[i]); * for (int j = 0; j < ms.Length; j++) * { * Material m = ms[j]; * if (m == null) * { * Debug.LogError("Game object " + objsToMesh[i] + " has a null material. Can't build atlases"); * return null; * } * * } * } * * MB3_TextureCombiner combiner = new MB3_TextureCombiner(); * combiner.LOG_LEVEL = LOG_LEVEL; * combiner.atlasPadding = _atlasPadding; * combiner.maxAtlasSize = _maxAtlasSize; * combiner.customShaderPropNames = _customShaderProperties; * combiner.fixOutOfBoundsUVs = _fixOutOfBoundsUVs; * combiner.maxTilingBakeSize = _maxTilingBakeSize; * combiner.packingAlgorithm = _packingAlgorithm; * combiner.meshBakerTexturePackerForcePowerOfTwo = _meshBakerTexturePackerForcePowerOfTwo; * combiner.resizePowerOfTwoTextures = _resizePowerOfTwoTextures; * combiner.saveAtlasesAsAssets = saveAtlasesAsAssets; * combiner.considerNonTextureProperties = _considerNonTextureProperties; * * // if editor analyse meshes and suggest treatment * if (!Application.isPlaying && _doSuggestTreatment) * { * Material[] rms; * if (_doMultiMaterial) * { * rms = new Material[resultMaterials.Length]; * for (int i = 0; i < rms.Length; i++) rms[i] = resultMaterials[i].combinedMaterial; * } * else * { * rms = new Material[1]; * rms[0] = _resultMaterial; * } * combiner.SuggestTreatment(objsToMesh, rms, combiner.customShaderPropNames); * } * * //initialize structure to store results * int numResults = 1; * if (_doMultiMaterial) numResults = resultMaterials.Length; * MB_AtlasesAndRects[] resultAtlasesAndRects = new MB_AtlasesAndRects[numResults]; * for (int i = 0; i < resultAtlasesAndRects.Length; i++) * { * resultAtlasesAndRects[i] = new MB_AtlasesAndRects(); * } * * //Do the material combining. * for (int i = 0; i < resultAtlasesAndRects.Length; i++) * { * Material resMatToPass = null; * List<Material> sourceMats = null; * if (_doMultiMaterial) * { * sourceMats = resultMaterials[i].sourceMaterials; * resMatToPass = resultMaterials[i].combinedMaterial; * } * else * { * resMatToPass = _resultMaterial; * } * Debug.Log(string.Format("Creating atlases for result material {0} using shader {1}", resMatToPass, resMatToPass.shader)); * if (!combiner.CombineTexturesIntoAtlases(progressInfo, resultAtlasesAndRects[i], resMatToPass, objsToMesh, sourceMats, editorMethods)) * { * return null; * } * } * * //Save the results * textureBakeResults.combinedMaterialInfo = resultAtlasesAndRects; * textureBakeResults.doMultiMaterial = _doMultiMaterial; * textureBakeResults.resultMaterial = _resultMaterial; * textureBakeResults.resultMaterials = resultMaterials; * textureBakeResults.fixOutOfBoundsUVs = combiner.fixOutOfBoundsUVs; * unpackMat2RectMap(textureBakeResults); * * //set the texture bake resultAtlasesAndRects on the Mesh Baker component if it exists * MB3_MeshBakerCommon[] mb = GetComponentsInChildren<MB3_MeshBakerCommon>(); * for (int i = 0; i < mb.Length; i++) * { * mb[i].textureBakeResults = textureBakeResults; * } * * if (LOG_LEVEL >= MB2_LogLevel.info) Debug.Log("Created Atlases"); * return resultAtlasesAndRects; * } */ void unpackMat2RectMap(MB2_TextureBakeResults tbr) { List <Material> ms = new List <Material>(); List <MB_MaterialAndUVRect> mss = new List <MB_MaterialAndUVRect>(); List <Rect> rs = new List <Rect>(); for (int i = 0; i < tbr.combinedMaterialInfo.Length; i++) { MB_AtlasesAndRects newMesh = tbr.combinedMaterialInfo[i]; List <MB_MaterialAndUVRect> map = newMesh.mat2rect_map; for (int j = 0; j < map.Count; j++) { mss.Add(map[j]); ms.Add(map[j].material); rs.Add(map[j].atlasRect); } } tbr.materialsAndUVRects = mss.ToArray(); tbr.materials = ms.ToArray(); tbr.prefabUVRects = rs.ToArray(); }
void unpackMat2RectMap(MB2_TextureBakeResults tbr) { List <Material> ms = new List <Material>(); List <MB_MaterialAndUVRect> mss = new List <MB_MaterialAndUVRect>(); List <Rect> rs = new List <Rect>(); for (int i = 0; i < OnCombinedTexturesCoroutineAtlasesAndRects.Length; i++) { MB_AtlasesAndRects newMesh = this.OnCombinedTexturesCoroutineAtlasesAndRects[i]; List <MB_MaterialAndUVRect> map = newMesh.mat2rect_map; if (map != null) { for (int j = 0; j < map.Count; j++) { mss.Add(map[j]); ms.Add(map[j].material); rs.Add(map[j].atlasRect); } } } tbr.version = MB2_TextureBakeResults.VERSION; tbr.materialsAndUVRects = mss.ToArray(); }
public UVAdjuster_Atlas(MB2_TextureBakeResults tbr, MB2_LogLevel ll) { textureBakeResults = tbr; LOG_LEVEL = ll; matsAndSrcUVRect = tbr.materialsAndUVRects; //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; } } } } }
bool IsGoodToBake(Renderer r, MB2_TextureBakeResults tbr){ if (r == null) return false; if (!(r is MeshRenderer) && !(r is SkinnedMeshRenderer)){ return false; } Material[] mats = r.sharedMaterials; for (int i = 0; i < mats.Length; i++){ if (!ArrayUtility.Contains<Material>(tbr.materials,mats[i])){ Debug.LogWarning("Mesh on " + r + " uses a material " + mats[i] + " that is not in the list of materials. This mesh will not be baked. The original mesh and material will be used in the result prefab."); //todo assign the source assets to the result return false; } } if (MB_Utility.GetMesh(r.gameObject) == null){ return false; } return true; }
void unpackMat2RectMap(MB2_TextureBakeResults resultAtlasesAndRects){ List<Material> ms = new List<Material>(); List<Rect> rs = new List<Rect>(); for (int i = 0; i < resultAtlasesAndRects.combinedMaterialInfo.Length; i++){ MB_AtlasesAndRects newMesh = resultAtlasesAndRects.combinedMaterialInfo[i]; Dictionary<Material,Rect> map = newMesh.mat2rect_map; foreach(Material m in map.Keys){ ms.Add(m); rs.Add(map[m]); } } resultAtlasesAndRects.materials = ms.ToArray(); resultAtlasesAndRects.prefabUVRects = rs.ToArray(); }
/// <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, out int sliceIdx, ref String errorMsg, MB2_LogLevel logLevel) { if (textureBakeResults.version < MB2_TextureBakeResults.VERSION) { textureBakeResults.UpgradeToCurrentVersion(textureBakeResults); } tilingTreatment = MB_TextureTilingTreatment.unknown; if (textureBakeResults.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(); sliceIdx = -1; return(false); } if (mat == null) { rectInAtlas = new Rect(); encapsulatingRectOut = new Rect(); sourceMaterialTilingOut = new Rect(); sliceIdx = -1; 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(); sliceIdx = -1; 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(); sliceIdx = -1; errorMsg = String.Format("Material {0} could not be found in the Texture Bake Result", mat.name); return(false); } bool considerUVs = textureBakeResults.GetConsiderMeshUVs(idxInResultMats, mat); if (!considerUVs) { if (numTimesMatAppearsInAtlas[idx] != 1) { Debug.LogError("There is a problem with this TextureBakeResults. FixOutOfBoundsUVs is false and a material appears more than once: " + matsAndSrcUVRect[idx].material + " appears: " + numTimesMatAppearsInAtlas[idx]); } MB_MaterialAndUVRect mr = matsAndSrcUVRect[idx]; rectInAtlas = mr.atlasRect; tilingTreatment = mr.tilingTreatment; encapsulatingRectOut = mr.GetEncapsulatingRect(); sourceMaterialTilingOut = mr.GetMaterialTilingRect(); sliceIdx = mr.textureArraySliceIdx; 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 (MB2_TextureBakeResults.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(); sliceIdx = mr.textureArraySliceIdx; return(true); } else { rectInAtlas = new Rect(); encapsulatingRectOut = new Rect(); sourceMaterialTilingOut = new Rect(); sliceIdx = -1; 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}. Was this mesh included when atlases were baked?", m.name, mat); return(false); } } }
void bake(MB3_MeshBakerCommon mom) { bool createdDummyTextureBakeResults = false; try{ if (mom.textureBakeResults == null) { if (_OkToCreateDummyTextureBakeResult(mom)) { createdDummyTextureBakeResults = true; List <GameObject> gos = mom.GetObjectsToCombine(); mom.textureBakeResults = MB2_TextureBakeResults.CreateForMaterialsOnRenderer(MB_Utility.GetRenderer(gos[0])); } } if (mom.meshCombiner.outputOption == MB2_OutputOptions.bakeIntoSceneObject) { MB3_MeshBakerEditorFunctions.BakeIntoCombined(mom); } else if (mom.meshCombiner.outputOption == MB2_OutputOptions.bakeIntoPrefab) { MB3_MeshBakerEditorFunctions.BakeIntoCombined(mom); } else { if (mom is MB3_MeshBaker) { if (MB3_MeshCombiner.EVAL_VERSION) { Debug.LogError("Bake Meshes In Place is disabled in the evaluation version."); } else { MB2_ValidationLevel vl = Application.isPlaying ? MB2_ValidationLevel.quick : MB2_ValidationLevel.robust; if (!MB3_MeshBakerRoot.DoCombinedValidate(mom, MB_ObjsToCombineTypes.prefabOnly, new MB3_EditorMethods(), vl)) { return; } List <GameObject> objsToMesh = mom.GetObjectsToCombine(); //objsToMesh = mom.GetComponent<MB3_TextureBaker>().GetObjectsToCombine(); MB3_BakeInPlace.BakeMeshesInPlace((MB3_MeshCombinerSingle)((MB3_MeshBaker)mom).meshCombiner, objsToMesh, mom.bakeAssetsInPlaceFolderPath, updateProgressBar); } } else { Debug.LogError("Multi-mesh Baker components cannot be used for Bake In Place. Use an ordinary Mesh Baker object instead."); } } if (mom.clearBuffersAfterBake) { mom.meshCombiner.ClearBuffers(); } } catch (Exception e) { Debug.LogError(e); } finally { if (createdDummyTextureBakeResults) { GameObject.DestroyImmediate(mom.textureBakeResults); mom.textureBakeResults = null; } EditorUtility.ClearProgressBar(); } }
/// <summary> /// Bakes a combined mesh. /// </summary> /// <param name="so">If this is being called from Inspector code then pass in the SerializedObject for the component. /// This is necessary for "bake into prefab" which can corrupt the SerializedObject.</param> public static bool BakeIntoCombined(MB3_MeshBakerCommon mom, out bool createdDummyTextureBakeResults, ref SerializedObject so) { MB2_OutputOptions prefabOrSceneObject = mom.meshCombiner.outputOption; createdDummyTextureBakeResults = false; // Initial Validate { if (mom.meshCombiner.resultSceneObject != null && (MBVersionEditor.PrefabUtility_GetPrefabType(mom.meshCombiner.resultSceneObject) == MB_PrefabType.modelPrefabAsset || MBVersionEditor.PrefabUtility_GetPrefabType(mom.meshCombiner.resultSceneObject) == MB_PrefabType.prefabAsset)) { Debug.LogWarning("Result Game Object was a project asset not a scene object instance. Clearing this field."); mom.meshCombiner.resultSceneObject = null; } if (prefabOrSceneObject != MB2_OutputOptions.bakeIntoPrefab && prefabOrSceneObject != MB2_OutputOptions.bakeIntoSceneObject) { Debug.LogError("Paramater prefabOrSceneObject must be bakeIntoPrefab or bakeIntoSceneObject"); return(false); } if (prefabOrSceneObject == MB2_OutputOptions.bakeIntoPrefab) { if (MB3_MeshCombiner.EVAL_VERSION) { Debug.LogError("Cannot BakeIntoPrefab with evaluation version."); return(false); } if (mom.resultPrefab == null) { Debug.LogError("Need to set the Combined Mesh Prefab field. Create a prefab asset, drag an empty game object into it, and drag it to the 'Combined Mesh Prefab' field."); return(false); } string prefabPth = AssetDatabase.GetAssetPath(mom.resultPrefab); if (prefabPth == null || prefabPth.Length == 0) { Debug.LogError("Could not save result to prefab. Result Prefab value is not a project asset. Is it an instance in the scene?"); return(false); } } } { // Find or create texture bake results MB3_TextureBaker tb = mom.GetComponentInParent <MB3_TextureBaker>(); if (mom.textureBakeResults == null && tb != null) { mom.textureBakeResults = tb.textureBakeResults; } if (mom.textureBakeResults == null) { if (_OkToCreateDummyTextureBakeResult(mom)) { createdDummyTextureBakeResults = true; List <GameObject> gos = mom.GetObjectsToCombine(); if (mom.GetNumObjectsInCombined() > 0) { if (mom.clearBuffersAfterBake) { mom.ClearMesh(); } else { Debug.LogError("'Texture Bake Result' must be set to add more objects to a combined mesh that already contains objects. Try enabling 'clear buffers after bake'"); return(false); } } mom.textureBakeResults = MB2_TextureBakeResults.CreateForMaterialsOnRenderer(gos.ToArray(), mom.meshCombiner.GetMaterialsOnTargetRenderer()); if (mom.meshCombiner.LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("'Texture Bake Result' was not set. Creating a temporary one. Each material will be mapped to a separate submesh."); } } } } // Second level of validation now that TextureBakeResults exists. MB2_ValidationLevel vl = Application.isPlaying ? MB2_ValidationLevel.quick : MB2_ValidationLevel.robust; if (!MB3_MeshBakerRoot.DoCombinedValidate(mom, MB_ObjsToCombineTypes.sceneObjOnly, new MB3_EditorMethods(), vl)) { return(false); } // Add Delete Game Objects bool success; if (prefabOrSceneObject == MB2_OutputOptions.bakeIntoSceneObject) { success = _BakeIntoCombinedSceneObject(mom, createdDummyTextureBakeResults, ref so); } else if (prefabOrSceneObject == MB2_OutputOptions.bakeIntoPrefab) { success = _BakeIntoCombinedPrefab(mom, createdDummyTextureBakeResults, ref so); } else { Debug.LogError("Should be impossible."); success = false; } if (mom.clearBuffersAfterBake) { mom.meshCombiner.ClearBuffers(); } if (createdDummyTextureBakeResults) { MB_Utility.Destroy(mom.textureBakeResults); } return(success); }
public override void meshAssign_UV0(int channel, MB_IMeshBakerSettings settings, MB2_TextureBakeResults textureBakeResults, Mesh mesh, Vector2[] uvs, float[] sliceIndexes) { if (textureBakeResults.resultType == MB2_TextureBakeResults.ResultType.atlas) { mesh.uv = uvs; } else { { if (uvs.Length == sliceIndexes.Length) { List <Vector3> nuvs = new List <Vector3>(); for (int i = 0; i < uvs.Length; i++) { nuvs.Add(new Vector3(uvs[i].x, uvs[i].y, sliceIndexes[i])); } mesh.SetUVs(0, nuvs); } else { Debug.LogError("UV slice buffer was not the same size as the uv buffer"); } } } }
public static void DefaultDelegateAssignMeshColors(MB_IMeshBakerSettings settings, MB2_TextureBakeResults textureBakeResults, Mesh mesh, Color[] colors, float[] sliceIndexes) { mesh.colors = colors; }
public void _bakePrefabs() { Debug.Log("Batch baking prefabs"); if (Application.isPlaying) { Debug.LogError("The BatchPrefabBaker cannot be run in play mode."); return; } MB3_BatchPrefabBaker pb = (MB3_BatchPrefabBaker)target; MB3_MeshBaker mb = pb.GetComponent <MB3_MeshBaker>(); if (mb == null) { Debug.LogError("Prefab baker needs to be attached to a Game Object with a MB3_MeshBaker component."); return; } if (mb.textureBakeResults == null) { Debug.LogError("Texture Bake Results is not set"); return; } if (mb.meshCombiner.outputOption != MB2_OutputOptions.bakeMeshAssetsInPlace) { mb.meshCombiner.outputOption = MB2_OutputOptions.bakeMeshAssetsInPlace; } MB2_TextureBakeResults tbr = mb.textureBakeResults; HashSet <Mesh> sourceMeshes = new HashSet <Mesh>(); HashSet <Mesh> allResultMeshes = new HashSet <Mesh>(); //validate prefabs for (int i = 0; i < pb.prefabRows.Length; i++) { if (pb.prefabRows[i] == null || pb.prefabRows[i].sourcePrefab == null) { Debug.LogError("Source Prefab on row " + i + " is not set."); return; } if (pb.prefabRows[i].resultPrefab == null) { Debug.LogError("Result Prefab on row " + i + " is not set."); return; } for (int j = i + 1; j < pb.prefabRows.Length; j++) { if (pb.prefabRows[i].sourcePrefab == pb.prefabRows[j].sourcePrefab) { Debug.LogError("Rows " + i + " and " + j + " contain the same source prefab"); return; } } for (int j = 0; j < pb.prefabRows.Length; j++) { if (pb.prefabRows[i].sourcePrefab == pb.prefabRows[j].resultPrefab) { Debug.LogError("Row " + i + " source prefab is the same as row " + j + " result prefab"); return; } } if (PrefabUtility.GetPrefabType(pb.prefabRows[i].sourcePrefab) != PrefabType.ModelPrefab && PrefabUtility.GetPrefabType(pb.prefabRows[i].sourcePrefab) != PrefabType.Prefab) { Debug.LogError("Row " + i + " source prefab is not a prefab asset"); return; } if (PrefabUtility.GetPrefabType(pb.prefabRows[i].resultPrefab) != PrefabType.ModelPrefab && PrefabUtility.GetPrefabType(pb.prefabRows[i].resultPrefab) != PrefabType.Prefab) { Debug.LogError("Row " + i + " result prefab is not a prefab asset"); return; } GameObject so = (GameObject)Instantiate(pb.prefabRows[i].sourcePrefab); GameObject ro = (GameObject)Instantiate(pb.prefabRows[i].resultPrefab); Renderer[] rs = (Renderer[])so.GetComponentsInChildren <Renderer>(); for (int j = 0; j < rs.Length; j++) { if (IsGoodToBake(rs[j], tbr)) { sourceMeshes.Add(MB_Utility.GetMesh(rs[j].gameObject)); } } rs = (Renderer[])ro.GetComponentsInChildren <Renderer>(); for (int j = 0; j < rs.Length; j++) { Renderer r = rs[j]; if (r is MeshRenderer || r is SkinnedMeshRenderer) { Mesh m = MB_Utility.GetMesh(r.gameObject); if (m != null) { allResultMeshes.Add(m); } } } DestroyImmediate(so); //todo should cache these and have a proper cleanup at end DestroyImmediate(ro); } sourceMeshes.IntersectWith(allResultMeshes); HashSet <Mesh> sourceMeshesThatAreUsedByResult = sourceMeshes; if (sourceMeshesThatAreUsedByResult.Count > 0) { foreach (Mesh m in sourceMeshesThatAreUsedByResult) { Debug.LogWarning("Mesh " + m + " is used by both the source and result prefabs. New meshes will be created."); } //return; } Dictionary <string, string> createdMeshPaths = new Dictionary <string, string>(); // Bake the meshes using the meshBaker component one prefab at a time for (int prefabIdx = 0; prefabIdx < pb.prefabRows.Length; prefabIdx++) { Debug.Log("==== Processing Source Prefab " + pb.prefabRows[prefabIdx].sourcePrefab); GameObject sceneObj = (GameObject)Instantiate(pb.prefabRows[prefabIdx].sourcePrefab); GameObject resultPrefab = (GameObject)Instantiate(pb.prefabRows[prefabIdx].resultPrefab); Renderer[] rs = sceneObj.GetComponentsInChildren <Renderer>(); if (rs.Length < 1) { Debug.LogWarning("Prefab " + prefabIdx + " does not have a renderer"); DestroyImmediate(sceneObj); DestroyImmediate(resultPrefab); continue; } List <Mesh> usedMeshes = new List <Mesh>(); List <UnityTransform> unityTransforms = new List <UnityTransform>(); for (int j = 0; j < rs.Length; j++) { unityTransforms.Clear(); Renderer r = rs[j]; if (!IsGoodToBake(r, tbr)) { continue; } //find the corresponding mesh in the result prefab string resultFolderPath = AssetDatabase.GetAssetPath(pb.prefabRows[prefabIdx].resultPrefab); resultFolderPath = Path.GetDirectoryName(resultFolderPath); Mesh m = null; Transform tRes = FindCorrespondingTransform(sceneObj.transform, r.transform, resultPrefab.transform); if (tRes != null) { m = MB_Utility.GetMesh(tRes.gameObject); } //if the meshes on source and result are the same we want to remove mesh so will create a new one if (sourceMeshesThatAreUsedByResult.Contains(m)) { Debug.LogWarning("Source and result prefabs share a mesh. Creating a new mesh for " + m); MB_Utility.SetMesh(tRes.gameObject, null); m = null; } string meshPath; //check that the mesh is an asset and that we have not used it already if (m != null && AssetDatabase.IsMainAsset(m.GetInstanceID()) && !usedMeshes.Contains(m)) { meshPath = AssetDatabase.GetAssetPath(m); if (createdMeshPaths.ContainsKey(meshPath)) { Debug.LogWarning("Different result prefabs share a mesh." + meshPath); } } else //create a new mesh asset with a unique name { string resultPrefabFilename = AssetDatabase.GetAssetPath(pb.prefabRows[prefabIdx].resultPrefab); resultPrefabFilename = resultPrefabFilename.Substring(0, resultPrefabFilename.Length - ".prefab".Length) + ".asset"; meshPath = AssetDatabase.GenerateUniqueAssetPath(resultPrefabFilename); m = new Mesh(); AssetDatabase.CreateAsset(m, meshPath); m = (Mesh)AssetDatabase.LoadAssetAtPath(meshPath, typeof(Mesh)); } Debug.Log(" creating new mesh asset at path " + meshPath); if (!createdMeshPaths.ContainsKey(meshPath)) { createdMeshPaths.Add(meshPath, meshPath); } // position rotation and scale are baked into combined mesh. // Remember all the transforms settings then // record transform values to root of hierarchy Transform t = r.transform; if (t != t.root) { do { unityTransforms.Add(new UnityTransform(t)); t = t.parent; } while (t != null && t != t.root); } //add the root unityTransforms.Add(new UnityTransform(t.root)); //position at identity for (int k = 0; k < unityTransforms.Count; k++) { unityTransforms[k].t.localPosition = Vector3.zero; unityTransforms[k].t.localRotation = Quaternion.identity; unityTransforms[k].t.localScale = Vector3.one; } //throw new Exception(""); //bake the mesh mb.ClearMesh(); MB3_MeshCombiner mc = mb.meshCombiner; m = MB3_BakeInPlace.BakeOneMesh((MB3_MeshCombinerSingle)mc, meshPath, r.gameObject); //replace the mesh if (r is MeshRenderer) { MeshFilter mf = r.gameObject.GetComponent <MeshFilter>(); mf.sharedMesh = m; } else //skinned mesh { SkinnedMeshRenderer smr = r.gameObject.GetComponent <SkinnedMeshRenderer>(); smr.sharedMesh = m; smr.bones = ((SkinnedMeshRenderer)mc.targetRenderer).bones; } //replace the result material(s) if (mb.textureBakeResults.doMultiMaterial) { Material[] rss = new Material[mb.textureBakeResults.resultMaterials.Length]; for (int k = 0; k < rss.Length; k++) { rss[k] = mb.textureBakeResults.resultMaterials[k].combinedMaterial; } r.sharedMaterials = rss; } else { Material[] originalMats = r.sharedMaterials; Material[] rss = new Material[originalMats.Length]; for (int k = 0; k < originalMats.Length; k++) { if (tbr.ContainsMaterial(originalMats[k])) { rss[k] = mb.textureBakeResults.resultMaterial; } else { rss[k] = originalMats[k]; } } r.sharedMaterials = rss; } //restore the transforms for (int k = 0; k < unityTransforms.Count; k++) { unityTransforms[k].t.localPosition = unityTransforms[k].p; unityTransforms[k].t.localRotation = unityTransforms[k].q; unityTransforms[k].t.localScale = unityTransforms[k].s; } } //replace the result prefab with the source object //duplicate the sceneObj so we can replace the clone into the prefab, not the source GameObject clone = (GameObject)Instantiate(sceneObj); PrefabUtility.ReplacePrefab(clone, pb.prefabRows[prefabIdx].resultPrefab, ReplacePrefabOptions.ReplaceNameBased); DestroyImmediate(clone); DestroyImmediate(sceneObj); DestroyImmediate(resultPrefab); } AssetDatabase.Refresh(); mb.ClearMesh(); }
protected virtual bool _CheckIfAllObjsToAddUseSameMaterialsAndCreateTemporaryTextrueBakeResult(GameObject[] gos){ _usingTemporaryTextureBakeResult = false; Renderer r = MB_Utility.GetRenderer(gos[0]); if (r != null){ Material[] mats = MB_Utility.GetGOMaterials(gos[0]); 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 false; } Material[] oMats = MB_Utility.GetGOMaterials(gos[i]); if (oMats == null){ Debug.LogError(string.Format("Game object {0} in list of objects to add no renderer", i)); return false; } for (int j = 0; j <oMats.Length; j++){ bool found = false; for (int k = 0; k < mats.Length; k++){ if (oMats[j] == mats[k]){ found = true; break; } } if (found == false){ Debug.LogError (string.Format("Material Bake Result is null and game object {0} in list of objects to add did not have a subset of the materials in on the first object. You need to bake textures or all objects must have a subset of materials on the first object.",i)); return false; } } } _usingTemporaryTextureBakeResult = true; _textureBakeResults = MB2_TextureBakeResults.CreateForMaterialsOnRenderer(r); return true; } return false; }
private static void ProcessPrefabRowReplaceTargetPrefab(MB3_BatchPrefabBaker pb, MB3_BatchPrefabBaker.MB3_PrefabBakerRow pr, MB2_TextureBakeResults tbr, List <UnityTransform> unityTransforms, MB3_MeshBaker mb) { if (pb.LOG_LEVEL >= MB2_LogLevel.info) { Debug.Log("==== Processing Source Prefab " + pr.sourcePrefab); } GameObject srcPrefab = pr.sourcePrefab; GameObject targetPrefab = pr.resultPrefab; string targetPrefabName = AssetDatabase.GetAssetPath(targetPrefab); GameObject prefabInstance = GameObject.Instantiate(srcPrefab); Renderer[] rs = prefabInstance.GetComponentsInChildren <Renderer>(); if (rs.Length < 1) { Debug.LogWarning("Prefab " + pr.sourcePrefab + " does not have a renderer"); DestroyImmediate(prefabInstance); return; } Renderer[] sourceRenderers = prefabInstance.GetComponentsInChildren <Renderer>(); Dictionary <Mesh, List <ProcessedMeshInfo> > processedMeshesSrcToTargetMap = new Dictionary <Mesh, List <ProcessedMeshInfo> >(); for (int i = 0; i < sourceRenderers.Length; i++) { if (!IsGoodToBake(sourceRenderers[i], tbr)) { continue; } Mesh sourceMesh = MB_Utility.GetMesh(sourceRenderers[i].gameObject); if (pb.LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("== Visiting renderer: " + sourceRenderers[i]); } // Try to find an existing mesh in the target that we can re-use Mesh targetMeshAsset = null; Transform tr = FindCorrespondingTransform(prefabInstance.transform, sourceRenderers[i].transform, targetPrefab.transform); if (tr != null) { Mesh targMesh = MB_Utility.GetMesh(tr.gameObject); // Only replace target meshes if they are part of the target prefab. if (AssetDatabase.GetAssetPath(targMesh) == AssetDatabase.GetAssetPath(targetPrefab)) { targetMeshAsset = MB_Utility.GetMesh(tr.gameObject); if (pb.LOG_LEVEL >= MB2_LogLevel.trace) { Debug.Log("Found correspoinding transform in target prefab: " + tr + " mesh: " + targetMeshAsset); } } } // Check that we haven't processed this mesh already. List <ProcessedMeshInfo> lpmi; if (processedMeshesSrcToTargetMap.TryGetValue(sourceMesh, out lpmi)) { Material[] srcMats = MB_Utility.GetGOMaterials(sourceRenderers[i].gameObject); for (int j = 0; j < lpmi.Count; j++) { if (ComapreMaterials(srcMats, lpmi[j].srcMaterials)) { if (pb.LOG_LEVEL >= MB2_LogLevel.trace) { Debug.Log("Found already processed mesh that uses the same mats"); } targetMeshAsset = lpmi[j].targetMesh; break; } } } Material[] sourceMaterials = MB_Utility.GetGOMaterials(sourceRenderers[i].gameObject); TargetMeshTreatment targetMeshTreatment = TargetMeshTreatment.createNewMesh; string newMeshName = sourceMesh.name; if (targetMeshAsset != null) { // check if this mesh has already been processed processedMeshesSrcToTargetMap.TryGetValue(sourceMesh, out lpmi); if (lpmi != null) { // check if this mesh uses the same materials as one of the processed meshs bool foundMatch = false; bool targetMeshHasBeenUsed = false; Material[] foundMatchMaterials = null; for (int j = 0; j < lpmi.Count; j++) { if (lpmi[j].targetMesh == targetMeshAsset) { targetMeshHasBeenUsed = true; } if (ComapreMaterials(sourceMaterials, lpmi[j].srcMaterials)) { foundMatchMaterials = lpmi[j].targMaterials; foundMatch = true; break; } } if (foundMatch) { // If materials match then we can re-use this processed mesh don't process. if (pb.LOG_LEVEL >= MB2_LogLevel.trace) { Debug.Log(" we can re-use this processed mesh don't process. " + targetMeshAsset); } targetMeshTreatment = TargetMeshTreatment.reuseMesh; MB_Utility.SetMesh(sourceRenderers[i].gameObject, targetMeshAsset); SetMaterials(foundMatchMaterials, sourceRenderers[i]); continue; } else { if (targetMeshHasBeenUsed) { // we need a new target mesh with a safe different name if (pb.LOG_LEVEL >= MB2_LogLevel.trace) { Debug.Log(" we can't re-use this processed mesh create new with different name. " + targetMeshAsset); } newMeshName = GetNameForNewMesh(AssetDatabase.GetAssetPath(targetPrefab), newMeshName); targetMeshTreatment = TargetMeshTreatment.createNewMesh; targetMeshAsset = null; } else { // is it safe to reuse the target mesh // we need a new target mesh with a safe different name if (pb.LOG_LEVEL >= MB2_LogLevel.trace) { Debug.Log(" we can replace this processed mesh. " + targetMeshAsset); } targetMeshTreatment = TargetMeshTreatment.replaceMesh; } } } else { // source mesh has not been processed can reuse the target mesh targetMeshTreatment = TargetMeshTreatment.replaceMesh; } } if (targetMeshTreatment == TargetMeshTreatment.replaceMesh) { if (pb.LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("Replace mesh " + targetMeshAsset); } EditorUtility.CopySerialized(sourceMesh, targetMeshAsset); AssetDatabase.SaveAssets(); AssetDatabase.ImportAsset(targetPrefabName); } else if (targetMeshTreatment == TargetMeshTreatment.createNewMesh) { if (pb.LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("Create new mesh " + newMeshName); } targetMeshAsset = GameObject.Instantiate <Mesh>(sourceMesh); targetMeshAsset.name = newMeshName; AssetDatabase.AddObjectToAsset(targetMeshAsset, targetPrefab); #if UNITY_2018_3_OR_NEWER PrefabUtility.SavePrefabAsset(targetPrefab); #endif Debug.Assert(targetMeshAsset != null); // need a new mesh } if (targetMeshTreatment == TargetMeshTreatment.createNewMesh || targetMeshTreatment == TargetMeshTreatment.replaceMesh) { if (ProcessMesh(sourceRenderers[i], targetMeshAsset, unityTransforms, mb)) { if (pb.LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("Done processing mesh " + targetMeshAsset + " verts " + targetMeshAsset.vertexCount); } ProcessedMeshInfo pmi = new ProcessedMeshInfo(); pmi.targetMesh = targetMeshAsset; pmi.srcMaterials = sourceMaterials; pmi.targMaterials = sourceRenderers[i].sharedMaterials; AddToDictionary(sourceMesh, pmi, processedMeshesSrcToTargetMap); } else { Debug.LogError("Error processing mesh " + targetMeshAsset); } } MB_Utility.SetMesh(sourceRenderers[i].gameObject, targetMeshAsset); } // TODO replace this with MBVersionEditor.ReplacePrefab I tried to do this, but when I did, // ProcessedMeshInfo.targetMesh becomes null, not sure what is going on there. GameObject obj = (GameObject)AssetDatabase.LoadAssetAtPath(targetPrefabName, typeof(GameObject)); PrefabUtility.ReplacePrefab(prefabInstance, obj, ReplacePrefabOptions.ReplaceNameBased); GameObject.DestroyImmediate(prefabInstance); // Destroy obsolete meshes UnityEngine.Object[] allAssets = AssetDatabase.LoadAllAssetsAtPath(targetPrefabName); HashSet <Mesh> usedByTarget = new HashSet <Mesh>(); foreach (List <ProcessedMeshInfo> ll in processedMeshesSrcToTargetMap.Values) { for (int i = 0; i < ll.Count; i++) { usedByTarget.Add(ll[i].targetMesh); } } int numDestroyed = 0; for (int i = 0; i < allAssets.Length; i++) { if (allAssets[i] is Mesh) { if (!usedByTarget.Contains((Mesh)allAssets[i]) && AssetDatabase.GetAssetPath(allAssets[i]) == AssetDatabase.GetAssetPath(targetPrefab)) { numDestroyed++; GameObject.DestroyImmediate(allAssets[i], true); } } } if (pb.LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("Destroyed " + numDestroyed + " meshes"); } AssetDatabase.SaveAssets(); //-------------------------- }
public static void BakePrefabs(MB3_BatchPrefabBaker pb, bool doReplaceTargetPrefab) { if (pb.LOG_LEVEL >= MB2_LogLevel.info) { Debug.Log("Batch baking prefabs"); } if (Application.isPlaying) { Debug.LogError("The BatchPrefabBaker cannot be run in play mode."); return; } MB3_MeshBaker mb = pb.GetComponent <MB3_MeshBaker>(); if (mb == null) { Debug.LogError("Prefab baker needs to be attached to a Game Object with a MB3_MeshBaker component."); return; } if (mb.textureBakeResults == null) { Debug.LogError("Texture Bake Results is not set"); return; } if (mb.meshCombiner.outputOption != MB2_OutputOptions.bakeMeshAssetsInPlace) { mb.meshCombiner.outputOption = MB2_OutputOptions.bakeMeshAssetsInPlace; } MB2_TextureBakeResults tbr = mb.textureBakeResults; HashSet <Mesh> sourceMeshes = new HashSet <Mesh>(); HashSet <Mesh> allResultMeshes = new HashSet <Mesh>(); //validate prefabs for (int i = 0; i < pb.prefabRows.Length; i++) { if (pb.prefabRows[i] == null || pb.prefabRows[i].sourcePrefab == null) { Debug.LogError("Source Prefab on row " + i + " is not set."); return; } if (pb.prefabRows[i].resultPrefab == null) { Debug.LogError("Result Prefab on row " + i + " is not set."); return; } for (int j = i + 1; j < pb.prefabRows.Length; j++) { if (pb.prefabRows[i].sourcePrefab == pb.prefabRows[j].sourcePrefab) { Debug.LogError("Rows " + i + " and " + j + " contain the same source prefab"); return; } } for (int j = 0; j < pb.prefabRows.Length; j++) { if (pb.prefabRows[i].sourcePrefab == pb.prefabRows[j].resultPrefab) { Debug.LogError("Row " + i + " source prefab is the same as row " + j + " result prefab"); return; } } if (MBVersionEditor.GetPrefabType(pb.prefabRows[i].sourcePrefab) != MB_PrefabType.modelPrefab && MBVersionEditor.GetPrefabType(pb.prefabRows[i].sourcePrefab) != MB_PrefabType.prefab) { Debug.LogError("Row " + i + " source prefab is not a prefab asset "); return; } if (MBVersionEditor.GetPrefabType(pb.prefabRows[i].resultPrefab) != MB_PrefabType.modelPrefab && MBVersionEditor.GetPrefabType(pb.prefabRows[i].resultPrefab) != MB_PrefabType.prefab) { Debug.LogError("Row " + i + " result prefab is not a prefab asset"); return; } GameObject so = (GameObject)Instantiate(pb.prefabRows[i].sourcePrefab); GameObject ro = (GameObject)Instantiate(pb.prefabRows[i].resultPrefab); Renderer[] rs = (Renderer[])so.GetComponentsInChildren <Renderer>(); for (int j = 0; j < rs.Length; j++) { if (IsGoodToBake(rs[j], tbr)) { sourceMeshes.Add(MB_Utility.GetMesh(rs[j].gameObject)); } } rs = (Renderer[])ro.GetComponentsInChildren <Renderer>(); for (int j = 0; j < rs.Length; j++) { Renderer r = rs[j]; if (r is MeshRenderer || r is SkinnedMeshRenderer) { Mesh m = MB_Utility.GetMesh(r.gameObject); if (m != null) { allResultMeshes.Add(m); } } } DestroyImmediate(so); //todo should cache these and have a proper cleanup at end DestroyImmediate(ro); } sourceMeshes.IntersectWith(allResultMeshes); HashSet <Mesh> sourceMeshesThatAreUsedByResult = sourceMeshes; if (sourceMeshesThatAreUsedByResult.Count > 0) { foreach (Mesh m in sourceMeshesThatAreUsedByResult) { Debug.LogWarning("Mesh " + m + " is used by both the source and result prefabs. New meshes will be created."); } //return; } List <UnityTransform> unityTransforms = new List <UnityTransform>(); // Bake the meshes using the meshBaker component one prefab at a time for (int prefabIdx = 0; prefabIdx < pb.prefabRows.Length; prefabIdx++) { if (doReplaceTargetPrefab) { ProcessPrefabRowReplaceTargetPrefab(pb, pb.prefabRows[prefabIdx], tbr, unityTransforms, mb); } else { ProcessPrefabRowOnlyMeshesAndMaterials(pb, pb.prefabRows[prefabIdx], tbr, unityTransforms, mb); } } AssetDatabase.Refresh(); mb.ClearMesh(); }
public virtual void meshAssign_UV0(int channel, MB_IMeshBakerSettings settings, MB2_TextureBakeResults textureBakeResults, Mesh mesh, Vector2[] uvs, float[] sliceIndexes) { mesh.uv = uvs; }
/// <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); }
public static bool BakeIntoCombined(MB3_MeshBakerCommon mom, out bool createdDummyTextureBakeResults) { MB2_OutputOptions prefabOrSceneObject = mom.meshCombiner.outputOption; createdDummyTextureBakeResults = false; if (MB3_MeshCombiner.EVAL_VERSION && prefabOrSceneObject == MB2_OutputOptions.bakeIntoPrefab){ Debug.LogError("Cannot BakeIntoPrefab with evaluation version."); return false; } if (prefabOrSceneObject != MB2_OutputOptions.bakeIntoPrefab && prefabOrSceneObject != MB2_OutputOptions.bakeIntoSceneObject){ Debug.LogError("Paramater prefabOrSceneObject must be bakeIntoPrefab or bakeIntoSceneObject"); return false; } MB3_TextureBaker tb = mom.GetComponentInParent<MB3_TextureBaker>(); if (mom.textureBakeResults == null && tb != null){ mom.textureBakeResults = tb.textureBakeResults; } if (mom.textureBakeResults == null) { if (_OkToCreateDummyTextureBakeResult(mom)) { createdDummyTextureBakeResults = true; List<GameObject> gos = mom.GetObjectsToCombine(); if (mom.GetNumObjectsInCombined() > 0) { Debug.LogError("'Texture Bake Result' must be set to add more objects to a combined mesh that already contains objects. Try enabling 'clear buffers after bake'"); return false; } mom.textureBakeResults = MB2_TextureBakeResults.CreateForMaterialsOnRenderer(gos.ToArray(), mom.meshCombiner.GetMaterialsOnTargetRenderer()); if (mom.meshCombiner.LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("'Texture Bake Result' was not set. Creating a temporary one. Each material will be mapped to a separate submesh."); } } } MB2_ValidationLevel vl = Application.isPlaying ? MB2_ValidationLevel.quick : MB2_ValidationLevel.robust; if (!MB3_MeshBakerRoot.DoCombinedValidate(mom, MB_ObjsToCombineTypes.sceneObjOnly, new MB3_EditorMethods(),vl)) return false; if (prefabOrSceneObject == MB2_OutputOptions.bakeIntoPrefab && mom.resultPrefab == null){ Debug.LogError("Need to set the Combined Mesh Prefab field. Create a prefab asset, drag an empty game object into it, and drag it to the 'Combined Mesh Prefab' field."); return false; } if (mom.meshCombiner.resultSceneObject != null && (PrefabUtility.GetPrefabType (mom.meshCombiner.resultSceneObject) == PrefabType.ModelPrefab || PrefabUtility.GetPrefabType (mom.meshCombiner.resultSceneObject) == PrefabType.Prefab)) { Debug.LogWarning("Result Game Object was a project asset not a scene object instance. Clearing this field."); mom.meshCombiner.resultSceneObject = null; } mom.ClearMesh(); if (mom.AddDeleteGameObjects(mom.GetObjectsToCombine().ToArray(),null,false)){ mom.Apply( UnwrapUV2 ); if (createdDummyTextureBakeResults) { Debug.Log(String.Format("Successfully baked {0} meshes each material is mapped to its own submesh.", mom.GetObjectsToCombine().Count)); } else { Debug.Log(String.Format("Successfully baked {0} meshes", mom.GetObjectsToCombine().Count)); } if (prefabOrSceneObject == MB2_OutputOptions.bakeIntoSceneObject){ PrefabType pt = PrefabUtility.GetPrefabType(mom.meshCombiner.resultSceneObject); if (pt == PrefabType.Prefab || pt == PrefabType.ModelPrefab){ Debug.LogError("Combined Mesh Object is a prefab asset. If output option bakeIntoSceneObject then this must be an instance in the scene."); return false; } } else if (prefabOrSceneObject == MB2_OutputOptions.bakeIntoPrefab){ string prefabPth = AssetDatabase.GetAssetPath(mom.resultPrefab); if (prefabPth == null || prefabPth.Length == 0){ Debug.LogError("Could not save result to prefab. Result Prefab value is not an Asset."); return false; } string baseName = Path.GetFileNameWithoutExtension(prefabPth); string folderPath = prefabPth.Substring(0,prefabPth.Length - baseName.Length - 7); string newFilename = folderPath + baseName + "-mesh"; SaveMeshsToAssetDatabase(mom, folderPath,newFilename); if (mom.meshCombiner.renderType == MB_RenderType.skinnedMeshRenderer){ Debug.LogWarning("Render type is skinned mesh renderer. " + "Can't create prefab until all bones have been added to the combined mesh object " + mom.resultPrefab + " Add the bones then drag the combined mesh object to the prefab."); } else { RebuildPrefab(mom); } } else { Debug.LogError("Unknown parameter"); return false; } } return true; }
public virtual void meshAssign_colors(MB_IMeshBakerSettings settings, MB2_TextureBakeResults textureBakeResults, Mesh mesh, Color[] colors, float[] sliceIndexes) { mesh.colors = colors; }
public virtual void meshAssign_UV8(int channel, MB_IMeshBakerSettings settings, MB2_TextureBakeResults textureBakeResults, Mesh mesh, Vector2[] uvs, float[] sliceIndexes) { #if UNITY_2018_2_OR_NEWER mesh.uv8 = uvs; #endif }