Unity中TextMeshPro渲染过慢致BoxCollider2D无法快速适配问题求助
问题:Unity中快速为TextMeshPro生成匹配包围盒的BoxCollider2D
我在Unity用C#开发,需要给TextMeshPro文本添加和文本尺寸匹配的BoxCollider2D(只要包围盒,不需要精确文本形状)。现在遇到两个问题:
- 调用
GetRenderedValues获取渲染尺寸时,生成实际值耗时极长 - 如果不延迟更新BoxCollider2D尺寸,返回值只有0.00001,已经用了
ForceMeshUpdate但没解决
现有创建TMP的代码
foreach (var programs in uniquePrograms) { //Create each Programs from Initial Full data List GameObject createProgram = (GameObject) Instantiate(ProgramPreFab); createProgram.name = programs; //Creates TextMeshPro Object (Should be used for Data Points) as child of First Child Component (should be Vertical layout - will likely need to be more specific in future) List<DataClass.DataStructure> dataSplit = FullData.Where(x => x.program == programs).ToList(); foreach (var data in dataSplit) { //Create TextMeshPro and associated Box Collider Variable & ensure it's sorting order is always in front of it's parent TextMeshPro dataPoint = (TextMeshPro)Instantiate(DataPointTMP, createProgram.transform.GetChild(0)); dataPoint.sortingOrder = createProgram.GetComponent<Renderer>().sortingOrder + 1; //Update TMP with Data Point Name (ForceMeshUpdate may be need to ensure the text is there so the BoxCollider will have the correct values) dataPoint.text = data.dataName; dataPoint.ForceMeshUpdate(); dataPoint.name = data.dataName; //Add TMP to createdDataPoint to add Box Collider in StartUpGenerateBoxColliders function (next) createdDataPoints.Add(dataPoint); } }
尝试过的延迟更新代码(耗时过长)
IEnumerator WaitToCreateCollider() { yield return new WaitForEndOfFrame(); StartUpGenerateBoxColliders(); } void StartUpGenerateBoxColliders() { foreach (var dataPoint in createdDataPoints) { BoxCollider2D boxCollider2D = dataPoint.GetComponent<BoxCollider2D>(); Vector2 textSize = dataPoint.GetRenderedValues(false); boxCollider2D.size = textSize; Debug.Log(dataPoint.name + "Box Colider Updated"); } }
上述代码均在Start方法中调用,目前虽能实现功能,但等待耗时过久,求加速文本渲染/碰撞体更新的方法。
优化方案
1. 改用异步渲染+分帧处理碰撞体
ForceMeshUpdate()默认同步执行,批量调用会阻塞主线程。改用异步更新,再分帧处理已完成渲染的文本:
// 创建TMP时替换同步ForceMeshUpdate为异步 dataPoint.text = data.dataName; dataPoint.ForceMeshUpdate(TMP_FontAsset.UpdateType.Asynchronous); // 异步更新网格 dataPoint.name = data.dataName; createdDataPoints.Add(dataPoint);
然后用分帧协程更新碰撞体,避免单帧负载过高:
IEnumerator UpdateCollidersOverFrames() { int processedCount = 0; while (processedCount < createdDataPoints.Count) { var dataPoint = createdDataPoints[processedCount]; if (dataPoint.IsGeometryReady) // 检查文本网格是否生成完成 { BoxCollider2D boxCollider2D = dataPoint.GetComponent<BoxCollider2D>(); Vector2 textSize = dataPoint.GetRenderedValues(false); boxCollider2D.size = textSize; Debug.Log($"{dataPoint.name} Box Collider Updated"); processedCount++; } yield return null; // 每帧处理一个,避免卡顿 } }
调用时直接启动这个协程即可,无需等待整帧结束。
2. 预计算文本尺寸(无需等待渲染)
如果文本内容已知,直接用TMP_TextUtilities.GetTextBounds预计算尺寸,跳过实际渲染步骤,速度最快:
foreach (var data in dataSplit) { TextMeshPro dataPoint = (TextMeshPro)Instantiate(DataPointTMP, createProgram.transform.GetChild(0)); dataPoint.sortingOrder = createProgram.GetComponent<Renderer>().sortingOrder + 1; dataPoint.text = data.dataName; dataPoint.name = data.dataName; // 预计算文本包围盒,无需等待渲染 Bounds textBounds = TMP_TextUtilities.GetTextBounds( dataPoint.text, dataPoint.font, dataPoint.fontSize, dataPoint.characterSpacing ); // 直接设置碰撞体尺寸 BoxCollider2D boxCollider2D = dataPoint.GetComponent<BoxCollider2D>(); boxCollider2D.size = new Vector2(textBounds.size.x, textBounds.size.y); createdDataPoints.Add(dataPoint); }
这个方法完全绕开了运行时渲染等待,适合批量生成文本的场景。
3. 优化TextMeshPro设置减少渲染开销
- 关闭
Word Wrapping、Extra Padding等不需要的特性,减少网格计算量 - 确保使用的字体已预生成Atlas(在TextMeshPro Font Asset中勾选
Include Font Atlas),避免运行时动态生成图集 - 降低字体的
Rendering Mode(比如从SDF改为Bitmap,如果视觉要求允许)
内容的提问来源于stack exchange,提问作者M Davis
相关产品推荐
相关产品推荐

