关于在iOS上使用OpenGL ES 2.0中的自定义文本的Quads的好教程

时间:2013-02-13 14:58:22

标签: ios opengl-es bitmap textures

我目前是OpenGL ES的新手,我自学了如何编写iOS游戏。我目前正在玩一个项目,我想用一些自定义文本放置HUD。我不想使用UILabel这样做,并且目前不知道如何使用Quads来剪切png或如此完整的文本并将它们附加到用于显示的普通文本。我希望最终结果是为命令/方法提供一个简单的字符串,并使用四边形的纹理/位图显示输出。说glPrint(" Hello World");.有人能指导我正确的方向吗?对于如何为OpenGL ES 2.0(只是OpenGL)执行此操作,似乎没有一个好的教程。我还想尽量避免使用第三方API。我真的需要/想要了解如何解决这个问题。

2 个答案:

答案 0 :(得分:1)

当我开始使用OpenGL ES进行当前的2D项目时,我使用了Ray's tutorial,这有助于我处理渲染纹理2D四边形。与他的3D OpenGL ES tutorial一起,你可能能够拼凑你想做的事情。请注意,您可能不会像教程中那样单独渲染每个四元组,因为效率非常低。相反,您会将字符的所有顶点收集到两个大数组/顶点缓冲区中并批量渲染字符。渲染每个帧的基本流程可能如下所示:传递用于3D渲染的普通透视投影矩阵,以某种方式将3D场景的顶点信息提供给着色器,渲染3D场景。这部分你已经完成了。对于文本,紧接着,传递正交投影矩阵,将您的字体纹理(通常先前使用GLKTextureLoader类生成)绑定到活动纹理单元,为字符/生成两个大的纹理和几何顶点数组如果文本已更改,则更新VBO,将其传入,然后使用glDrawArraysglDrawElements(需要索引)批量渲染所有字母。

另外,由于我也是使用OpenGL的新手,其中一些可能是错误/低效的。我还没有使用OpenGL ES渲染任何3D,所以我不确定在渲染3D场景和2D场景(文本)之间可能还需要不同的投影矩阵,其他状态更改(启用,禁用等)

似乎仅使用OpenGL绘制文本是一项相对困难和繁琐的任务,因此如果您只想呈现显示帧率和其他内容的HUD叠加层,那么最好使用UILabel并保存自己麻烦,特别是如果你的项目不是很复杂。这也可以防止您不得不处理包装,字距调整,字体大小,颜色,不同语言以及其他大量内容,如果您需要更复杂的内容,这些内容会使文本呈现变得非常复杂。

答案 1 :(得分:0)

为什么不使用Core Graphics将整个字符串绘制成位图,然后将其作为纹理上传,而不是跟踪每个字母的位置?您只需要从位图中获取尺寸即可知道要为该文本字符串绘制的四边形大小。

在我的开源GPUImage框架中,我有一个名为GPUImageUIElement的输入类,它做了类似的事情。该输入的相关代码如下:

CGSize layerPixelSize = [self layerSizeInPixels];

GLubyte *imageData = (GLubyte *) calloc(1, (int)layerPixelSize.width * (int)layerPixelSize.height * 4);

CGColorSpaceRef genericRGBColorspace = CGColorSpaceCreateDeviceRGB();    
CGContextRef imageContext = CGBitmapContextCreate(imageData, (int)layerPixelSize.width, (int)layerPixelSize.height, 8, (int)layerPixelSize.width * 4, genericRGBColorspace,  kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
CGContextTranslateCTM(imageContext, 0.0f, layerPixelSize.height);
CGContextScaleCTM(imageContext, layer.contentsScale, -layer.contentsScale);

[layer renderInContext:imageContext];

CGContextRelease(imageContext);
CGColorSpaceRelease(genericRGBColorspace);

glBindTexture(GL_TEXTURE_2D, outputTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (int)layerPixelSize.width, (int)layerPixelSize.height, 0, GL_BGRA, GL_UNSIGNED_BYTE, imageData);

free(imageData);

此代码使用CALayer(直接或从UIView的后备层)并将其内容呈现为纹理。我之前已经初始化了纹理,因此代码设置了一个位图上下文,使用-renderInContext:将图层渲染到该上下文中,然后将该位图上传到纹理以供OpenGL ES使用。

辅助方法-layerSizeInPixels仅考虑当前的Retina比例因子,如下所示:

- (CGSize)layerSizeInPixels;
{
    CGSize pointSize = layer.bounds.size;
    return CGSizeMake(layer.contentsScale * pointSize.width, layer.contentsScale * pointSize.height);
}

如果您为视图使用UILabel并使其自动调整以适合其文本,则可以在其上设置文本,使用上面的内容渲染和上传纹理,然后获取元素的像素大小以确定四倍大小。但是,使用带有NSString的-drawAtPoint:withFont:fontForSize:等来自己绘制文本可能会更有效。

使用Core Graphics渲染文本可以轻松地将文本作为NSString进行操作,并使用所有Core Graphics的排版功能,而不是自己编写。