我正在为OpenGL应用程序编写文本渲染器。可以在运行时对大小,颜色,字体和消除锯齿进行双重处理(因此屏幕上可以同时显示多个字体)。将一个纹理分配给字符串和属性的每个组合的组合太多。但是,在任何给定时间,屏幕上只有整个字符串数据库的一小部分。
这使我有机会为逐帧打印的字符串创建缓存。我强制要求我只对整个操作使用一个纹理,因为创建许多纹理的缓存会对从缓存中打印的每个不同字符串产生纹理交换惩罚。
所以我面前有一个2048x2048纹理,我可以放置任何我可以适合的字符串,因为它们是应用程序为缓存目的而请求的。我很快意识到跟踪二维空间中的可用空间并非易事。
我一直在寻找Best Fit和Next fit之类的东西,但这些似乎适合1d空间。
如何在OpenGL中管理此缓存纹理?
编辑:我从那时起就知道这是“二维打包问题”的一个例子。
答案 0 :(得分:2)
你所拥有的是装箱问题。
首先是坏消息:它是NP难的,因此找到最佳解决方案是值得的。
我也为字体做了这样的纹理缓存。我没有缓存整个单词,只是字形图像。这使事情变得更加容易,因为你的所有图像都是大致方形的。一个简单的基于网格的方法来跟踪纹理内存的效果非常好。
如果我得到的字形大于我的一个网格框,我只是使用强力搜索分配了两个或更多的框(它经常没有发生)。如果我没有找到任何合适的块,我只是从缓存中随机删除一些字形以腾出空间。
这比在最近使用的最后一个缓存中保存内容并且表现几乎一样好。
顺便说一句 - 对于这样的缓存,你总是会在纹理内存上浪费一些。除非你非常严格记忆,这应该不是问题。你应该使用一个小的纹理格式(8位alpha适用于字体)。
另外:如果你的网格块是8像素的倍数,你可以将抗锯齿降为4位,你可以动态地将字形压缩成压缩的DXT或S3TC格式之一。浪费的纹理空间就成了一个问题。
答案 1 :(得分:1)
如果您缺少纹理记忆,可以查看“距离场”或“有符号距离场”字体渲染技术。您可以为每个字体系列使用512x512纹理,并且可以呈现任意大小的完全抗锯齿文本。
对于该算法,您需要生成一个特殊纹理,其中包含从纹理元素到纹理边缘的距离。看看Valve的原始论文:http://www.valvesoftware.com/publications/2007/SIGGRAPH2007_AlphaTestedMagnification.pdf。有一些框架利用这一点。例如,Qt的最新版本使用带符号的距离字段进行文本渲染。
答案 2 :(得分:0)
我选择使用一种简单的方法。将纹理划分为可变高度行。要放在一行中的第一个纹理决定了行的高度。如果纹理可以按高度适合现有行,请检查是否有足够的宽度并将其放置在那里。否则开始一个新行。如果无法启动新行,请不要缓存该字符串。