2016-02-12 77 views
0

我已經實現了一個程序,將UILabel渲染爲紋理,然後將相同的紋理映射到OpenGL中的四邊形。然後,我通常通過將它添加到UIView層次結構來直觀地呈現相同的UILabel。iOS UIView渲染紋理 - 保留質量

我立即注意到,我渲染到紋理的UILabel的質量低於通常呈現的UILabel。我無法弄清楚爲什麼質量較低,並會感謝任何建議。

我使用的紋理渲染技術,在這裏找到Render contents of UIView as an OpenGL texture

Screenshot of simple test case

下面是一些相關的代碼

// 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); 

回答

1

難道你不需要乘以撕裂呃寬度和高度由@ 2x/@ 3x? OpenGL以實像素工作。

+0

增加CGBitmapContext的尺寸以及傳遞給glTexImage2D的尺寸只會將相同的圖像渲染成更大的紋理。因此,例如增加3,將使相同的UILabel成爲比填充像素大3倍的紋理,因此您最終得到的紋理在左上角具有標籤,其餘紋理填充爲黑色。 – mbradber

1

@soprof的答案是正確的。在創建視圖截圖時,您確實需要在每種情況下使用主屏幕邊界來縮放內容。將數據上傳到紋理時,您需要稍後使用相同的座標。僅僅創造一個更大的背景是不夠的。

這實際上適用於openGLUIView之間的所有連接。您需要了解座標系保持爲1x,這對視圖佈局非常有用。 Apple在UIView上使用contentScaleFactor屬性來實際縮放內部內容,但在framebounds屬性中仍然不可見。因此,例如從一個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; 

您需要使用這種矩形的所有繼續碼,但不改變幀的新框架您正在嘗試繪製的視圖因爲字體不會與其縮放。儘管在實際的輸入視圖上應用一個縮放變換矩陣(如果我沒有記錯的話,框架也會縮放,所以即使你的代碼應該自然地工作)也可能工作。

正如我所提到的,這涉及到所有連接,所以如果您要從圖層創建渲染緩衝區,您還需要使用其中的比例尺。 renderbufferStorage:GL_RENDERBUFFER fromDrawable:將採用UIView圖層,但您必須明確地將比例設置爲該圖層,以使用layer.contentsScale = [UIScreen mainScreen].scale獲得渲染緩衝區的正確大小。所以,如果你使用這個,你沒有設置規模,整個場景將具有1倍的質量,甚至固定標籤紋理不會產生足夠高的質量。