/// <summary> /// 为材料平铺和采样矩形和UV平铺分配初始值 /// </summary> /// <param name="allTexturesUseSameMatTiling"></param> /// <param name="matTiling"></param> public void AssignInitialValuesForMaterialTilingAndSamplingRectMatAndUVTiling(bool allTexturesUseSameMatTiling, DRect matTiling) { if (allTexturesUseSameMatTiling) { materialTiling = matTiling; } else { materialTiling = new DRect(0f, 0f, 1f, 1f); } DRect tmpMatTiling = materialTiling; DRect obUVrect = obUVRectIfTilingSame; samplingRectMatAndUVTiling = UVRectUtility.CombineTransforms(ref obUVrect, ref tmpMatTiling); }
public static Rect BuildTransformMeshUV2AtlasRect( bool considerMeshUVs, Rect _atlasRect, Rect _obUVRect, Rect _sourceMaterialTiling, Rect _encapsulatingRect) { DRect atlasRect = new DRect(_atlasRect); DRect obUVRect; if (considerMeshUVs) { obUVRect = new DRect(_obUVRect); //this is the uvRect in src mesh } else { obUVRect = new DRect(0.0, 0.0, 1.0, 1.0); } DRect sourceMaterialTiling = new DRect(_sourceMaterialTiling); //封装材质, UV 参数 DRect encapsulatingRectMatAndUVTiling = new DRect(_encapsulatingRect); DRect encapsulatingRectMatAndUVTilingInverse = UVRectUtility.InverseTransform(ref encapsulatingRectMatAndUVTiling); DRect toNormalizedUVs = UVRectUtility.InverseTransform(ref obUVRect); DRect meshFullSamplingRect = UVRectUtility.CombineTransforms(ref obUVRect, ref sourceMaterialTiling); DRect shiftToFitInEncapsulating = UVRectUtility.GetShiftTransformToFitBinA(ref encapsulatingRectMatAndUVTiling, ref meshFullSamplingRect); meshFullSamplingRect = UVRectUtility.CombineTransforms(ref meshFullSamplingRect, ref shiftToFitInEncapsulating); //transform between full sample rect and encapsulating rect DRect relativeTrans = UVRectUtility.CombineTransforms(ref meshFullSamplingRect, ref encapsulatingRectMatAndUVTilingInverse); DRect trans = UVRectUtility.CombineTransforms(ref toNormalizedUVs, ref relativeTrans); trans = UVRectUtility.CombineTransforms(ref trans, ref atlasRect); Rect rr = trans.GetRect(); return(rr); }
public void DrawRectsToMergeGizmos(Color encC, Color innerC) { DRect r = ts[0].GetEncapsulatingSamplingRect(); r.Expand(.05f); Gizmos.color = encC; Gizmos.DrawWireCube(r.center.GetVector2(), r.size); for (int i = 0; i < matsAndGOs.mats.Count; i++) { DRect rr = matsAndGOs.mats[i].samplingRectMatAndUVTiling; DRect trans = UVRectUtility.GetShiftTransformToFitBinA(ref r, ref rr); Vector2 xy = UVRectUtility.TransformPoint(ref trans, rr.min); rr.x = xy.x; rr.y = xy.y; //Debug.Log("r " + r + " rr" + rr); Gizmos.color = innerC; Gizmos.DrawWireCube(rr.center.GetVector2(), rr.size); } }
//assumes all materials use the same obUVrects. //假设所有材料都使用相同的obUVrects。 internal void CalcInitialFullSamplingRects(bool fixOutOfBoundsUVs) { DRect validFullSamplingRect = new DRect(0, 0, 1, 1); if (fixOutOfBoundsUVs) { validFullSamplingRect = obUVrect; } for (int propIdx = 0; propIdx < ts.Length; propIdx++) { if (!ts[propIdx].isNull) { DRect matTiling = ts[propIdx].matTilingRect; DRect ruv; if (fixOutOfBoundsUVs) { ruv = obUVrect; } else { ruv = new DRect(0.0, 0.0, 1.0, 1.0); } ts[propIdx].SetEncapsulatingSamplingRect(this, UVRectUtility.CombineTransforms(ref ruv, ref matTiling)); validFullSamplingRect = ts[propIdx].GetEncapsulatingSamplingRect(); } } //if some of the textures were null make them match the sampling of one of the other textures for (int propIdx = 0; propIdx < ts.Length; propIdx++) { if (ts[propIdx].isNull) { ts[propIdx].SetEncapsulatingSamplingRect(this, validFullSamplingRect); } } }
/// <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); } } }
public void MergeOverlappingDistinctMaterialTexturesAndCalcMaterialSubrects(List <MaterialPropTexturesSet> distinctMaterialTextures) { int numMerged = 0; // IMPORTANT: Note that the verts stored in the mesh are NOT Normalized UV Coords. They are normalized * [UVTrans]. To get normalized UV // coords we must multiply them by [invUVTrans]. Need to do this to the verts in the mesh before we do any transforms with them. // Also check that all textures use same tiling. This is a prerequisite for merging. // Mark MB3_TexSet that are mergable (allTexturesUseSameMatTiling) //存储在网格中的顶点不是归一化UV坐标。 它们已归一化 * [UVTrans]。 //获得归一化的 UV 坐标必须将其乘以[invUVTrans]。 //在对它们进行任何转换之前,需要对网格中的顶点执行此操作。 //检查所有纹理是否使用相同的拼贴。 这是合并的先决条件。 //标记可合并的TexSet(allTexturesUseSameMatTiling) for (int i = 0; i < distinctMaterialTextures.Count; i++) { MaterialPropTexturesSet matPropsTextureSet = distinctMaterialTextures[i]; int idxOfFirstNotNull = -1; bool allAreSame = true; DRect firstRect = new DRect(); //判断不是相同的 texture 资源 for (int propIdx = 0; propIdx < matPropsTextureSet.ts.Length; propIdx++) { if (idxOfFirstNotNull != -1) { if (!matPropsTextureSet.ts[propIdx].isNull && firstRect != matPropsTextureSet.ts[propIdx].matTilingRect) { allAreSame = false; } } //先找第一个非空纹理,设置为 idxOfFirstNotNull else if (!matPropsTextureSet.ts[propIdx].isNull) { idxOfFirstNotNull = propIdx; firstRect = matPropsTextureSet.ts[propIdx].matTilingRect; } } if (LOG_LEVEL_TRACE_MERGE_MAT_SUBRECTS == true) { if (allAreSame) { Debug.LogFormat("TextureSet {0} allTexturesUseSameMatTiling = {1}", i, allAreSame); } else { Debug.Log(string.Format("Textures in material(s) do not all use the same material tiling. " + "This set of textures will not be considered for merge: {0} ", matPropsTextureSet.GetDescription())); } } if (allAreSame) { matPropsTextureSet.SetAllTexturesUseSameMatTilingTrue(); } } //设置 材质Obj 名称 for (int i = 0; i < distinctMaterialTextures.Count; i++) { MaterialPropTexturesSet matPropsTextureSet = distinctMaterialTextures[i]; for (int matIdx = 0; matIdx < matPropsTextureSet.matsAndGOs.mats.Count; matIdx++) { if (matPropsTextureSet.matsAndGOs.gos.Count > 0) { matPropsTextureSet.matsAndGOs.mats[matIdx].objName = matPropsTextureSet.matsAndGOs.gos[0].name; } else if (matPropsTextureSet.ts[0] != null) { matPropsTextureSet.matsAndGOs.mats[matIdx].objName = string.Format("[objWithTx:{0} atlasBlock:{1} matIdx{2}]", matPropsTextureSet.ts[0].GetTexName(), i, matIdx); } else { matPropsTextureSet.matsAndGOs.mats[matIdx].objName = string.Format("[objWithTx:{0} atlasBlock:{1} matIdx{2}]", "Unknown", i, matIdx); } } matPropsTextureSet.CalcInitialFullSamplingRects(fixOutOfBoundsUVs); matPropsTextureSet.CalcMatAndUVSamplingRects(); } // need to calculate the srcSampleRect for the complete tiling in the atlas // for each material need to know what the subrect would be in the atlas if material UVRect was 0,0,1,1 and Merged uvRect was full tiling //需要为图集中的完整切片计算src SampleRect //对于每种材料,如果材料UVRect为0,0,1,1并且合并的uvRect为完整平铺,则需要知道该图集在图集中的位置 List <int> MarkedForDeletion = new List <int>(); for (int i = 0; i < distinctMaterialTextures.Count; i++) { MaterialPropTexturesSet tx2 = distinctMaterialTextures[i]; for (int j = i + 1; j < distinctMaterialTextures.Count; j++) { MaterialPropTexturesSet tx1 = distinctMaterialTextures[j]; if (tx1.AllTexturesAreSameForMerge(tx2, _considerNonTextureProperties, resultMaterialTextureBlender)) { double accumulatedAreaCombined = 0f; double accumulatedAreaNotCombined = 0f; DRect encapsulatingRectMerged = new DRect(); int idxOfFirstNotNull = -1; for (int propIdx = 0; propIdx < tx2.ts.Length; propIdx++) { if (!tx2.ts[propIdx].isNull) { if (idxOfFirstNotNull == -1) { idxOfFirstNotNull = propIdx; } } } if (idxOfFirstNotNull != -1) { // only in here if all properties use the same tiling so don't need to worry about which propIdx we are dealing with //Get the rect that encapsulates all material and UV tiling for materials and meshes in tx1 //如果所有属性都使用相同的tiling,因此无需担心我们正在处理哪个propIdx //获取将所有材料和UV平铺封装为rect的rect在tx1中 DRect encapsulatingRect1 = tx1.matsAndGOs.mats[0].samplingRectMatAndUVTiling; for (int matIdx = 1; matIdx < tx1.matsAndGOs.mats.Count; matIdx++) { DRect tmpSsamplingRectMatAndUVTilingTx1 = tx1.matsAndGOs.mats[matIdx].samplingRectMatAndUVTiling; encapsulatingRect1 = UVRectUtility.GetEncapsulatingRectShifted(ref encapsulatingRect1, ref tmpSsamplingRectMatAndUVTilingTx1); } //same for tx2 DRect encapsulatingRect2 = tx2.matsAndGOs.mats[0].samplingRectMatAndUVTiling; for (int matIdx = 1; matIdx < tx2.matsAndGOs.mats.Count; matIdx++) { DRect tmpSsamplingRectMatAndUVTilingTx2 = tx2.matsAndGOs.mats[matIdx].samplingRectMatAndUVTiling; encapsulatingRect2 = UVRectUtility.GetEncapsulatingRectShifted(ref encapsulatingRect2, ref tmpSsamplingRectMatAndUVTilingTx2); } encapsulatingRectMerged = UVRectUtility.GetEncapsulatingRectShifted(ref encapsulatingRect1, ref encapsulatingRect2); accumulatedAreaCombined += encapsulatingRectMerged.width * encapsulatingRectMerged.height; accumulatedAreaNotCombined += encapsulatingRect1.width * encapsulatingRect1.height + encapsulatingRect2.width * encapsulatingRect2.height; } else { encapsulatingRectMerged = new DRect(0f, 0f, 1f, 1f); } //the distinct material textures may overlap. //if the area of these rectangles combined is less than the sum of these areas of these rectangles then merge these distinctMaterialTextures if (accumulatedAreaCombined < accumulatedAreaNotCombined) { // merge tx2 into tx1 numMerged++; StringBuilder sb = null; sb = new StringBuilder(); sb.AppendFormat("About To Merge:\n TextureSet1 {0}\n TextureSet2 {1}\n", tx1.GetDescription(), tx2.GetDescription()); for (int matIdx = 0; matIdx < tx1.matsAndGOs.mats.Count; matIdx++) { sb.AppendFormat("tx1 Mat {0} matAndMeshUVRect {1} fullSamplingRect {2}\n", tx1.matsAndGOs.mats[matIdx].mat, tx1.matsAndGOs.mats[matIdx].samplingRectMatAndUVTiling, tx1.ts[0].GetEncapsulatingSamplingRect()); } for (int matIdx = 0; matIdx < tx2.matsAndGOs.mats.Count; matIdx++) { sb.AppendFormat("tx2 Mat {0} matAndMeshUVRect {1} fullSamplingRect {2}\n", tx2.matsAndGOs.mats[matIdx].mat, tx2.matsAndGOs.mats[matIdx].samplingRectMatAndUVTiling, tx2.ts[0].GetEncapsulatingSamplingRect()); } //copy game objects over for (int k = 0; k < tx2.matsAndGOs.gos.Count; k++) { if (!tx1.matsAndGOs.gos.Contains(tx2.matsAndGOs.gos[k])) { tx1.matsAndGOs.gos.Add(tx2.matsAndGOs.gos[k]); } } //copy materials over from tx2 to tx1 for (int matIdx = 0; matIdx < tx2.matsAndGOs.mats.Count; matIdx++) { tx1.matsAndGOs.mats.Add(tx2.matsAndGOs.mats[matIdx]); } tx1.SetEncapsulatingSamplingRectWhenMergingTexSets(encapsulatingRectMerged); if (!MarkedForDeletion.Contains(i)) { MarkedForDeletion.Add(i); } sb.AppendFormat("=== After Merge TextureSet {0}\n", tx1.GetDescription()); for (int matIdx = 0; matIdx < tx1.matsAndGOs.mats.Count; matIdx++) { sb.AppendFormat("tx1 Mat {0} matAndMeshUVRect {1} fullSamplingRect {2}\n", tx1.matsAndGOs.mats[matIdx].mat, tx1.matsAndGOs.mats[matIdx].samplingRectMatAndUVTiling, tx1.ts[0].GetEncapsulatingSamplingRect()); } //Integrity check that sampling rects fit into enapsulating rects if (MeshBakerRoot.DO_INTEGRITY_CHECKS) { if (MeshBakerRoot.DO_INTEGRITY_CHECKS) { DoIntegrityCheckMergedEncapsulatingSamplingRects(distinctMaterialTextures); } } Debug.Log(sb.ToString()); break; Debug.Log(string.Format("Considered merging {0} and {1} but there was not enough overlap. It is more efficient to bake these to separate rectangles.", tx1.GetDescription(), tx2.GetDescription())); } } } //remove distinctMaterialTextures that were merged for (int j = MarkedForDeletion.Count - 1; j >= 0; j--) { distinctMaterialTextures.RemoveAt(MarkedForDeletion[j]); } MarkedForDeletion.Clear(); Debug.Log(string.Format("MergeOverlappingDistinctMaterialTexturesAndCalcMaterialSubrects complete merged {0} now have {1}", numMerged, distinctMaterialTextures.Count)); if (MeshBakerRoot.DO_INTEGRITY_CHECKS) { DoIntegrityCheckMergedEncapsulatingSamplingRects(distinctMaterialTextures); } } }