24

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

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

那么是否有任何 Objective-C 包装的 OpenGL 文本库可以与人们一直在使用的 iPhone SDK 一起使用?还是我只是在想这个并且我缺少一种更简单的方法?

4

8 回答 8

22

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

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

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

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

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

于 2009-02-04T18:46:00.150 回答
8

您对使用 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

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

于 2009-02-04T17:21:32.240 回答
6

我找到了一个简单的解决方案。这是我为它写的一个快速函数。(您将需要 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);    
}

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

于 2009-03-24T05:58:00.303 回答
3

谢谢你的方法。它为我节省了一些时间。

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

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_ALPHA)

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

于 2009-03-28T08:16:47.877 回答
3

使用“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;
于 2010-01-20T21:11:31.833 回答
2

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

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

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

GitHub链接:

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

于 2012-12-10T02:46:16.973 回答
1

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

于 2009-02-04T17:04:29.840 回答
1

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

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

一旦您了解了渲染字体的基础知识,就很容易启动纹理生成工具(在 xCode 中)。

您所要做的就是拥有一个有效的 CGContext。你可以在这个纹理加载器中找到一些非常棒的示例代码。

基本上代码是:

// 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 字体列表,并在此处提供预渲染

于 2012-09-22T19:03:49.630 回答