我已经实现了一个程序来将UILabel渲染到纹理,然后将相同的纹理映射到OpenGL中的四边形。然后,我通常通过将其添加到UIView层次结构来呈现相同的UILabel,以便在视觉上对它们进行比较。
我立即注意到我渲染到纹理的UILabel的质量低于正常渲染的UILabel。我无法弄清楚质量降低的原因,并希望得到任何建议。
我使用了Render contents of UIView as an OpenGL texture
中的渲染到纹理技术以下是一些相关代码
// setup test UIView (label for now) to be rendered to texture
_testLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 50)];
[_testLabel setText:@"yo"];
_testLabel.textAlignment = NSTextAlignmentCenter;
[_testLabel setBackgroundColor:RGB(0, 255, 0)];
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
_testLabelContext = CGBitmapContextCreate(NULL, _testLabel.bounds.size.width, _testLabel.bounds.size.height, 8, 4*_testLabel.bounds.size.width, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);
// setup texture handle for view to be rendered to texture
glGenTextures(1, &_testLabelTextureHandle);
glBindTexture(GL_TEXTURE_2D, _testLabelTextureHandle);
// these must be defined for non mipmapped nPOT textures (double check)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _testLabel.bounds.size.width, _testLabel.bounds.size.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
然后在我的渲染功能......
GLubyte *labelPixelData = (GLubyte*)CGBitmapContextGetData(_testLabelContext);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, _testLabel.bounds.size.width, _testLabel.bounds.size.height, GL_RGBA, GL_UNSIGNED_BYTE, labelPixelData);
答案 0 :(得分:1)
你不需要将渲染宽度和高度乘以@ 2x / @ 3x吗? OpenGL以真实像素工作。
答案 1 :(得分:1)
@soprof的答案是正确的。在创建视图屏幕截图时,您需要在每种情况下使用主屏幕边界缩放内容。将数据上传到纹理时,需要稍后使用相同的坐标。仅仅创建一个更大的上下文是不够的。
这实际上适用于openGL
和UIView
之间的所有连接。您需要了解坐标系保持使用1x,这对于视图布局非常有用。 Apple使用contentScaleFactor
上的UIView
属性来实际扩展内部内容,但在frame
或bounds
属性中仍然无法显示。因此,例如,要从UIView
获取图像,您需要执行以下操作:
+ (UIImage *)imageFromView:(UIView *)view
{
CGRect rect = [view bounds];
UIGraphicsBeginImageContextWithOptions(rect.size, NO, view.contentScaleFactor);
CGContextRef context = UIGraphicsGetCurrentContext();
[view.layer renderInContext:context];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
请参阅可以使用选项创建的上下文,并使用视图比例。但问题并不止于此。将视图添加到视图层次结构时,将设置实际内容比例因子。这意味着简单地初始化标签不足以使比例因子正确(默认情况下为1.0f
)。因此,您可以在视图上手动将比例设置为您想要的,您可以使用[UIScreen mainScreen].scale
从屏幕指定比例,在创建上下文或其间的任何内容时直接插入此值。
无论如何,如果你修改你的代码以包含比例,你将需要新的框架,总是
rect.size.width *= view.contentScaleFactor;
rect.size.height *= view.contentScaleFactor;
您需要对所有连续代码使用此类rect,但不要更改您尝试绘制的视图的框架,因为字体不会使用它进行缩放。可能有用的是在实际的输入视图中应用缩放变换矩阵(如果我没记错的话,帧也会缩放,所以即使你的代码应该自然地工作)。
正如我所提到的,这涉及到所有连接,因此如果您要从图层创建渲染缓冲区,则还需要使用其中的比例。 renderbufferStorage:GL_RENDERBUFFER fromDrawable:
将采用UIView
图层,但您必须使用layer.contentsScale = [UIScreen mainScreen].scale
将比例显式设置为图层,以获得正确的渲染缓冲区大小。因此,如果你正在使用它而你没有设置比例,整个场景将具有1倍的质量,甚至修复标签纹理也不会产生足够高的质量。