我目前是 OpenGL ES 的新手,并且正在自学如何编写 iOS 游戏。我目前正在玩一个项目,我想在 HUD 上放置一些自定义文本。我不想使用 UILabel 来执行此操作,并且目前不知道如何使用 Quads 来剪切 png 或这样的完整文本并将它们附加到用于显示的普通文本上。我希望最终结果是为命令/方法提供一个简单的字符串,并使用四边形的纹理/位图显示输出。说 glPrint("Hello World");。谁能指导我正确的方向?似乎没有一个关于如何为 OpenGL ES 2.0(只是 OpenGL)执行此操作的好的教程。我还想尽量避免使用 3rd 方 API。我真的需要/想了解如何解决这个问题。
2 回答
当我开始为我当前的 2D 项目使用 OpenGL ES 时,我使用了Ray 的教程,它帮助我掌握了渲染纹理 2D 四边形的方法。结合他的3D OpenGL ES 教程,你也许可以拼凑出你想做的事情。请注意,您可能不会像教程中那样单独渲染每个四边形,因为这样效率非常低。相反,您会将字符的所有顶点收集到两个大数组/顶点缓冲区中并批量渲染字符。渲染每一帧的基本流程可能如下所示:为 3D 渲染传递一个正常的透视投影矩阵,以某种方式将 3D 场景的顶点信息传递给着色器,然后渲染 3D 场景。这部分你已经完成了。对于文本,紧随其后,传入一个正交投影矩阵,绑定你的字体纹理(通常在前面生成GLKTextureLoader
类)到活动纹理单元,为字符生成两个大的纹理和几何顶点数组/如果文本已更改,则更新 VBO,将其传入,然后使用glDrawArrays
or一次批量渲染所有字母glDrawElements
(这需要索引)。
此外,由于我也是使用 OpenGL 的新手,因此其中一些可能是错误的/效率低下的。我还没有使用 OpenGL ES 来渲染任何 3D,所以我不确定在渲染 3D 场景和 2D 场景(文本)之间除了不同的投影矩阵之外可能需要哪些其他状态更改(启用、禁用等) .
似乎仅使用 OpenGL 绘制文本是一项相对困难且乏味的任务,因此,如果您只想渲染显示帧速率和其他内容的 HUD 叠加层,则最好使用UILabel
s 并省去麻烦,尤其是如果您的项目是不是很复杂。这也使您不必处理换行、字距调整、字体大小、颜色、不同语言和大量其他内容,如果您需要更复杂的内容,这些内容会使文本渲染变得非常复杂。
与其跟踪每个字母的位置,不如使用 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 并使其自动调整大小以适合其文本,您可以在其上设置文本,使用上面的内容来渲染和上传您的纹理,然后获取元素的像素大小来确定您的四边形大小。-drawAtPoint:withFont:fontForSize:
但是,仅使用NSString 等自己绘制文本可能会更有效。
使用 Core Graphics 渲染您的文本可以轻松地将文本作为 NSString 进行操作,并使用 Core Graphics 的所有排版功能,而不是自己滚动。