iOS OpenGL:为什么缩放我的视网膜渲染缓冲区会缩小我的图像,我该如何解决?
iOS OpenGL: Why has scaling my renderbuffer for retina shrunk my image, and how do I fix it?
我正在使用 Retina iPad 进行增强现实项目,但两层 - 相机源和 OpenGL 覆盖层 - 没有使用高分辨率屏幕。相机源被绘制到一个纹理,该纹理似乎正在缩放和采样,其中叠加使用块状 4 像素放大:
我查看了一堆问题并将以下行添加到我的 EAGLView class。
到initWithCoder,在调用setupFrameBuffer和setupRenderBuffer之前:
self.contentScaleFactor = [[UIScreen mainScreen] scale];
并在 setupFrameBuffer 中
float screenScale = [[UIScreen mainScreen] scale];
float width = self.frame.size.width;
float height = self.frame.size.height;
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width * screenScale, height * screenScale);
...
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width*screenScale, height*screenScale, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
最后两行只是修改为包含比例因子。
运行 这段代码给出了以下结果:
如您所见,图片现在只填满了屏幕的左下四分之一,但我可以确认图片只是缩放了,没有被裁剪。谁能帮我弄清楚这是为什么?
它实际上并没有被缩放,而是您实际上是将帧绘制到您在允许渲染缓冲区在两个方向上都是 2 倍大小之前定义的定义大小。
最有可能发生的事情是您根据像素而不是更通用的 OpenGL 坐标 space 定义尺寸,它在 x 和 y 方向上从 -1 移动到 1(这确实是当你在 2D 中工作时,就像你一样)。
此外,呼叫:
float width = self.frame.size.width;
float height = self.frame.size.height;
将 return 不是视网膜尺寸的尺寸。如果你 NSLog 那些,你会看到即使在基于视网膜的设备上,那些 return 值基于非基于视网膜的屏幕,或者更一般地说是运动单位,而不是像素。
我选择获取视图实际大小(以像素为单位)的方式是:
GLint myWidth = 0;
GLint myHeight = 0;
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &myWidth);
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &myHeight);
在 iOS 中,我一直使用以下代码作为我的设置:
-(void)setupView:(GLView*)theView{
const GLfloat zNear = 0.00, zFar = 1000.0, fieldOfView = 45.0;
GLfloat size;
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
size = zNear * tanf(DEGREES_TO_RADIANS(fieldOfView) / 2.0);
//CGRect rect = theView.bounds;
GLint width, height;
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &width);
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &height);
// NSLog(@"setupView rect width = %d, height = %d", width, height);
glFrustumf(-size, size, -size / ((float)width / (float)height), size /
((float)width / (float)height), zNear, zFar);
glViewport(0, 0, width, height);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
上面的例程在我正在测试视网膜和非视网膜设置的代码中使用,并且工作正常。此 setupView 例程在 viewController.
中是可重写的
这是我找到的解决方案。
我发现在我的绘图函数中我设置了基于 glview.bounds.size 的 glViewport 大小,它以点而不是像素为单位。将其切换为基于 framebufferWidth 和 framebufferHeight 的设置解决了这个问题。
glViewport(0, 0, m_glview.framebufferWidth, m_glview.framebufferHeight);
我正在使用 Retina iPad 进行增强现实项目,但两层 - 相机源和 OpenGL 覆盖层 - 没有使用高分辨率屏幕。相机源被绘制到一个纹理,该纹理似乎正在缩放和采样,其中叠加使用块状 4 像素放大:
我查看了一堆问题并将以下行添加到我的 EAGLView class。
到initWithCoder,在调用setupFrameBuffer和setupRenderBuffer之前:
self.contentScaleFactor = [[UIScreen mainScreen] scale];
并在 setupFrameBuffer 中
float screenScale = [[UIScreen mainScreen] scale];
float width = self.frame.size.width;
float height = self.frame.size.height;
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width * screenScale, height * screenScale);
...
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width*screenScale, height*screenScale, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
最后两行只是修改为包含比例因子。
运行 这段代码给出了以下结果:
如您所见,图片现在只填满了屏幕的左下四分之一,但我可以确认图片只是缩放了,没有被裁剪。谁能帮我弄清楚这是为什么?
它实际上并没有被缩放,而是您实际上是将帧绘制到您在允许渲染缓冲区在两个方向上都是 2 倍大小之前定义的定义大小。
最有可能发生的事情是您根据像素而不是更通用的 OpenGL 坐标 space 定义尺寸,它在 x 和 y 方向上从 -1 移动到 1(这确实是当你在 2D 中工作时,就像你一样)。
此外,呼叫:
float width = self.frame.size.width;
float height = self.frame.size.height;
将 return 不是视网膜尺寸的尺寸。如果你 NSLog 那些,你会看到即使在基于视网膜的设备上,那些 return 值基于非基于视网膜的屏幕,或者更一般地说是运动单位,而不是像素。
我选择获取视图实际大小(以像素为单位)的方式是:
GLint myWidth = 0;
GLint myHeight = 0;
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &myWidth);
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &myHeight);
在 iOS 中,我一直使用以下代码作为我的设置:
-(void)setupView:(GLView*)theView{
const GLfloat zNear = 0.00, zFar = 1000.0, fieldOfView = 45.0;
GLfloat size;
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
size = zNear * tanf(DEGREES_TO_RADIANS(fieldOfView) / 2.0);
//CGRect rect = theView.bounds;
GLint width, height;
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &width);
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &height);
// NSLog(@"setupView rect width = %d, height = %d", width, height);
glFrustumf(-size, size, -size / ((float)width / (float)height), size /
((float)width / (float)height), zNear, zFar);
glViewport(0, 0, width, height);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
上面的例程在我正在测试视网膜和非视网膜设置的代码中使用,并且工作正常。此 setupView 例程在 viewController.
中是可重写的这是我找到的解决方案。
我发现在我的绘图函数中我设置了基于 glview.bounds.size 的 glViewport 大小,它以点而不是像素为单位。将其切换为基于 framebufferWidth 和 framebufferHeight 的设置解决了这个问题。
glViewport(0, 0, m_glview.framebufferWidth, m_glview.framebufferHeight);