Android 在 OpenGL ES 中绘制文本
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1339136/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Draw text in OpenGL ES
提问by shakazed
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.
我目前正在为 Android 平台开发一个小型 OpenGL 游戏,我想知道是否有一种简单的方法可以在渲染帧的顶部渲染文本(例如带有玩家分数的 HUD 等)。文本也需要使用自定义字体。
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?
有任何想法吗?
采纳答案by Dave
The Android SDK doesn't come with any easy way to draw text on OpenGL views. Leaving you with the following options.
Android SDK 没有提供在 OpenGL 视图上绘制文本的任何简单方法。留给您以下选项。
- Place a TextView over your SurfaceView.This is slow and bad, but the most direct approach.
- Render common strings to textures, and simply draw those textures.This is by far the simplest and fastest, but the least flexible.
- Roll-your-own text rendering code based on a sprite.Probably second best choice if 2 isn't an option. A good way to get your feet wet but note that while it seems simple (and basic features are), it get's harder and more challenging as you add more features (texture-alignment, dealing with line-breaks, variable-width fonts etc.) - if you take this route, make it as simple as you can get away with!
- Use an off-the-shelf/open-source library.There are a few around if you hunt on Google, the tricky bit is getting them integrated and running. But at least, once you do that, you'll have all the flexibility and maturity they provide.
- 在 SurfaceView 上放置一个 TextView。这是缓慢而糟糕的,但最直接的方法。
- 将常用字符串渲染到纹理,然后简单地绘制这些纹理。这是迄今为止最简单和最快的,但最不灵活。
- 基于精灵滚动你自己的文本渲染代码。如果 2 不是一个选项,则可能是第二个最佳选择。一个让你的脚变湿的好方法,但请注意,虽然它看起来很简单(基本功能也是如此),但随着您添加更多功能(纹理对齐、处理换行符、可变宽度字体等),它会变得更加困难和更具挑战性。 ) - 如果你走这条路,让它尽可能简单!
- 使用现成的/开源库。如果你在谷歌上搜索,有几个,棘手的一点是让它们集成和运行。但至少,一旦您这样做,您将拥有它们提供的所有灵活性和成熟度。
回答by JVitela
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:
将文本渲染到纹理比 Sprite Text 演示看起来更简单,基本思想是使用 Canvas 类渲染到 Bitmap,然后将 Bitmap 传递给 OpenGL 纹理:
// Create an empty, mutable bitmap
Bitmap bitmap = Bitmap.createBitmap(256, 256, Bitmap.Config.ARGB_4444);
// get a canvas to paint over the bitmap
Canvas canvas = new Canvas(bitmap);
bitmap.eraseColor(0);
// get a background image from resources
// note the image format must match the bitmap format
Drawable background = context.getResources().getDrawable(R.drawable.background);
background.setBounds(0, 0, 256, 256);
background.draw(canvas); // draw the background to our bitmap
// Draw the text
Paint textPaint = new Paint();
textPaint.setTextSize(32);
textPaint.setAntiAlias(true);
textPaint.setARGB(0xff, 0x00, 0x00, 0x00);
// draw the text centered
canvas.drawText("Hello World", 16,112, textPaint);
//Generate one texture pointer...
gl.glGenTextures(1, textures, 0);
//...and bind it to our array
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
//Create Nearest Filtered Texture
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
//Different possible texture parameters, e.g. GL10.GL_CLAMP_TO_EDGE
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT);
//Use the Android GLUtils to specify a two-dimensional texture image from our bitmap
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
//Clean up
bitmap.recycle();
回答by free3dom
I've written a tutorialthat 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).
我写了一个教程,扩展了JVitela发布的答案。基本上,它使用相同的想法,但不是将每个字符串渲染到纹理,而是将字体文件中的所有字符渲染到纹理,并使用它来允许完全动态文本渲染而不会进一步减速(一旦初始化完成) .
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 :)
与各种字体图集生成器相比,我的方法的主要优点是您可以随项目一起发送小字体文件 (.ttf .otf),而不必为每个字体变体和大小发送大位图。它可以仅使用字体文件以任何分辨率生成完美质量的字体:)
The tutorialincludes full code that can be used in any project :)
本教程包含可在任何项目中使用的完整代码:)
回答by JWGS
According to this link:
根据这个链接:
http://code.neenbedankt.com/how-to-render-an-android-view-to-a-bitmap
http://code.neenbedankt.com/how-to-render-an-android-view-to-a-bitmap
You can render any Viewto 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 aboveyou should be able to use that Bitmap as an OpenGL texture.
使用上面的 JVitela 代码,您应该能够将该位图用作 OpenGL 纹理。
回答by Codehead
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 和 Android 端口。您应该能够将代码放入您的项目中并立即使用它。
CBFG - http://www.codehead.co.uk/cbfg
CBFG - http://www.codehead.co.uk/cbfg
Android loader - http://www.codehead.co.uk/cbfg/TexFont.java
Android 加载程序 - http://www.codehead.co.uk/cbfg/TexFont.java
回答by shakazed
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 :)
我查看了精灵文本示例,对于这样的任务,它看起来非常复杂,我也考虑过渲染到纹理,但我担心可能会导致性能下降。我可能只需要查看视图并担心在该桥过桥时进行移植 :)
回答by Thomas Zoechling
Look at the "Sprite Text" sample in the GLSurfaceView samples.
查看GLSurfaceView示例中的“Sprite Text”示例。
回答by cleuton
IMHO there are three reasons to use OpenGL ES in a game:
恕我直言,在游戏中使用 OpenGL ES 的三个原因:
- Avoid differences between mobile platforms by using an open standard;
- To have more control of the render process;
- To benefit from GPU parallel processing;
- 通过使用开放标准避免移动平台之间的差异;
- 对渲染过程有更多的控制;
- 受益于 GPU 并行处理;
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.
您可以使用框架从 TrueType 字体生成位图字体并渲染它们。我见过的所有框架都以相同的方式运行:在绘制时为文本生成顶点和纹理坐标。这不是 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.
最好的方法是在代码早期为顶点和纹理分配远程缓冲区(顶点缓冲区对象 - VBO),避免绘制时的惰性内存传输操作。
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:
所以,我的解决方案很简单:
- Create texture for common labels and warnings;
- Create texture for numbers 0-9, ":", "+", and "-". One texture for each character;
- Generate remote VBOs for all positions in the screen. I can render static or dynamic text in that positions, but the VBOs are static;
- Generate just one Texture VBO, as text is always rendered one way;
- In draw time, I render the static text;
- For dynamic text, I can peek at the position VBO, get the character texture and draw it, a character at a time.
- 为常见标签和警告创建纹理;
- 为数字 0-9、“:”、“+”和“-”创建纹理。每个角色一个纹理;
- 为屏幕中的所有位置生成远程 VBO。我可以在这些位置渲染静态或动态文本,但 VBO 是静态的;
- 只生成一个纹理 VBO,因为文本总是以一种方式呈现;
- 在绘制时,我渲染静态文本;
- 对于动态文本,我可以偷看 VBO 的位置,获取字符纹理并绘制它,一次一个字符。
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.
我创建了一个带有屏幕位置(基于屏幕的对角线百分比)和纹理(静态和字符)的 XML 文件,然后在渲染之前加载这个 XML。
To get a high FPS rate, you should avoid generating VBOs at draw time.
为了获得高 FPS 率,您应该避免在绘制时生成 VBO。
回答by Aetherna
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
加载/渲染代码的 Android 端口。您应该能够将代码放入您的项目中并立即使用它。
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 :(
我对这个实现有问题。它只显示一个字符,当我尝试更改字体位图的大小(我需要特殊字母)时,整个绘制失败:(
回答by Tal Pressman
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.
如果您坚持使用 GL,您可以将文本渲染到纹理上。假设大部分 HUD 是相对静态的,您不应该过于频繁地将纹理加载到纹理内存中。