/// <param name="mat">The Material</param> /// <param name="destRect">The rect in the atlas this material maps to</param> /// <param name="allPropsUseSameTiling">If true then use sourceMaterialTiling and samplingEncapsulatingRect. /// if false then use srcUVsamplingRect. None used values should be 0,0,0,0.</param> /// <param name="sourceMaterialTiling">allPropsUseSameTiling_sourceMaterialTiling</param> /// <param name="samplingEncapsulatingRect">allPropsUseSameTiling_samplingEncapsulatinRect</param> /// <param name="srcUVsamplingRect">propsUseDifferntTiling_srcUVsamplingRect</param> public MaterialAndUVRect(Material mat, Rect destRect, bool allPropsUseSameTiling, Rect sourceMaterialTiling, Rect samplingEncapsulatingRect, Rect srcUVsamplingRect, TextureTilingTreatment treatment, string objName) { if (allPropsUseSameTiling) { Debug.Assert(srcUVsamplingRect == new Rect(0, 0, 0, 0)); } if (!allPropsUseSameTiling) { Debug.Assert(samplingEncapsulatingRect == new Rect(0, 0, 0, 0)); Debug.Assert(sourceMaterialTiling == new Rect(0, 0, 0, 0)); } material = mat; atlasRect = destRect; tilingTreatment = treatment; this.allPropsUseSameTiling = allPropsUseSameTiling; allPropsUseSameTiling_sourceMaterialTiling = sourceMaterialTiling; allPropsUseSameTiling_samplingEncapsulatinRect = samplingEncapsulatingRect; propsUseDifferntTiling_srcUVsamplingRect = srcUVsamplingRect; srcObjName = objName; }
public void SetTilingTreatmentAndAdjustEncapsulatingSamplingRect(TextureTilingTreatment newTilingTreatment) { Debug.Assert(texSet.allTexturesUseSameMatTiling == true); if (texSet.tilingTreatment == TextureTilingTreatment.edgeToEdgeX) { foreach (MaterialPropTexture t in texSet.ts) { DRect r = t.GetEncapsulatingSamplingRect(); r.width = 1; t.SetEncapsulatingSamplingRect(texSet, r); } } else if (texSet.tilingTreatment == TextureTilingTreatment.edgeToEdgeY) { foreach (MaterialPropTexture t in texSet.ts) { DRect r = t.GetEncapsulatingSamplingRect(); r.height = 1; t.SetEncapsulatingSamplingRect(texSet, r); } } else if (texSet.tilingTreatment == TextureTilingTreatment.edgeToEdgeXY) { foreach (MaterialPropTexture t in texSet.ts) { DRect r = t.GetEncapsulatingSamplingRect(); r.height = 1; r.width = 1; t.SetEncapsulatingSamplingRect(texSet, r); } } }
public MaterialPropTexturesSet(MaterialPropTexture[] tss, Vector2 uvOffset, Vector2 uvScale, TextureTilingTreatment treatment) { ts = tss; tilingTreatment = treatment; obUVoffset = uvOffset; obUVscale = uvScale; allTexturesUseSameMatTiling = false; thisIsOnlyTexSetInAtlas = false; matsAndGOs = new MatsAndGOs(); matsAndGOs.mats = new List <MatAndTransformToMerged>(); matsAndGOs.gos = new List <GameObject>(); pipelineVariation = new PipelineVariationSomeTexturesUseDifferentMatTiling(this); }
/// <summary> /// 验证 /// </summary> /// <param name="tilingTreatment"></param> /// <param name="uvR"></param> /// <param name="sourceMaterialTiling"></param> /// <param name="samplingEncapsulatinRect"></param> /// <returns></returns> public static bool IsMeshAndMaterialRectEnclosedByAtlasRect(TextureTilingTreatment tilingTreatment, Rect uvR, Rect sourceMaterialTiling, Rect samplingEncapsulatinRect) { Rect potentialRect = new Rect(); potentialRect = CombineTransforms(ref uvR, ref sourceMaterialTiling); Debug.Log("IsMeshAndMaterialRectEnclosedByAtlasRect Rect in atlas uvR=" + uvR.ToString("f5") + " sourceMaterialTiling=" + sourceMaterialTiling.ToString("f5") + "Potential Rect (must fit in encapsulating) " + potentialRect.ToString("f5") + " encapsulating=" + samplingEncapsulatinRect.ToString("f5") + " tilingTreatment=" + tilingTreatment); if (tilingTreatment == TextureTilingTreatment.edgeToEdgeX) { if (LineSegmentContainsShifted(samplingEncapsulatinRect.y, samplingEncapsulatinRect.height, potentialRect.y, potentialRect.height)) { return(true); } } else if (tilingTreatment == TextureTilingTreatment.edgeToEdgeY) { if (LineSegmentContainsShifted(samplingEncapsulatinRect.x, samplingEncapsulatinRect.width, potentialRect.x, potentialRect.width)) { return(true); } } else if (tilingTreatment == TextureTilingTreatment.edgeToEdgeXY) { //only one rect in atlas and is edge to edge in both X and Y directions. return(true); } else { if (RectContainsShifted(ref samplingEncapsulatinRect, ref potentialRect)) { return(true); } } return(false); }
/// <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> /// 第一步: /// 写入 TexturePipelineData 的 MaterialPropTexturesSet 列表,和 usedObjsToMesh 列表 /// 每个TexSet在 Atlas 中都是一个矩形。 /// 如果 allowedMaterialsFilter (过滤器)为空,那么将收集 allObjsToMesh 上的所有材质,usedObjsToMesh 将与allObjsToMesh相同 /// 否则,将仅包括allowedMaterialsFilter中的材料,而usedObjsToMesh将是使用这些材料的objs。 /// </summary> internal static IEnumerator __Step1_CollectDistinctMatTexturesAndUsedObjects(ProgressUpdateDelegate progressInfo, CombineTexturesIntoAtlasesCoroutineResult result, TexturePipelineData data, EditorMethodsInterface textureEditorMethods, List <GameObject> usedObjsToMesh) { // Collect distinct list of textures to combine from the materials on objsToCombine // 收集UsedObjects上不同的材质纹理 bool outOfBoundsUVs = false; Dictionary <int, MeshAnalysisResult[]> meshAnalysisResultsCache = new Dictionary <int, MeshAnalysisResult[]>(); //cache results for (int i = 0; i < data.allObjsToMesh.Count; i++) { GameObject obj = data.allObjsToMesh[i]; //报道进度 if (progressInfo != null) { progressInfo("Collecting textures for " + obj, ((float)i) / data.allObjsToMesh.Count / 2f); } if (obj == null) { Debug.LogError("合并游戏物体列表中包含空物体"); result.success = false; yield break; } Mesh sharedMesh = MeshBakerUtility.GetMesh(obj); if (sharedMesh == null) { Debug.LogError("游戏物体 " + obj.name + " 网格为空"); result.success = false; yield break; } Material[] sharedMaterials = MeshBakerUtility.GetGOMaterials(obj); if (sharedMaterials.Length == 0) { Debug.LogError("游戏物体 " + obj.name + " 材质为空."); result.success = false; yield break; } //analyze mesh or grab cached result of previous analysis, stores one result for each submesh //处理网格数据 MeshAnalysisResult[] meshAnalysisResults;//每个游戏物体的主网格子网格数据数组 if (!meshAnalysisResultsCache.TryGetValue(sharedMesh.GetInstanceID(), out meshAnalysisResults)) { meshAnalysisResults = new MeshAnalysisResult[sharedMesh.subMeshCount]; for (int j = 0; j < sharedMesh.subMeshCount; j++) { MeshBakerUtility.hasOutOfBoundsUVs(sharedMesh, ref meshAnalysisResults[j], j); if (data._normalizeTexelDensity) { meshAnalysisResults[j].submeshArea = GetSubmeshArea(sharedMesh, j); } if (data._fixOutOfBoundsUVs && !meshAnalysisResults[j].hasUVs) { meshAnalysisResults[j].uvRect = new Rect(0, 0, 1, 1); Debug.LogWarning("Mesh for object " + obj + " has no UV channel but 'consider UVs' is enabled." + " Assuming UVs will be generated filling 0,0,1,1 rectangle."); } } meshAnalysisResultsCache.Add(sharedMesh.GetInstanceID(), meshAnalysisResults); } if (data._fixOutOfBoundsUVs) { Debug.Log("Mesh Analysis for object " + obj + " numSubmesh=" + meshAnalysisResults.Length + " HasOBUV=" + meshAnalysisResults[0].hasOutOfBoundsUVs + " UVrectSubmesh0=" + meshAnalysisResults[0].uvRect); } //处理材质数据 for (int matIdx = 0; matIdx < sharedMaterials.Length; matIdx++) { ////for each submesh //if (progressInfo != null) //{ // progressInfo(string.Format("Collecting textures for {0} submesh {1}", obj, matIdx), // ((float)i) / data.allObjsToMesh.Count / 2f); //} Material mat = sharedMaterials[matIdx]; // 材质过滤器 if (data.allowedMaterialsFilter != null && !data.allowedMaterialsFilter.Contains(mat)) { continue; } outOfBoundsUVs = outOfBoundsUVs || meshAnalysisResults[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."); result.success = false; yield break; } if (data._fixOutOfBoundsUVs) { if (!MeshBakerUtility.AreAllSharedMaterialsDistinct(sharedMaterials)) { Debug.LogWarning("游戏物体 " + obj.name + " 使用相同的材质在多个子网格. " + "可能生成奇怪的 resultAtlasesAndRects,尤其是与 _fixOutOfBoundsUVs 为 true 时"); } } //材质属性所用到的 Texutre MaterialPropTexture[] mts = new MaterialPropTexture[data.texPropertyNames.Count]; for (int propIdx = 0; propIdx < data.texPropertyNames.Count; propIdx++) { Texture tx = null; Vector2 scale = Vector2.one; Vector2 offset = Vector2.zero; float texelDensity = 0f; if (mat.HasProperty(data.texPropertyNames[propIdx].name)) { Texture txx = GetTextureConsideringStandardShaderKeywords(data.resultMaterial.shader.name, mat, data.texPropertyNames[propIdx].name); if (txx != null) { if (txx is Texture2D) { //TextureFormat 验证 tx = txx; TextureFormat f = ((Texture2D)tx).format; bool isNormalMap = false; if (!Application.isPlaying && textureEditorMethods != null) { isNormalMap = textureEditorMethods.IsNormalMap((Texture2D)tx); } if ((f == TextureFormat.ARGB32 || f == TextureFormat.RGBA32 || f == TextureFormat.BGRA32 || f == TextureFormat.RGB24 || f == TextureFormat.Alpha8) && !isNormalMap) //DXT5 does not work { //可使用 } else { //TRIED to copy texture using tex2.SetPixels(tex1.GetPixels()) but bug in 3.5 means DTX1 and 5 compressed textures come out skewe //尝试使用tex2.SetPixels(tex1.GetPixels())复制纹理,但是3.5中的bug意味着DTX1和5压缩纹理出现扭曲 if (Application.isPlaying && data._packingAlgorithm != PackingAlgorithmEnum.MeshBakerTexturePacker_Fast) { Debug.LogWarning("合并列表中,游戏物体 " + obj.name + " 所使用的 Texture " + tx.name + " 使用的格式 " + f + "不是: ARGB32, RGBA32, BGRA32, RGB24, Alpha8 或 DXT. " + "无法在运行时重新设置尺寸" + "If format says 'compressed' try changing it to 'truecolor'"); result.success = false; yield break; } else { tx = (Texture2D)mat.GetTexture(data.texPropertyNames[propIdx].name); } } } else { Debug.LogError("合并列表中,游戏物体 " + obj.name + " 渲染网格使用的 Texture 不是 Texture2D. "); result.success = false; yield break; } } //像素密度 if (tx != null && data._normalizeTexelDensity) { //不考虑平铺和UV采样超出范围 if (meshAnalysisResults[propIdx].submeshArea == 0) { texelDensity = 0f; } else { texelDensity = (tx.width * tx.height) / (meshAnalysisResults[propIdx].submeshArea); } } //规格,偏移 GetMaterialScaleAndOffset(mat, data.texPropertyNames[propIdx].name, out offset, out scale); } mts[propIdx] = new MaterialPropTexture(tx, offset, scale, texelDensity); } // 收集材质参数值的平均值 data.nonTexturePropertyBlender.CollectAverageValuesOfNonTextureProperties(data.resultMaterial, mat); Vector2 obUVscale = new Vector2(meshAnalysisResults[matIdx].uvRect.width, meshAnalysisResults[matIdx].uvRect.height); Vector2 obUVoffset = new Vector2(meshAnalysisResults[matIdx].uvRect.x, meshAnalysisResults[matIdx].uvRect.y); //Add to distinct set of textures if not already there TextureTilingTreatment tilingTreatment = TextureTilingTreatment.none; if (data._fixOutOfBoundsUVs) { tilingTreatment = TextureTilingTreatment.considerUVs; } //合并信息 distinctMaterialTextures 数据设置 //材质各参数 Texture,及 UV 偏移数据映射 MaterialPropTexturesSet setOfTexs = new MaterialPropTexturesSet(mts, obUVoffset, obUVscale, tilingTreatment); //one of these per submesh //材质及各变化参数Rect 数据 MatAndTransformToMerged matt = new MatAndTransformToMerged(new DRect(obUVoffset, obUVscale), data._fixOutOfBoundsUVs, mat); setOfTexs.matsAndGOs.mats.Add(matt); MaterialPropTexturesSet setOfTexs2 = data.distinctMaterialTextures.Find(x => x.IsEqual(setOfTexs, data._fixOutOfBoundsUVs, data.nonTexturePropertyBlender)); if (setOfTexs2 != null) { setOfTexs = setOfTexs2; } else { data.distinctMaterialTextures.Add(setOfTexs); } if (!setOfTexs.matsAndGOs.mats.Contains(matt)) { setOfTexs.matsAndGOs.mats.Add(matt); } if (!setOfTexs.matsAndGOs.gos.Contains(obj)) { setOfTexs.matsAndGOs.gos.Add(obj); //已使用 游戏物体 if (!usedObjsToMesh.Contains(obj)) { usedObjsToMesh.Add(obj); } } } } Debug.Log(string.Format("第一阶段完成;" + "参与合并的游戏物体的不同材质,各自包含与shader属性对应的不同的纹理,收集到 {0} 组 textures,即 {0} 个不同的材质," + "fixOutOfBoundsUV:{1} " + "considerNonTextureProperties:{2}", data.distinctMaterialTextures.Count, data._fixOutOfBoundsUVs, data._considerNonTextureProperties)); if (data.distinctMaterialTextures.Count == 0) { Debug.LogError("None of the source object materials matched any of the allowed materials for submesh with result material: " + data.resultMaterial); result.success = false; yield break; } TextureCombinerMerging merger = new TextureCombinerMerging(data._considerNonTextureProperties, data.nonTexturePropertyBlender, data._fixOutOfBoundsUVs); merger.MergeOverlappingDistinctMaterialTexturesAndCalcMaterialSubrects(data.distinctMaterialTextures); yield break; }
public void SetTilingTreatmentAndAdjustEncapsulatingSamplingRect(TextureTilingTreatment newTilingTreatment) { tilingTreatment = newTilingTreatment; pipelineVariation.SetTilingTreatmentAndAdjustEncapsulatingSamplingRect(newTilingTreatment); }