在OpenGL ES绘制文本(Draw text in OpenGL ES)

2019-06-21 04:06发布

我目前正在开发针对Android平台的OpenGL小游戏,我不知道是否有呈现文本的渲染帧的顶部(如HUD与player's成绩等)的简单方法。 该文本将需要使用自定义字体也。

我见过使用视图作为覆盖一个例子,但我不知道如果我想这样做,因为我可能要口游戏到其他平台版本。

有任何想法吗?

Answer 1:

Android SDK提供不附带任何简单的方法来绘制OpenGL的意见文本。 让你有以下选项。

  1. 将在你的SurfaceView一个TextView。 这是缓慢的,坏的,但最直接的方法。
  2. 渲染常见字符串,纹理,和简单地划那些纹理。 这是迄今为止最简单和最快的,但也是最不灵活的。
  3. 滚你自己的基于精灵的文本渲染代码。 如果2是不是一种选择可能退而求其次的选择。 一个好方法,让你的脚湿,但注意,虽然看似简单(和基本功能),它获得的更困难和更有挑战性,因为你添加更多的功能(纹理排列,处理换行符,可变宽度的字体等。 ) - 如果你走这条路线,让它就这么简单,你可以逃脱!
  4. 使用一个现成的,货架/开放源码库。 还有,如果你在寻找谷歌的几个周围,棘手位是让他们集成和运行。 但至少,一旦你这样做,你就会有所有的灵活性和成熟,他们提供的。


Answer 2:

文本渲染到纹理比雪碧文本演示做什么样子,其基本思想是使用Canvas类来渲染成位图,然后将位图传递到一个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();


Answer 3:

我写了一个教程上刊登的答案扩展JVitela 。 基本上,它采用了同样的想法,但不是每个字符串渲染到纹理,它呈现从字体文件中的所有字符的纹理和使用,为了让全动态文本渲染,没有进一步的减速(一旦初始化完成) 。

我的方法的主要优点,相比于各种字体地图集发电机,是可以出货,而不必船舶大型位图每个字体的变化和体积小的字体文件(.TTF .otf)的与您的项目。 它可以产生仅使用字体文件在任何分辨率下完美的品质字体:)

该教程包括完整的代码可以在任何项目中使用:)



Answer 4:

根据此链接:

http://code.neenbedankt.com/how-to-render-an-android-view-to-a-bitmap

可以渲染任何视图为位图。 这可能是值得假设你需要(包括文字,图片等),你可以配置的图,然后将其渲染为位图。

使用JVitela的代码上面 ,你应该能够使用位图作为一个OpenGL纹理。



Answer 5:

看看CBFG和加载/渲染代码的Android的端口。 您应该能够将代码放到你的项目,并用它立竿见影。

CBFG - http://www.codehead.co.uk/cbfg

Android的装载机- http://www.codehead.co.uk/cbfg/TexFont.java



Answer 6:

我看着精灵文本示例,它看起来对这样的任务非常复杂,我认为渲染到纹理太多,但我担心对性能的影响可能会导致。 我可能只是有一个观点去代替而发愁时移植它的时间到桥头:)



Answer 7:

看看在“雪碧文本”样品GLSurfaceView样本 。



Answer 8:

如果你坚持使用GL,你可以渲染到纹理的文本。 假设大部分的HUD的是相对静态的,你不应该过于频繁加载纹理纹理内存。



Answer 9:

看看CBFG和加载/渲染代码的Android的端口。 您应该能够将代码放到你的项目,并用它立竿见影。

  1. CBFG

  2. Android的装载机

我有这个执行问题。 它显示只有一个字符,当我尝试做字体的位图的变化大小(我需要特殊字母)全平局失败:(



Answer 10:

恕我直言,有三个方面的原因在一场比赛中使用OpenGL ES:

  1. 通过使用开放标准避免移动平台之间的差异;
  2. 有渲染过程的更多的控制;
  3. 从GPU的并行处理中受益;

绘制文本始终是在游戏设计中的一个问题,因为你是画的东西,所以你不能拥有的外观和感觉的共同活动,与小部件等。

你可以用一个框架来从TrueType字体位图字体,并将其呈现。 我见过的所有的框架的操作方式相同:生成顶点,并在绘制时文本纹理坐标。 这是不是最有效利用OpenGL。

最好的办法是分配远程缓冲器(顶点缓冲对象 - 维也纳各组织)为顶点和纹理代码早,避免了在绘制时所述懒惰存储器传输操作。

请记住,游戏玩家不喜欢阅读的文本,这样你就不会写很长的动态生成的文本。 对于标签,您可以使用静态的纹理,使动态文本的时间和得分,无一不是数字与几个字符。

所以,我的解决方法很简单:

  1. 创建纹理常见的标签和警告;
  2. 创建纹理数字0-9, “:”, “+” 和 “ - ”。 为每个字符一个纹理;
  3. 生成在屏幕上的所有位置偏远维也纳组织。 我可以呈现在该位置静态或动态文本,但维也纳组织是静态的;
  4. 生成只有一个纹理VBO,如文本始终呈现一种方式;
  5. 在抽签的时候,我渲染静态文本;
  6. 对于动态文本,我可以在该位置VBO偷看,让人物的纹理和绘制,一次一个字符。

绘制操作速度快,如果你使用远程静态缓冲。

我创建屏幕位置(基于屏幕的对角线百分比)和纹理(静态和字符)的XML文件,然后我呈现之前加载此XML。

为了得到一个高的FPS率,你应该避免在绘图时产生维也纳组织。



Answer 11:

我一直在寻找这几个小时,这是我来到翻过的第一篇文章,虽然它有最好的答案,最流行的答案,我认为是没谱。 当然,我需要的东西。 weichsel的和shakazed的答案是正确的按钮,但在文章有点模糊。 把你的权利的项目。 在这里:只要创建基于现有样本一个新的Android项目。 选择ApiDemos:

看看源文件夹下

ApiDemos/src/com/example/android/apis/graphics/spritetext

而且你会发现你所需要的一切。



Answer 12:

对于静态文本

  • 可为您的PC上使用(例如用GIMP)所有单词的图像。
  • 这个加载作为纹理,并用它作为材料的平面。

对于需要在一段时间更新一次长文本

  • 让我们在一个位图的画布的Android平局(JVitela的解决方案)。
  • 加载这个为材料的平面。
  • 使用不同的纹理坐标的每个字。

对于一些 (格式化00.0):

  • 生成与所有数字和一个点的图像。
  • 加载这个为材料的平面。
  • 使用下面着色器。
  • 在你的onDraw事件仅更新发送到着色器变量的值。

     precision highp float; precision highp sampler2D; uniform float uTime; uniform float uValue; uniform vec3 iResolution; varying vec4 v_Color; varying vec2 vTextureCoord; uniform sampler2D s_texture; void main() { vec4 fragColor = vec4(1.0, 0.5, 0.2, 0.5); vec2 uv = vTextureCoord; float devisor = 10.75; float digit; float i; float uCol; float uRow; if (uv.y < 0.45) { if (uv.x > 0.75) { digit = floor(uValue*10.0); digit = digit - floor(digit/10.0)*10.0; i = 48.0 - 32.0 + digit; uRow = floor(i / 10.0); uCol = i - 10.0 * uRow; fragColor = texture2D( s_texture, uv / devisor * 2.0 + vec2((uCol-1.5) / devisor, uRow / devisor) ); } else if (uv.x > 0.5) { uCol = 4.0; uRow = 1.0; fragColor = texture2D( s_texture, uv / devisor * 2.0 + vec2((uCol-1.0) / devisor, uRow / devisor) ); } else if (uv.x > 0.25) { digit = floor(uValue); digit = digit - floor(digit/10.0)*10.0; i = 48.0 - 32.0 + digit; uRow = floor(i / 10.0); uCol = i - 10.0 * uRow; fragColor = texture2D( s_texture, uv / devisor * 2.0 + vec2((uCol-0.5) / devisor, uRow / devisor) ); } else if (uValue >= 10.0) { digit = floor(uValue/10.0); digit = digit - floor(digit/10.0)*10.0; i = 48.0 - 32.0 + digit; uRow = floor(i / 10.0); uCol = i - 10.0 * uRow; fragColor = texture2D( s_texture, uv / devisor * 2.0 + vec2((uCol-0.0) / devisor, uRow / devisor) ); } else { fragColor = vec4(0.0, 0.0, 0.0, 0.0); } } else { fragColor = vec4(0.0, 0.0, 0.0, 0.0); } gl_FragColor = fragColor; } 

上面的代码工作的纹理图集其中数字是从0开始的字体地图集(纹理)的第二行的第七列。

请参阅https://www.shadertoy.com/view/Xl23Dw示范(纹理错的)



文章来源: Draw text in OpenGL ES