【问题标题】:Is there a decent OpenGL text drawing library for the iPhone SDK?iPhone SDK 有没有像样的 OpenGL 文本绘图库?
【发布时间】:2009-02-04 17:00:48
【问题描述】:

我正在尝试找出一个在 OpenGL 中绘制一些文本的简单方法。我的研究表明这是一项相当复杂的任务。它涉及创建(或在运行时生成)字体图集纹理,然后为每个字母创建一个具有正确位置和纹理坐标的四边形。

我听说过一些关于 freetype 的好消息,但几乎没有发现如何让它在 iPhone 上运行,而且它似乎相当复杂。

那么,有没有任何 Objective-C 封装的 OpenGL 文本库可以与人们一直在使用的 iPhone SDK 一起使用?还是我只是想多了,我错过了一种更简单的方法?

【问题讨论】:

标签: cocoa-touch opengl-es freetype


【解决方案1】:

一种方法是设置 UILabel,然后将其图层渲染为纹理。一个间接的途径是首先使用文本、字体等设置 UILabel,然后使用以下代码

UIGraphicsBeginImageContext(yourLabel.frame.size);
[yourLabel.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *layerImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

将 UILabel 捕获到 UIImage。然后,您可以使用 CrashLanding 项目中 Texture2D 类的 initWithImage: 构造函数将其转换为纹理。

看起来像 initWithImage:在该示例中,将 UIImage 重新渲染到位图上下文并使用它来创建纹理。通过一些工作,您可以从该方法中提取相关代码并更改上述代码以将您的图层直接渲染到纹理中。

这样,在为纹理创建文本时,您可以获得 UILabel 良好的 Unicode 和字体支持。

【讨论】:

  • 我试图避免为每个渲染的字符串动态生成不同的纹理。我的应用会显示许多不同的字符串,这似乎会对 CPU 和内存造成巨大压力。
  • 这实际上是 iPhone 对您看到的每条文本所做的事情。所有的 UILabel 都是 CALayer 支持的,而 CALayer 只是包装的 OpenGL 纹理。我认为这并不像你想象的那样消耗资源。
  • iPhone 开发者网站似乎不再提供崩溃登陆演示应用程序下载,是否有合适的替代方案?
  • GLSprite 使用了类似的技术,所以我相信您可以使用它来代替它。
  • 这个方法不是很有用,因为你必须在 drawRect 方法中调用 UIGraphicsBeginImageContext,而这需要创建一个 UIKit 视图来渲染 UILabel。最好使用 UIGraphicsPushContext 手动完成。
【解决方案2】:

您对使用 freetype 创建纹理图集以及所有字形信息的描述正是我在当前 iPhone 项目中所做的。

我在预处理步骤中对字体进行所有解析(所有在 Windows 上的 C# 中)。地图集本身会生成并且仅包含所需的字符 - 为了减少空间,我有时也会生成多个地图集以保持纹理大小 pow2 和合理的分辨率。

您可以轻松地从 freetype 中提取字形信息。在运行时将其与纹理一起传递给您的应用程序,然后根据需要更改纹理的 UV 坐标相当简单。

不管怎样,这就是我在我的小引擎中定义字形字符的方式:

struct FontGlyph
{

u32 char_code;

u32 m_x;                // base x position on tpage

u32 m_y;            // base y position on tpage

u32 m_width;            // glyph width

u32 m_height;           // glyph height

i32 m_horiBearingX;     // Distance to X shift

i32 m_horiBearingY;     // Distance to Y shift

u32 m_horiAdvance;      // Total Horizontal advance this character requires

u32 m__tpage_index;     // Which tpage does this glyph use?

};

然后我有一个“SpriteString”对象,它的行为与任何其他字符串非常相似,除了我可以使用精灵来绘制它......

我同意这对于一个相当微不足道的问题来说似乎是一项艰巨的工作,但我发现它给了我很大的灵活性,而且当我开始着手时真的不需要那么长时间来实施。

如果您需要任何其他详细信息,请随时回复或评论。 (祝你好运:)


当我在评论部分的空间不足时回复您的评论...

查看 freetype 文档,它基本上为您提供字形数据而不会弄乱,它只是将其从字体中提取出来。至于纹理本身,您可以使用 freetype 来渲染每个字形,然后对其进行管理以构建纹理。这是我作为一个完全独立于我的主应用程序的预处理来完成的。

这是我执行此操作的工具代码的摘录:http://pastebin.com/md1c6354

但请注意,这只是为了我的眼睛而不是为了公共消费,所以请原谅它乱七八糟的事实:)

【讨论】:

  • 这个结构绝对可以帮助我理解所涉及的所有步骤。谢谢你。不过,我将如何生成纹理和字形数据?
  • 谢谢,这可能是最好的路线。如果我想出一个不错的解决方案,我会试着把它包装好,然后把它扔到 github 上供大家分享。
  • @Squeegy :你准备好解决方案了吗?可以分享一下链接吗
  • 不,我从来没有这样做过。太懒了。 :(
【解决方案3】:

我找到了一个简单的解决方案。这是我为它写的一个快速函数。 (您将需要 Texture2D 类。)

- (void) drawText:(NSString*)theString AtX:(float)X Y:(float)Y {
// Use black
glColor4f(0, 0, 0, 1.0);

// Set up texture
Texture2D* statusTexture = [[Texture2D alloc] initWithString:theString dimensions:CGSizeMake(150, 150) alignment:UITextAlignmentLeft fontName:@"Helvetica" fontSize:11];

// Bind texture
glBindTexture(GL_TEXTURE_2D, [statusTexture name]);

// Enable modes needed for drawing
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);

glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

// Draw
[statusTexture drawInRect:CGRectMake(X,Y-1,1,1)];   

// Disable modes so they don't interfere with other parts of the program
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);    
}

我相信输入坐标需要在您的世界坐标中,但我不确定这是否普遍适用,或者它是否适合我。您可能需要使用偏移量才能使其正确。

【讨论】:

  • 一个带有 statusTexture 的内存泄漏?
  • Tony Tonev 的解决方案对我有用。我从达斯汀的链接中获得了 texture2D。非常干净的解决方案。如果需要,以后可以轻松添加缓存。
【解决方案4】:

感谢您提供的方法。它为我节省了一些时间。

不过,有几件事我必须改变。 glBlendFunc 调用必须是:

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_ALPHA)

其次,文本似乎被绘制成一个点。 CGRectMake 调用正在创建一个 1x1 矩形,除非我读错了。

【讨论】:

    【解决方案5】:

    使用“musings”字体库:

    http://www.themusingsofalostprogrammer.com/2010/01/how-to-do-font-rendering-in-opengl-on.html

    Font font("Verdena");
    font.print("Hello World!", x, y, z);
    

    简单:)

    它支持 unicode,“按需”加载字形,甚至可以输出变量

    font.print(x, y, z) << "fps: " << fps;
    

    【讨论】:

    • 这个库将每个角色加载为一个单独的纹理,如果你正在做任何适当大小的绘图,这将非常慢。正如其他一些答案所建议的那样,使用纹理图集要好得多
    • 遗憾的是这是在 OpenGL ES 1(不是 2)中,并且下载链接不再起作用..
    【解决方案6】:

    我创建了一个类似于“musings”字体库的 Font 类,减去了内存泄漏和为每个字符、每一帧创建的纹理。不过,它仍然为每个字符使用不同的 glTexture。注意:Texture2D 已更改以注释掉其纹理删除。

    在构造函数中初始化: _font = new Font("Helvetica", 40);

    在 redraw() 方法中使用: _font-&gt;draw("Hello, World!", 50, 100, ALIGN_LEFT);

    GitHub 链接:

    https://github.com/chandl34/public/tree/master/personal/c%2B%2B/Font

    【讨论】:

    • 你知道是否有 OpenGLES 2.0 的等价物吗?提前致谢
    【解决方案7】:

    查看坠机着陆演示。提供的 Texture2D 类允许使用文本和字体创建纹理。 (希望会有更好的答案,我会喜欢一种更简单的方式来绘制 opengles 视图)

    【讨论】:

    • 我认为这不是我想要的。我相信这会为整个字符串动态创建纹理,这是一个 CPU 密集型操作。寻找更多从单个四边形构造单词的方法,以便我可以在运行时呈现任意文本。这应该快得多。
    • 为什么你认为你提出的方法会更快?
    • 你不能在没有纹理的情况下绘制视图——它运行的速度不够快
    【解决方案8】:

    是的,我知道有 2 个。诀窍是,您必须使用 Quartz(CGContext* 函数)渲染到纹理,然后渲染该纹理以供用户查看。

    如果您关心性能,也可以使用 Quartz 生成纹理图集。

    创建一个纹理生成工具(在 xCode 中)once you know the basics of rendering a font 相当容易。

    您所要做的就是拥有一个有效的 CGContext。您可以在 texture loader 中找到一些非常棒的示例代码。

    基本上代码如下:

    // Create the cgcontext as shown by links above
    
    // Now to render text into the cg context,
    // the drop the raw data behind the cgcontext
    // to opengl.  2 ways to do this:
    // 1)  CG* way: (advantage: easy to use color)
    CGContextSelectFont(cgContext, "Arial", 24, kCGEncodingMacRoman);
    
    // set color to yellow text
    CGContextSetRGBFillColor(cgContext, 1, 1, 0, 1) ; // Be sure to use FILL not stroke!
    
    // draw it in there
    CGContextShowTextAtPoint(cgContext, 20, 20, "HI THERE", strlen("HI THERE") ) ;
    
    /*
    // WAY #2:  this way it's always black and white
    // DRAW SOME TEXT IN IT
    // that works ok but let's try cg to control color
    UIGraphicsPushContext(cgContext);
    UIFont *helv = [UIFont fontWithName:@"Helvetica" size:[UIFont systemFontSize]];
    NSString* msg = @"Hi hello" ;  
    [msg drawInRect:CGRectMake(0,0,pow2Width,pow2Height) withFont:helv] ;
        UIGraphicsPopContext();
    */
    
    // put imData into OpenGL's memory
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pow2Width, pow2Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imData);
    CHECK_GL ;
    

    它看起来非常好并且抗锯齿,

    ios 字体列表是available here,和prerenders here

    【讨论】:

      猜你喜欢
      • 2012-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多