/// <summary> /// 多材质验证 /// </summary> /// <returns></returns> bool _ValidateResultMaterials() { HashSet <Material> allMatsOnObjs = new HashSet <Material>(); for (int i = 0; i < objsToMesh.Count; i++) { if (objsToMesh[i] != null) { Material[] ms = MeshBakerUtility.GetGOMaterials(objsToMesh[i]); for (int j = 0; j < ms.Length; j++) { if (ms[j] != null) { allMatsOnObjs.Add(ms[j]); } } } } //多材质判断 HashSet <Material> allMatsInMapping = new HashSet <Material>(); for (int i = 0; i < resultMaterials.Length; i++) { //查重 for (int j = i + 1; j < resultMaterials.Length; j++) { if (resultMaterials[i].combinedMaterial == resultMaterials[j].combinedMaterial) { Debug.LogError(String.Format("Source To Combined Mapping: Submesh {0} and Submesh {1} use the same combined material. These should be different", i, j)); return(false); } } //判空 MultiMaterial mm = resultMaterials[i]; if (mm.combinedMaterial == null) { Debug.LogError("Combined Material is null please create and assign a result material."); return(false); } Shader targShader = mm.combinedMaterial.shader; for (int j = 0; j < mm.sourceMaterials.Count; j++) { if (mm.sourceMaterials[j] == null) { Debug.LogError("There are null entries in the list of Source Materials"); return(false); } if (targShader != mm.sourceMaterials[j].shader) { Debug.LogWarning("Source material " + mm.sourceMaterials[j] + " does not use shader " + targShader + " it may not have the required textures. If not empty textures will be generated."); } if (allMatsInMapping.Contains(mm.sourceMaterials[j])) { Debug.LogError("A Material " + mm.sourceMaterials[j] + " appears more than once in the list of source materials in the source material to combined mapping. Each source material must be unique."); return(false); } allMatsInMapping.Add(mm.sourceMaterials[j]); } } if (allMatsOnObjs.IsProperSubsetOf(allMatsInMapping)) { allMatsInMapping.ExceptWith(allMatsOnObjs); Debug.LogWarning("There are materials in the mapping that are not used on your source objects: " + PrintSet(allMatsInMapping)); } if (resultMaterials != null && resultMaterials.Length > 0 && allMatsInMapping.IsProperSubsetOf(allMatsOnObjs)) { allMatsOnObjs.ExceptWith(allMatsInMapping); Debug.LogError("There are materials on the objects to combine that are not in the mapping: " + PrintSet(allMatsOnObjs)); return(false); } return(true); }
/// <summary> /// 创建贴图 Atlas 协程 /// </summary> /// <returns></returns> public IEnumerator CreateAtlasesCoroutine(ProgressUpdateDelegate progressInfo, CreateAtlasesCoroutineResult coroutineResult, bool saveAtlasesAsAssets = false, EditorMethodsInterface editorMethods = null, float maxTimePerFrame = .01f) { OnCombinedTexturesCoroutineAtlasesAndRects = null; //--- 1、合并前检测 if (maxTimePerFrame <= 0f) { Debug.LogError("maxTimePerFrame must be a value greater than zero"); coroutineResult.isFinished = true; yield break; } //验证等级 ValidationLevel vl = Application.isPlaying ? ValidationLevel.quick : ValidationLevel.robust; //验证 if (!DoCombinedValidate(this, ObjsToCombineTypes.dontCare, null, vl)) { coroutineResult.isFinished = true; yield break; } //合并为多材质验证 if (_doMultiMaterial && !_ValidateResultMaterials()) { coroutineResult.isFinished = true; yield break; } else if (!_doMultiMaterial) { //合并为单独材质 if (_resultMaterial == null) { Debug.LogError("Combined Material is null please create and assign a result material."); coroutineResult.isFinished = true; yield break; } Shader targShader = _resultMaterial.shader; for (int i = 0; i < objsToMesh.Count; i++) { Material[] ms = MeshBakerUtility.GetGOMaterials(objsToMesh[i]); for (int j = 0; j < ms.Length; j++) { Material m = ms[j]; if (m != null && m.shader != targShader) { Debug.LogWarning("游戏物体" + objsToMesh[i] + " 没有使用 shader " + targShader + " it may not have the required textures. " + "If not small solid color textures will be generated."); } } } } TextureCombineHandler combiner = CreateAndConfigureTextureCombiner(); combiner.saveAtlasesAsAssets = saveAtlasesAsAssets; ////--- 2、初始化存储合并结果的数据结构 int numResults = 1; if (_doMultiMaterial) { numResults = resultMaterials.Length; } OnCombinedTexturesCoroutineAtlasesAndRects = new AtlasesAndRects[numResults]; for (int i = 0; i < OnCombinedTexturesCoroutineAtlasesAndRects.Length; i++) { OnCombinedTexturesCoroutineAtlasesAndRects[i] = new AtlasesAndRects(); } //--- 3、开始合并材质(单个,多个) for (int i = 0; i < OnCombinedTexturesCoroutineAtlasesAndRects.Length; i++) { Material resMatToPass; List <Material> sourceMats; if (_doMultiMaterial) { sourceMats = resultMaterials[i].sourceMaterials; resMatToPass = resultMaterials[i].combinedMaterial; combiner.fixOutOfBoundsUVs = resultMaterials[i].considerMeshUVs; } else { resMatToPass = _resultMaterial; sourceMats = null; } //TextureHandler 材质合并协程结果 CombineTexturesIntoAtlasesCoroutineResult coroutineResult2 = new CombineTexturesIntoAtlasesCoroutineResult(); yield return(combiner.CombineTexturesIntoAtlasesCoroutine(progressInfo, OnCombinedTexturesCoroutineAtlasesAndRects[i], resMatToPass, objsToMesh, sourceMats, editorMethods, coroutineResult2, maxTimePerFrame)); coroutineResult.success = coroutineResult2.success; if (!coroutineResult.success) { coroutineResult.isFinished = true; yield break; } } //--- 4、TextureBakeResults 保存合并结果 unpackMat2RectMap(textureBakeResults); textureBakeResults.doMultiMaterial = _doMultiMaterial; if (_doMultiMaterial) { textureBakeResults.resultMaterials = resultMaterials; } else { MultiMaterial[] resMats = new MultiMaterial[1]; resMats[0] = new MultiMaterial(); resMats[0].combinedMaterial = _resultMaterial; resMats[0].considerMeshUVs = _fixOutOfBoundsUVs; resMats[0].sourceMaterials = new List <Material>(); for (int i = 0; i < textureBakeResults.materialsAndUVRects.Length; i++) { resMats[0].sourceMaterials.Add(textureBakeResults.materialsAndUVRects[i].material); } textureBakeResults.resultMaterials = resMats; } //--- 5、传递合并结果到 MeshCombiner MeshBakerCommon[] mb = GetComponentsInChildren <MeshBakerCommon>(); for (int i = 0; i < mb.Length; i++) { mb[i].textureBakeResults = textureBakeResults; } coroutineResult.isFinished = true; //--- 6、合并材质结束回调 if (coroutineResult.success && onBuiltAtlasesSuccess != null) { onBuiltAtlasesSuccess(); } if (!coroutineResult.success && onBuiltAtlasesFail != null) { onBuiltAtlasesFail(); } }