public override bool Equals(object obj) { if (!(obj is MaterialAndUVRect)) { return(false); } MaterialAndUVRect b = (MaterialAndUVRect)obj; return(material == b.material && allPropsUseSameTiling_samplingEncapsulatinRect == b.allPropsUseSameTiling_samplingEncapsulatinRect && allPropsUseSameTiling_sourceMaterialTiling == b.allPropsUseSameTiling_sourceMaterialTiling && allPropsUseSameTiling == b.allPropsUseSameTiling && propsUseDifferntTiling_srcUVsamplingRect == b.propsUseDifferntTiling_srcUVsamplingRect); }
/// <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. /// 尝试获取源物体材质在合并材质中的映射信息 /// 如果使用fixOutOfBoundsUVs,一个材质可以在图集中出现多次。在这种情况下,您需要使用网格的UV矩形来找到正确的矩形。 /// 如果材质上的所有属性都使用相同的拼贴,则 encapsulatingRect 可以更大,并将包含烘焙的UV和材质平铺 /// 如果mat 对不同映射使用不同的tiling,则 encapsulatingRect 是用于烘焙图集的 uvs 且 sourceMaterialTilingOut 为0,0,1,1。 /// 材质 tiling 烘焙到 atlas 中。 /// </summary> public bool TryGetMaterialToUVRectMap(Material sourceMat, Mesh sourceMesh, int submeshIdx, int idxInResultMats, MeshChannelsCache meshChannelCache, Dictionary <int, MeshAnalysisResult[]> meshAnalysisCache, out TextureTilingTreatment tilingTreatment, out Rect rectInAtlas, out Rect encapsulatingRectOut, out Rect sourceMaterialTilingOut, ref string errorMsg) { for (int i = 0; i < resultAsset.materialsAndUVRects.Length; i++) { resultAsset.materialsAndUVRects[i].allPropsUseSameTiling = true; } tilingTreatment = TextureTilingTreatment.unknown; if (resultAsset.materialsAndUVRects.Length == 0) { errorMsg = "Texture Bake Result 资源中的 材质UVRect 映射信息为空,需重新合并"; rectInAtlas = new Rect(); encapsulatingRectOut = new Rect(); sourceMaterialTilingOut = new Rect(); return(false); } if (sourceMat == null) { rectInAtlas = new Rect(); encapsulatingRectOut = new Rect(); sourceMaterialTilingOut = new Rect(); errorMsg = string.Format("网格 {0} 的子网格 {1} 缺少材质,无法获取映射关系", sourceMesh.name, submeshIdx); return(false); } if (submeshIdx >= sourceMesh.subMeshCount) { errorMsg = "参数错误 :Submesh index 大于子网格数量"; rectInAtlas = new Rect(); encapsulatingRectOut = new Rect(); sourceMaterialTilingOut = new Rect(); return(false); } //源材质在 matsAndSrcUVRect 的 ID int idx = -1; for (int i = 0; i < matsAndSrcUVRect.Length; i++) { if (sourceMat == matsAndSrcUVRect[i].material) { idx = i; break; } } if (idx == -1) { rectInAtlas = new Rect(); encapsulatingRectOut = new Rect(); sourceMaterialTilingOut = new Rect(); errorMsg = string.Format("Material {0} 在 Texture Bake Result 中无法找到", sourceMat.name); return(false); } //不处理网格 UVs if (!resultAsset.resultMaterials[idxInResultMats].considerMeshUVs) { if (numTimesMatAppearsInAtlas[idx] != 1) { Debug.LogError("TextureBakeResults 资源错误,FixOutOfBoundsUVs is false and a material appears more than once."); } 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 //源网格分析,并缓存 MeshAnalysisResult[] meshAnalysisInfo; if (!meshAnalysisCache.TryGetValue(sourceMesh.GetInstanceID(), out meshAnalysisInfo)) { meshAnalysisInfo = new MeshAnalysisResult[sourceMesh.subMeshCount]; for (int j = 0; j < sourceMesh.subMeshCount; j++) { Vector2[] uvss = meshChannelCache.GetUv0Raw(sourceMesh); MeshBakerUtility.hasOutOfBoundsUVs(uvss, sourceMesh, ref meshAnalysisInfo[j], j); } meshAnalysisCache.Add(sourceMesh.GetInstanceID(), meshAnalysisInfo); } //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 //这可能是未在纹理烘焙中使用的网格,该网格的UV贴图对于烘焙的rect而言太大 //找到一条记录,该记录具有能够包含此图集的uvRect bool found = false; Rect encapsulatingRect = new Rect(0, 0, 0, 0); Rect sourceMaterialTiling = new Rect(0, 0, 0, 0); //Debug.Log(string.Format("尝试在图集中查找能够使用材质{1}保持网格{0}的平铺采样rect的矩形", // m, sourceMat, meshAnalysisInfo[submeshIdx].uvRect.ToString("f5"))); for (int i = idx; i < matsAndSrcUVRect.Length; i++) { MaterialAndUVRect matAndUVrect = matsAndSrcUVRect[i]; if (matAndUVrect.material == sourceMat) { if (matAndUVrect.allPropsUseSameTiling) { encapsulatingRect = matAndUVrect.allPropsUseSameTiling_samplingEncapsulatinRect; sourceMaterialTiling = matAndUVrect.allPropsUseSameTiling_sourceMaterialTiling; } else { encapsulatingRect = matAndUVrect.propsUseDifferntTiling_srcUVsamplingRect; sourceMaterialTiling = new Rect(0, 0, 1, 1); } if (UVRectUtility.IsMeshAndMaterialRectEnclosedByAtlasRect( matAndUVrect.tilingTreatment, meshAnalysisInfo[submeshIdx].uvRect, sourceMaterialTiling, encapsulatingRect)) { Debug.Log("在图集中找到" + "ID 为 " + i + "包含" + sourceMesh + " 的 tiled sampling 的 Rect"); idx = i; found = true; break; } } } if (found) { 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}. " + "Was this mesh included when atlases were baked?", sourceMesh.name, sourceMat); return(false); } } }
/// <summary> /// Texture 合并管线第 3 步,创建 Atlas 并保存资源 /// </summary> /// <returns></returns> internal static IEnumerator __Step3_BuildAndSaveAtlasesAndStoreResults(ProgressUpdateDelegate progressInfo, CombineTexturesIntoAtlasesCoroutineResult result, TexturePipelineData data, TextureCombineHandler combiner, ITextureCombinerPacker packer, AtlasPackingResult atlasPackingResult, EditorMethodsInterface textureEditorMethods, AtlasesAndRects resultAtlasesAndRects) { //run the garbage collector to free up as much memory as possible before bake to reduce MissingReferenceException problems GC.Collect(); Texture2D[] atlases = new Texture2D[data.numAtlases]; //StringBuilder report = GenerateReport(data); //创建图集 yield return(packer.CreateAtlases(progressInfo, data, combiner, atlasPackingResult, atlases, textureEditorMethods)); data.nonTexturePropertyBlender.AdjustNonTextureProperties(data.resultMaterial, data.texPropertyNames, data.distinctMaterialTextures, textureEditorMethods); if (data.distinctMaterialTextures.Count > 0) { data.distinctMaterialTextures[0].AdjustResultMaterialNonTextureProperties(data.resultMaterial, data.texPropertyNames); } //结果报告 //if (progressInfo != null) // progressInfo("Building Report", .7f); ////report on atlases created //StringBuilder atlasMessage = new StringBuilder(); //atlasMessage.AppendLine("---- Atlases ------"); //for (int i = 0; i < data.numAtlases; i++) //{ // if (atlases[i] != null) // { // atlasMessage.AppendLine("Created Atlas For: " + data.texPropertyNames[i].name + " h=" + atlases[i].height + " w=" + atlases[i].width); // } // else if (!_ShouldWeCreateAtlasForThisProperty(i, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor)) // { // atlasMessage.AppendLine("Did not create atlas for " + data.texPropertyNames[i].name + " because all source textures were null."); // } //} //report.Append(atlasMessage.ToString()); List <MaterialAndUVRect> mat2rect_map = new List <MaterialAndUVRect>(); for (int i = 0; i < data.distinctMaterialTextures.Count; i++) { MaterialPropTexturesSet texSet = data.distinctMaterialTextures[i]; List <MatAndTransformToMerged> mats = texSet.matsAndGOs.mats; Rect allPropsUseSameTiling_encapsulatingSamplingRect; Rect propsUseDifferntTiling_obUVRect; texSet.GetRectsForTextureBakeResults(out allPropsUseSameTiling_encapsulatingSamplingRect, out propsUseDifferntTiling_obUVRect); for (int j = 0; j < mats.Count; j++) { Rect allPropsUseSameTiling_sourceMaterialTiling = texSet.GetMaterialTilingRectForTextureBakerResults(j); MaterialAndUVRect key = new MaterialAndUVRect( mats[j].mat, atlasPackingResult.rects[i], texSet.allTexturesUseSameMatTiling, allPropsUseSameTiling_sourceMaterialTiling, allPropsUseSameTiling_encapsulatingSamplingRect, propsUseDifferntTiling_obUVRect, texSet.tilingTreatment, mats[j].objName); if (!mat2rect_map.Contains(key)) { mat2rect_map.Add(key); } } } resultAtlasesAndRects.atlases = atlases; // one per texture on result shader resultAtlasesAndRects.texPropertyNames = ShaderTextureProperty.GetNames(data.texPropertyNames); // one per texture on source shader resultAtlasesAndRects.originMatToRect_map = mat2rect_map; if (progressInfo != null) { progressInfo("Restoring Texture Formats & Read Flags", .8f); } combiner._destroyAllTemporaryTextures(); if (textureEditorMethods != null) { textureEditorMethods.RestoreReadFlagsAndFormats(progressInfo); } //if (report != null) // Debug.Log(report.ToString()); yield break; }
/// <summary> /// Creates for materials on renderer. /// 生成 TextureBakeResult,如果要合并的所有游戏物体都使用相同的材质,则可以使用该 TextureBakeResult。 /// 将游戏物体的渲染器所使用的所有材质映射到 Atlas 中的矩形0,0..1,1 中。 /// 用于创建临时 TextureCombineResult,Mesh 合并时,TextureCombineResult 为空时调用 /// </summary> public static 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("列表中第 {0} 个游戏物体为空", i)); return(null); } Material[] oMats = MeshBakerUtility.GetGOMaterials(gos[i]); if (oMats.Length == 0) { Debug.LogError(string.Format("列表中第 {0} 个游戏物体没有 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); TextureBakeResults textureCombineResult = (TextureBakeResults)CreateInstance(typeof(TextureBakeResults)); List <MaterialAndUVRect> sourceMatUVRects = new List <MaterialAndUVRect>(); for (int i = 0; i < rms.Length; i++) { if (rms[i] != null) { MaterialAndUVRect matAndUVRect = new MaterialAndUVRect(rms[i], new Rect(0f, 0f, 1f, 1f), true, new Rect(0f, 0f, 1f, 1f), new Rect(0f, 0f, 1f, 1f), new Rect(0, 0, 0, 0), TextureTilingTreatment.none, ""); if (!sourceMatUVRects.Contains(matAndUVRect)) { sourceMatUVRects.Add(matAndUVRect); } } } textureCombineResult.resultMaterials = new MultiMaterial[sourceMatUVRects.Count]; for (int i = 0; i < sourceMatUVRects.Count; i++) { textureCombineResult.resultMaterials[i] = new MultiMaterial(); List <Material> sourceMats = new List <Material>(); sourceMats.Add(sourceMatUVRects[i].material); textureCombineResult.resultMaterials[i].sourceMaterials = sourceMats; textureCombineResult.resultMaterials[i].combinedMaterial = sourceMatUVRects[i].material; textureCombineResult.resultMaterials[i].considerMeshUVs = false; } if (rms.Length == 1) { textureCombineResult.doMultiMaterial = false; } else { textureCombineResult.doMultiMaterial = true; } textureCombineResult.materialsAndUVRects = sourceMatUVRects.ToArray(); return(textureCombineResult); }