5

我正在使用 OpenGL 在 Mac OS 中绘图。当我的代码在 Retina 显示屏上运行时,除文本绘图外,一切正常。在视网膜显示下,文本是应有的两倍大。这是因为字体大小以点为单位,每个点在 Retina 下是 2 个像素,但 OpenGL 是基于像素的。

以下是标准显示下的正确文字图:
在标准显示下正确绘制文本

这是 Retina 显示下的错误文本绘制:
Retina 显示下的文字绘制不正确

这是我通常如何绘制字符串。由于 OpenGL 没有文本绘制功能,为了绘制文本,我执行以下操作:

  1. 获取字体:

    NSFontManager fontManager = [NSFontManager sharedFontManager];
    NSString
    font_name = [NSString stringWithCString: "Helvetica" 编码: NSMacOSRomanStringEncoding];
    字体 = [fontManager fontWithFamily:字体名称特征:字体样式重量:5 大小:9];
    属性 = [[NSMutableDictionary dictionaryWithCapacity: 3] 保留];
    [属性 setObject:font forKey:NSFontAttributeName];

  2. 创建并测量字符串:

    NSString* aString = [NSString stringWithCString: "blah blah" encoding: NSMacOSRomanStringEncoding];
    NSSize frameSize = [aString sizeWithAttributes: m_attribs];

  3. 分配 NSImage 的大小:

    NSImage* image = [[NSImage alloc] initWithSize:frameSize];
    [图像锁定焦点];

  4. 将字符串绘制到图像中:

    [aString drawAtPoint:NSMakePoint (0, 0) withAttributes:m_attribs];

  5. 获取位:

    NSBitmapImageRep* 位图 = [[NSBitmapImageRep alloc] initWithFocusedViewRect:NSMakeRect (0.0f, 0.0f, frameSize.width, frameSize.height)];
    [图像解锁焦点];

  6. 创建 OpenGL 纹理:

    GLuint 纹理 = 0;
    glGenTextures(1, &texture);
    glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, GL_RGBA, GLsizei(frameSize.width), GLsizei(frameSize.height), 0, GL_RGBA, [位图 bitmapData]);

  7. 绘制纹理:

    glBindTexture ....
    其他OpenGL绘图代码

我的问题是如何让 NSString 以像素分辨率而不是以点为单位绘制。

我尝试了以下方法:

  1. 以点大小的一半绘制:4.5 而不是 9。这给了我正确的大小,但文本绘制模糊。
  2. 以点大小绘制并将纹理缩小到 OpenGL 中大小的一半,这同样不会产生好看的结果:
    纹理收缩
4

3 回答 3

1

OpenGLs 坐标系实际上是基于点的,而不是基于像素的,但你是决定这些点是什么的人。上下文通过 glOrtho 函数(或者您可以手动构建正交矩阵)定义 2D 坐标系,该函数设置屏幕上的最小和最大 x,y 坐标。例如,可以设置正交投影,使 0 位于屏幕左侧,而 100 位于右侧,无论您渲染到的帧缓冲区的大小如何。

字体纹理似乎创建得很好。问题是你在几何上渲染它是它需要的两倍大。在 OpenGL 中,纹理大小不会影响屏幕上呈现的对象的大小。屏幕上的大小由传递给glDrawArraysglBegin等的几何图形而不是纹理定义。

我认为问题在于您使用字体纹理的像素大小来定义用于在屏幕上渲染的四边形大小。这会将您的问题放在“其他 OpenGL 绘图代码”部分。要解决这个问题,您可以对绘图应用某种比例因子。在视网膜模式下,比例因子为 0.5,对于普通屏幕,它是 1.0(UIKit 使用类似的想法来渲染 UIView 内容)

四边形计算可能如下所示:

quad.width = texture.width * scaleFactor 
quad.height = texture.height * scaleFactor

另一种选择是将四边形渲染大小与纹理完全分开。如果您有一个用于绘制文本的函数或类,它可能有一个字体大小参数,它将用作实际的四边形大小,而不是使用纹理大小。

于 2012-10-10T14:14:04.257 回答
0

鉴于您有一个NSBitmapImageRep并从中获取像素栅格数据,您应该使用bitmap.pixelsWideand bitmap.pixelsHigh,而不是frameSize在从位图创建纹理时。

于 2017-12-14T02:20:27.603 回答
0

对于我的视网膜显示器,我遇到了帧缓冲区不适合实际窗口的问题(整个缓冲区被渲染到窗口的四分之一)。在这种情况下,使用双视口可以解决问题。

# Instead of actual window size width*height,
# double the dimensions for retina display 

glViewport(0, 0, width*2, height*2)

在您的情况下(这部分只是一个假设,因为我无法运行您的代码),更改您传递给 gl 以创建纹理的帧大小可以解决问题。

GLsizei(frameSize.width*2), GLsizei(frameSize.height*2)
于 2017-12-14T00:43:40.720 回答