要点
- 现象:文本超过约 260 个字符时,出现错误字形,但仅发生在 WebGL 上。
- 原因:Nova 的回退渲染器将顶点打包到一维 RGBA 纹理中,宽度超过了 WebGL 的 8192 像素限制。
- 修复:将缓冲区分成宽度为 8192 像素的行,并同步 shader 中的行宽。
问题:长文本显示损坏
测试发现,WebGL 中超过约 260 chars ≈ 1 024 glyphs 的对话文本,会大约每隔 20 个字形丢失或替换字符。Editor 中原本正常,直到我们强制启用 SystemSettings.UseFallbackRendering = true,同样的问题才出现。
// WebGL console
Texture has out of range width (got 12800 max supported 8192)
原因:过大的回退缓冲区与行宽不一致
当 SSBO 不可用时,例如 WebGL,Nova 会通过纹理缓冲区进行回退渲染。每个字形顶点占 64 字节,即四个 float4 像素。一个包含 3224 个顶点的 <TextBlock> 会生成 12896 px × 1 的纹理,远超 WebGL 限制。
把宽度限制到 8192 像素后,又出现了第二个问题:shader 仍然预期每行宽 16384 像素,导致更新写入一行,而 GPU 从另一行读取。
通过两处代码调整解决
1. 将缓冲区纹理分行
int maxEdge = 8192;
int width = Mathf.Min(numPixels, maxEdge);
int height = Mathf.CeilToInt((float)numPixels / width);
texture = new Texture2D(width, height, TextureFormat.RGBAFloat, false, true);
2. 同步 shader 常量
#if defined(NOVA_FALLBACK_RENDERING)
#if defined(UNITY_WEBGL) || defined(UNITY_EDITOR)
#define MAX_TEXTURE_DIMENSION 8192u
#else
#define MAX_TEXTURE_DIMENSION 16384u
#endif
#endif
我们还修改了 SetData(),让 RGBA 路径遵循 shaderBufferStartIndex * 4,避免运行时更新覆盖之前的字形。
结果
- WebGL 构建:没有显示伪影或崩溃。
- 独立桌面构建继续使用 16384 像素的 SSBO 路径。
- Editor 中仍有异常表现,但目前并非优先修复事项。
下一步
改动位于 develop 分支,预计会随下一次 Alpha 版本发布。如果你遇到类似的 Nova UI 问题,欢迎通过 Discord、Facebook 或评论告诉我们。
