使用 openGL 渲染时如何判断字体大小(以像素为单位)
我正在开发 Bitfighter 的编辑器,我们使用默认的 OpenGL 描边字体。我们通常使用 2 的线宽来渲染文本,但这会使较小的字体可读性较差。我想做的是检测字体大小何时低于某个阈值,并将线宽降至 1。问题是,在应用了所有变换等之后,我不知道如何判断有多高(在像素)大小为
这是实际的内部渲染函数:
if(---something--- < thresholdSizeInPixels)
glLineWidth(1);
float scalefactor = fontsize / 120;
glPushMatrix();
glTranslatef(x, y + (fix ? 0 : size), 0);
glRotatef(angle * radiansToDegreesConversion, 0, 0, 1);
glScalef(scaleFactor, -scaleFactor, 1);
for(S32 i = 0; string[i]; i++)
OpenglUtils::drawCharacter(string[i]);
glPopMatrix();
在调用此函数之前,我想检查字体的高度,然后在必要时降低线宽。那个——某物——地方有什么?
Bitfighter 是一款纯粹的老式 2D 游戏,因此没有花哨的 3D 变换。所有代码均采用 C++ 编写。
我的解决方案是将克里斯蒂安·劳的解决方案的第一部分与第二部分的一部分结合起来。基本上,我可以通过以下方式获得当前的缩放因子:
static float modelview[16];
glGetFloatv(GL_MODELVIEW_MATRIX, modelview); // Fills modelview[]
float scalefact = modelview[0];
然后,我将scalefact乘以以像素为单位的字体大小,然后将其乘以windowHeight / canvasHeight的比率以获得我的文本将呈现的高度(以像素为单位)。
那就是……
textheight = scalefact * fontsize * widndowHeight / canvasHeight
我还喜欢缩放线条粗细的想法,而不是在超过阈值时从 2 步进到 1。现在一切都运转良好。
I'm working on the editor for Bitfighter, where we use the default OpenGL stroked font. We generally render the text with a linewidth of 2, but this makes smaller fonts less readable. What I'd like to do is detect when the fontsize will fall below some threshold, and drop the linewidth to 1. The problem is, after all the transforms and such are applied, I don't know how to tell how tall (in pixels) a font of size <fontsize> will be rendered.
This is the actual inner rendering function:
if(---something--- < thresholdSizeInPixels)
glLineWidth(1);
float scalefactor = fontsize / 120;
glPushMatrix();
glTranslatef(x, y + (fix ? 0 : size), 0);
glRotatef(angle * radiansToDegreesConversion, 0, 0, 1);
glScalef(scaleFactor, -scaleFactor, 1);
for(S32 i = 0; string[i]; i++)
OpenglUtils::drawCharacter(string[i]);
glPopMatrix();
Just before calling this, I want to check the height of the font, then drop the linewidth if necessary. What goes in the ---something--- spot?
Bitfighter is a pure old-school 2D game, so there are no fancy 3D transforms going on. All code is in C++.
My solution was to combine the first part Christian Rau's solution with a fragment of the second. Basically, I can get the current scaling factor with this:
static float modelview[16];
glGetFloatv(GL_MODELVIEW_MATRIX, modelview); // Fills modelview[]
float scalefact = modelview[0];
Then, I multiply scalefact by the fontsize in pixels, and multiply that by the ratio of windowHeight / canvasHeight to get the height in pixels that my text will be rendered.
That is...
textheight = scalefact * fontsize * widndowHeight / canvasHeight
And I liked also the idea of scaling the line thickness rather than stepping from 2 to 1 when a threshold is crossed. It all works very nicely now.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
OpenGL 不处理字体。没有默认的 OpenGL 描边字体。
也许您指的是 GLUT 及其 glutStrokeCharacter 函数。那么请注意 GLUT 不是 OpenGL 的一部分。它是一个独立的库,专注于为小型 OpenGL 演示和教程提供简单的框架。
回答你的问题: GLUT Stroke Fonts 是根据顶点定义的,因此应用通常的转换。由于通常所有变换都是线性的,因此您可以简单地通过模型视图和投影变换向量 (0, base_height, 0),最后进行透视划分(
gluProject
为您完成所有这一切 - GLU 不是 OpenGL 的一部分,也),得到的向量就是您要寻找的;取向量长度来缩放宽度。OpenGL doesn't do fonts. There is no default OpenGL stroked font.
Maybe you are referring to GLUT and its
glutStrokeCharacter
function. Then please take note that GLUT is not part of OpenGL. It's an independent library, focused on providing a simplicistic framework for small OpenGL demos and tutorials.To answer your question: GLUT Stroke Fonts are defined in terms of vertices, so the usual transformations apply. Since usually all transformations are linear, you can simply transform the vector (0, base_height, 0) through modelview and projection finally doing the perspective divide (
gluProject
does all this for you – GLU is not part OpenGL, too), the resulting vector is what you're looking for; take the vector length for scaling the width.这应该很容易确定。字体的像素大小仅取决于模型视图变换(实际上仅缩放部分)、投影变换(我想这是一个简单的正交投影)和视口设置,当然还取决于单个字符的大小未转换形式的字体(进入
glVertex
调用的内容)。因此,您只需采用字体的基本尺寸(让我们仅考虑高度并将其称为
height
),然后首先进行模型视图转换(假设代码中显示的缩放是唯一的):接下来我们执行投影变换:
top
和bottom
是指定正交变换时使用的值(例如使用glOrtho
)。最后但并非最不重要的一点是,我们进行视口转换:您猜对了,
viewportHeight
是在glViewport
调用中指定的视口高度。生成的height
应该是字体的高度(以像素为单位)。您可以使用它以某种方式缩放线宽(无需 if),因为线宽参数无论如何都是浮点数,让 OpenGL 进行离散化。如果您的转换管道更复杂,您可以使用更通用的方法,使用完整的转换矩阵,也许可以在 gluProject 将对象空间点转换为屏幕空间点:
这里我采用了角色的对角线,而不仅仅是高度,以便更好地忽略旋转,我们使用原点作为参考值忽略翻译。
您可能还会发现这个问题的答案很有趣,这可以让您更深入地了解 OpenGL 的转换管道。
This should be determinable rather easily. The font's size in pixels just depends on the modelview transformation (actually only the scaling part), the projection transformation (which is a simple orthographic projection, I suppose) and the viewport settings, and of course on the size of an individual character of the font in untransformed form (what goes into the
glVertex
calls).So you just take the font's basic size (lets consider the height only and call it
height
) and first do the modelview transformation (assuming the scaling shown in the code is the only one):Next we do the projection transformation:
with
top
andbottom
being the values you used when specifying the orthographic transformation (e.g. usingglOrtho
). And last but not least we do the viewport transformation:with
viewportHeight
being, you guessed it, the height of the viewport specified in theglViewport
call. The resultingheight
should be the height of your font in pixels. You can use this to somehow scale the line width (without an if), as the line width parameter is in floats anyway, let OpenGL do the discretization.If your transformation pipeline is more complicated, you could use a more general approach using the complete transformation matrices, perhaps with the help of gluProject to transform an object-space point to a screen-space point:
Here I took the diagonal of the character and not only the height, to better ignore rotations and we used the origin as reference value to ignore translations.
You might also find the answers to this question interesting, which give some more insight into OpenGL's transformation pipeline.