在 OpenGL ES 中绘制文本
我目前正在为 Android 平台开发一个小型 OpenGL 游戏,我想知道是否有一种简单的方法可以在渲染帧之上渲染文本(例如带有玩家分数的 HUD 等)。文本还需要使用自定义字体。
我见过一个使用视图作为叠加层的示例,但我不知道是否要这样做,因为我稍后可能想将游戏移植到其他平台。
有什么想法吗?
I'm currently developing a small OpenGL game for the Android platform and I wonder if there's an easy way to render text on top of the rendered frame (like a HUD with the player´s score etc). The text would need to use a custom font also.
I've seen an example using a View as an overlay, but I don't know if I want to do that since I might want to port the game to other platforms later.
Any ideas?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(13)
将文本渲染到纹理比 Sprite Text 演示使它看起来更简单,基本思想是使用 Canvas 类渲染到位图,然后将位图传递到 OpenGL 纹理:
Rendering text to a texture is simpler than what the Sprite Text demo make it looks like, the basic idea is to use the Canvas class to render to a Bitmap and then pass the Bitmap to an OpenGL texture:
Android SDK 没有提供任何在 OpenGL 视图上绘制文本的简单方法。留给您以下选择。
The Android SDK doesn't come with any easy way to draw text on OpenGL views. Leaving you with the following options.
我写了一个教程扩展了 JVitela 发布的答案。基本上,它使用相同的想法,但不是将每个字符串渲染到纹理,而是将字体文件中的所有字符渲染到纹理,并使用它来允许完全动态文本渲染,而不会进一步减慢(初始化完成后) 。
与各种字体图集生成器相比,我的方法的主要优点是您可以在项目中提供小字体文件(.ttf .otf),而不必为每种字体变体和大小提供大位图。它可以仅使用字体文件在任何分辨率下生成完美质量的字体:)
教程 包含可在任何项目中使用的完整代码:)
I've written a tutorial that expands on the answer posted by JVitela. Basically, it uses the same idea, but instead of rendering each string to a texture, it renders all characters from a font file to a texture and uses that to allow for full dynamic text rendering with no further slowdowns (once the initialization is complete).
The main advantage of my method, compared to the various font atlas generators, is that you can ship small font files (.ttf .otf) with your project instead of having to ship large bitmaps for every font variation and size. It can generate perfect quality fonts at any resolution using only a font file :)
The tutorial includes full code that can be used in any project :)
看一下 CBFG 和加载/渲染代码的 Android 端口。您应该能够将代码放入您的项目中并立即使用它。
CBFG - http://www.codehead.co.uk/cbfg
Android 加载程序 - http://www.codehead.co.uk/cbfg/TexFont.java
Take a look at CBFG and the Android port of the loading/rendering code. You should be able to drop the code into your project and use it straight away.
CBFG - http://www.codehead.co.uk/cbfg
Android loader - http://www.codehead.co.uk/cbfg/TexFont.java
根据此链接:
http://code .neenbedankt.com/how-to-render-an-android-view-to-a-bitmap
您可以将任何视图渲染为位图。可能值得假设您可以根据需要布局视图(包括文本、图像等),然后将其渲染为位图。
使用 JVitela 的代码上面你应该能够使用该位图作为 OpenGL 纹理。
According to this link:
http://code.neenbedankt.com/how-to-render-an-android-view-to-a-bitmap
You can render any View to a bitmap. It's probably worth assuming that you can layout a view as you require (including text, images etc.) and then render it to a Bitmap.
Using JVitela's code above you should be able to use that Bitmap as an OpenGL texture.
我查看了精灵文本示例,对于这样的任务来说,它看起来非常复杂,我也考虑过渲染到纹理,但我担心这可能会导致性能下降。
我可能只需要去看风景,然后担心在过桥时需要移植:)
I looked at the sprite text example and it looks awfully complicated for such a task, I considered rendering to a texture too, but I'm worried about the performance hit that might cause.
I might just have to go with a view instead and worry about porting when it's time to cross that bridge :)
恕我直言,在游戏中使用 OpenGL ES 有以下三个原因:
绘制文本始终是游戏设计中的一个问题,因为您正在绘制东西,因此您无法拥有常见活动(例如小部件等)的外观和感觉。
您可以使用框架从 TrueType 字体生成位图字体并渲染它们。我见过的所有框架都以相同的方式运行:在绘制时生成文本的顶点和纹理坐标。这并不是 OpenGL 最有效的使用方式。
最好的方法是在代码的早期为顶点和纹理分配远程缓冲区(顶点缓冲区对象 - VBO),避免绘制时的惰性内存传输操作。
请记住,游戏玩家不喜欢阅读文本,因此您不会编写长的动态生成的文本。对于标签,您可以使用静态纹理,保留时间和分数的动态文本,两者都是带有几个字符长的数字。
所以,我的解决方案很简单:
如果您使用远程静态缓冲区,绘制操作会很快。
我创建一个包含屏幕位置(基于屏幕对角线百分比)和纹理(静态和字符)的 XML 文件,然后在渲染之前加载此 XML。
为了获得高 FPS 速率,您应该避免在绘制时生成 VBO。
IMHO there are three reasons to use OpenGL ES in a game:
Drawing text is always a problem in game design, because you are drawing things, so you cannot have the look and feel of a common activity, with widgets and so on.
You can use a framework to generate Bitmap fonts from TrueType fonts and render them. All the frameworks I've seen operate the same way: generate the vertex and texture coordinates for the text in draw time. This is not the most efficient use of OpenGL.
The best way is to allocate remote buffers (vertex buffer objects - VBOs) for the vertices and textures early in code, avoiding the lazy memory transfer operations in draw time.
Keep in mind that game players don't like to read text, so you won't write a long dynamically generated text. For labels, you can use static textures, leaving dynamic text for time and score, and both are numeric with a few characters long.
So, my solution is simple:
Draw operations are fast, if you use remote static buffers.
I create an XML file with screen positions (based on screen's diagonal percentage) and textures (static and characters), and then I load this XML before rendering.
To get a high FPS rate, you should avoid generating VBOs at draw time.
查看 GLSurfaceView 示例 中的“Sprite Text”示例。
Look at the "Sprite Text" sample in the GLSurfaceView samples.
如果您坚持使用 GL,您可以将文本渲染到纹理上。假设大部分 HUD 是相对静态的,您不必过于频繁地将纹理加载到纹理内存中。
If you insist on using GL, you could render the text on to textures. Assuming that most of the HUD is relatively static, you shouldn't have to load the textures to texture memory too often.
看一下
CBFG
和加载/渲染的Android端口代码。您应该能够将代码放入您的项目中并使用它
马上。
CBFG
Android loader
我对此实现有问题。它只显示一个字符,当我尝试更改字体位图的大小(我需要特殊字母)时,整个绘制失败:(
Take a look at
CBFG
and the Android port of the loading/renderingcode. You should be able to drop the code into your project and use it
straight away.
CBFG
Android loader
I have problems with this implementation. It displays only one character, when I try do change size of the font's bitmap (I need special letters) whole draw fails :(
我已经找了几个小时了,这是我遇到的第一篇文章,虽然它有最好的答案,但我认为最受欢迎的答案是不切实际的。当然是为了我需要的。
weichsel 和 shakazed 的答案就在按钮上,但在文章中有点模糊。
让您正确参与该项目。这里:
只需根据现有示例创建一个新的 Android 项目即可。选择 ApiDemos:
查看源文件夹
ApiDemos/src/com/example/android/apis/graphics/spritetext
你会找到你需要的一切。
I have been looking for this for a few hours, this was the first article i came accross and although it has the best answer, the most popular answers i think are off the mark. Certainly for what i needed.
weichsel's and shakazed's answers were right on the button but a bit obscured in the articles.
To put you right to the project. Here:
Just create a new Android project based on existing sample. Choose ApiDemos:
Look under the source folder
ApiDemos/src/com/example/android/apis/graphics/spritetext
And you will find everything you need.
对于静态文本:
对于需要偶尔更新的长文本:
对于数字(格式为 00.0):
在 onDraw 事件中仅更新发送到着色器的值变量。
上面的代码适用于纹理图集,其中数字从字体图集(纹理)第二行的第七列的 0 开始。
参考https://www.shadertoy.com/view/Xl23Dw进行演示(纹理错误尽管)
For static text:
For long text that needs to be updated once in a while:
For a number (formatted 00.0):
In your onDraw event only update the value variable sent to the shader.
Above code works for a texture atlas where numbers start from 0 at the 7th column of the 2nd row of the font atlas (texture).
Refer to https://www.shadertoy.com/view/Xl23Dw for demonstration (with wrong texture though)
在OpenGL ES 2.0/3.0中,您还可以结合OGL视图和Android的UI元素:
创建布局activity_gl.xml:
要从渲染线程更新元素,可以使用Handler/Looper。
In the OpenGL ES 2.0/3.0 you can also combining OGL View and Android's UI-elements:
Create layout activity_gl.xml:
To update elements from the render thread, can use Handler/Looper.