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



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

当我开始为当前的2D项目使用OpenGL ES时,我使用了Ray的教程,它帮助我掌握了渲染纹理2D四边形的方法。结合他的3D OpenGL ES教程,你可能可以拼凑出你想做的事情。请注意,你可能不会像教程中那样单独渲染每个四边形,因为这是非常低效的。相反,您可以将角色的所有顶点聚集到两个大数组/顶点缓冲区中,并批量渲染角色。渲染每一帧的基本流程可能是这样的:为3D渲染传递法线透视投影矩阵,以某种方式将3D场景的顶点信息获取到着色器,渲染3D场景。这部分你已经完成了。对于文本,紧接着,传入一个正交投影矩阵,将字体纹理(通常在GLKTextureLoader类早期生成)绑定到活动纹理单元,为字符生成两个纹理和几何顶点的大数组/如果文本发生了更改,则更新VBO,传入,然后使用CCD_ 2或CCD_。

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

似乎只使用OpenGL绘制文本是一项相对困难和乏味的任务,因此,如果你只想渲染显示帧速率和其他内容的HUD覆盖,最好使用UILabel,这样可以省去麻烦,尤其是在你的项目不是很复杂的情况下。这也防止了你不得不处理包装、紧排、字体大小、颜色、不同的语言和大量其他东西,如果你需要更复杂的东西,这些东西会使文本呈现变得非常复杂。

与其跟踪每个字母的位置,为什么不使用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仅说明当前视网膜比例因子如下:

- (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 Graphic的所有排版功能,而不是滚动自己的功能。

最新更新