glReadPixels returns null 多重采样
glReadPixels returns null with multi-sampling
我遇到了与 this one 相同的问题,但是根据这些提示,我仍然无法从 glReadPixels 获取数据。
我粘贴我的源代码,我的代码和之前的几乎一样one.And我在快照前设置了GL_READ_FRAMEBUFFER_APPLE
,但是数据returns null。
创建我的帧缓冲区
- (void)createFrameBuffer {
glGenRenderbuffers(1, &colorRenderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderBuffer);
[_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:_eaglLayer];
GLint backingWidth;
GLint backingHeight;
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &backingWidth);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &backingHeight);
glGenFramebuffers(1, &defaultFrameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, defaultFrameBuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,GL_RENDERBUFFER, colorRenderBuffer);
glGenFramebuffers(1, &sampleFramebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, sampleFramebuffer);
glGenRenderbuffers(1, &sampleColorRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, sampleColorRenderbuffer);
glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER, 4, GL_RGBA8_OES, backingWidth, backingHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, sampleColorRenderbuffer);
glGenRenderbuffers(1, &sampleDepthRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, sampleDepthRenderbuffer);
glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT16, backingWidth, backingHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, sampleDepthRenderbuffer);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE){
NSAssert(true, @"buffer is not complete");
NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER));
}
}
渲染函数
- (void)render {
FC_PERFORMANCE_START();
if ([EAGLContext currentContext] !=_context) {
[EAGLContext setCurrentContext:_context];
}
[self destoryFrameBuffer];
[self createFrameBuffer];
[self.director setup:self.frame.size contentScale:self.contentScaleFactor backgroudColor:self.backgroundColor];
[self.director mainloop];
glBindFramebuffer(GL_READ_FRAMEBUFFER_APPLE, sampleFramebuffer);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER_APPLE, defaultFrameBuffer);
glResolveMultisampleFramebufferAPPLE();
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderBuffer);
const GLenum discards[] = {GL_COLOR_ATTACHMENT0,GL_DEPTH_ATTACHMENT};
glDiscardFramebufferEXT(GL_READ_FRAMEBUFFER_APPLE,2,discards);
glBindFramebuffer(GL_FRAMEBUFFER, sampleFramebuffer);
[_context presentRenderbuffer:GL_RENDERBUFFER];
FC_PERFORMANCE_END("FCViewOpenGL Render");
}
屏幕截图功能
- (nullable UIImage*)snapShot{
__block UIImage *ret = nil;
dispatch_sync(dispatch_get_main_queue(), ^{
glBindFramebuffer(GL_READ_FRAMEBUFFER_APPLE, defaultFrameBuffer);
GLint backingWidth;
GLint backingHeight;
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &backingWidth);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &backingHeight);
NSInteger x = 0, y = 0, width2 = backingWidth, height2 = backingHeight;
NSInteger dataLength = width2 * height2 * 4;
GLubyte *data = (GLubyte*)malloc(dataLength * sizeof(GLubyte));
CHECK_GL_ERROR_DEBUG();
glReadPixels((GLint)x, (GLint)y, (GLsizei)width2, (GLsizei)height2, GL_RGBA, GL_UNSIGNED_BYTE, data);
GLenum attachments[] = {GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT };
glDiscardFramebufferEXT(GL_READ_FRAMEBUFFER_APPLE, 2, attachments);
CHECK_GL_ERROR_DEBUG();
CGDataProviderRef ref = CGDataProviderCreateWithData(NULL, data, dataLength, NULL);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGImageRef iref = CGImageCreate(width2, height2, 8, 32, width2 * 4, colorspace, kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast,
ref, NULL, true, kCGRenderingIntentDefault);
NSInteger widthInPoints, heightInPoints;
if (NULL != UIGraphicsBeginImageContextWithOptions) {
CGFloat scale = self.contentScaleFactor;
widthInPoints = width2 / scale;
heightInPoints = height2 / scale;
UIGraphicsBeginImageContextWithOptions(CGSizeMake(widthInPoints, heightInPoints), NO, scale);
}
else {
widthInPoints = width2;
heightInPoints = height2;
UIGraphicsBeginImageContext(CGSizeMake(widthInPoints, heightInPoints));
}
CGContextRef cgcontext = UIGraphicsGetCurrentContext();
CGContextSetBlendMode(cgcontext, kCGBlendModeCopy);
CGContextDrawImage(cgcontext, CGRectMake(0.0, 0.0, widthInPoints, heightInPoints), iref);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
free(data);
CFRelease(ref);
CFRelease(colorspace);
CGImageRelease(iref);
ret = image;
});
return ret;
}
谁能帮我一下?
见OpenGL ES 3.2 Specification; 16.1.2 ReadPixels; page 406
An INVALID_OPERATION
error is generated if the value of READ_FRAMEBUFFER_BINDING
(see section 9) is non-zero, the read framebuffer is framebuffer complete, and the effective value of SAMPLE_BUFFERS
for the read framebuffer is one.
....
If the read framebuffer is multisampled (its effective value of SAMPLE_BUFFERS
is one) ...
另见 OpenGL-Refpages; OpenGL ES 3.0; glReadPixels
:
GL_INVALID_OPERATION
is generated if GL_READ_FRAMEBUFFER_BINDING
is non-zero, the read framebuffer is complete, and the value of GL_SAMPLE_BUFFERS
for the read framebuffer is greater than zero.
这意味着,您不能使用 glReadPixels
多采样帧缓冲区。您将获得 GL_INVALID_OPERATION
操作错误。在glReadPixels
之后使用glGetError
获取错误信息。
要解决这个问题,您必须绕过传统的帧缓冲区。执行以下步骤:
- 创建第二个帧缓冲区对象,这是常规的(非多重采样)。
- 绑定多采样帧缓冲区以供读取 (
GL_READ_FRAMEBUFFER_APPLE
)。
- 为绘图绑定传统的帧缓冲区(
GL_DRAW_FRAMEBUFFER_APPLE
)。
- 使用
glBlitFramebuffer
复制将像素从多重采样(读取)帧缓冲区复制到常规(绘制)帧缓冲区。
- 复制完成后绑定常规framebuffer读取(
GL_READ_FRAMEBUFFER_APPLE
)。
- 最后使用
glReadPixels
从常规帧缓冲区读取。
作为替代方案,您当然可以直接从默认帧缓冲区读取像素。
我遇到了与 this one 相同的问题,但是根据这些提示,我仍然无法从 glReadPixels 获取数据。
我粘贴我的源代码,我的代码和之前的几乎一样one.And我在快照前设置了GL_READ_FRAMEBUFFER_APPLE
,但是数据returns null。
创建我的帧缓冲区
- (void)createFrameBuffer {
glGenRenderbuffers(1, &colorRenderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderBuffer);
[_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:_eaglLayer];
GLint backingWidth;
GLint backingHeight;
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &backingWidth);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &backingHeight);
glGenFramebuffers(1, &defaultFrameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, defaultFrameBuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,GL_RENDERBUFFER, colorRenderBuffer);
glGenFramebuffers(1, &sampleFramebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, sampleFramebuffer);
glGenRenderbuffers(1, &sampleColorRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, sampleColorRenderbuffer);
glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER, 4, GL_RGBA8_OES, backingWidth, backingHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, sampleColorRenderbuffer);
glGenRenderbuffers(1, &sampleDepthRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, sampleDepthRenderbuffer);
glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT16, backingWidth, backingHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, sampleDepthRenderbuffer);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE){
NSAssert(true, @"buffer is not complete");
NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER));
}
}
渲染函数
- (void)render {
FC_PERFORMANCE_START();
if ([EAGLContext currentContext] !=_context) {
[EAGLContext setCurrentContext:_context];
}
[self destoryFrameBuffer];
[self createFrameBuffer];
[self.director setup:self.frame.size contentScale:self.contentScaleFactor backgroudColor:self.backgroundColor];
[self.director mainloop];
glBindFramebuffer(GL_READ_FRAMEBUFFER_APPLE, sampleFramebuffer);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER_APPLE, defaultFrameBuffer);
glResolveMultisampleFramebufferAPPLE();
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderBuffer);
const GLenum discards[] = {GL_COLOR_ATTACHMENT0,GL_DEPTH_ATTACHMENT};
glDiscardFramebufferEXT(GL_READ_FRAMEBUFFER_APPLE,2,discards);
glBindFramebuffer(GL_FRAMEBUFFER, sampleFramebuffer);
[_context presentRenderbuffer:GL_RENDERBUFFER];
FC_PERFORMANCE_END("FCViewOpenGL Render");
}
屏幕截图功能
- (nullable UIImage*)snapShot{
__block UIImage *ret = nil;
dispatch_sync(dispatch_get_main_queue(), ^{
glBindFramebuffer(GL_READ_FRAMEBUFFER_APPLE, defaultFrameBuffer);
GLint backingWidth;
GLint backingHeight;
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &backingWidth);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &backingHeight);
NSInteger x = 0, y = 0, width2 = backingWidth, height2 = backingHeight;
NSInteger dataLength = width2 * height2 * 4;
GLubyte *data = (GLubyte*)malloc(dataLength * sizeof(GLubyte));
CHECK_GL_ERROR_DEBUG();
glReadPixels((GLint)x, (GLint)y, (GLsizei)width2, (GLsizei)height2, GL_RGBA, GL_UNSIGNED_BYTE, data);
GLenum attachments[] = {GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT };
glDiscardFramebufferEXT(GL_READ_FRAMEBUFFER_APPLE, 2, attachments);
CHECK_GL_ERROR_DEBUG();
CGDataProviderRef ref = CGDataProviderCreateWithData(NULL, data, dataLength, NULL);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGImageRef iref = CGImageCreate(width2, height2, 8, 32, width2 * 4, colorspace, kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast,
ref, NULL, true, kCGRenderingIntentDefault);
NSInteger widthInPoints, heightInPoints;
if (NULL != UIGraphicsBeginImageContextWithOptions) {
CGFloat scale = self.contentScaleFactor;
widthInPoints = width2 / scale;
heightInPoints = height2 / scale;
UIGraphicsBeginImageContextWithOptions(CGSizeMake(widthInPoints, heightInPoints), NO, scale);
}
else {
widthInPoints = width2;
heightInPoints = height2;
UIGraphicsBeginImageContext(CGSizeMake(widthInPoints, heightInPoints));
}
CGContextRef cgcontext = UIGraphicsGetCurrentContext();
CGContextSetBlendMode(cgcontext, kCGBlendModeCopy);
CGContextDrawImage(cgcontext, CGRectMake(0.0, 0.0, widthInPoints, heightInPoints), iref);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
free(data);
CFRelease(ref);
CFRelease(colorspace);
CGImageRelease(iref);
ret = image;
});
return ret;
}
谁能帮我一下?
见OpenGL ES 3.2 Specification; 16.1.2 ReadPixels; page 406
An
INVALID_OPERATION
error is generated if the value ofREAD_FRAMEBUFFER_BINDING
(see section 9) is non-zero, the read framebuffer is framebuffer complete, and the effective value ofSAMPLE_BUFFERS
for the read framebuffer is one.....
If the read framebuffer is multisampled (its effective value of
SAMPLE_BUFFERS
is one) ...
另见 OpenGL-Refpages; OpenGL ES 3.0; glReadPixels
:
GL_INVALID_OPERATION
is generated ifGL_READ_FRAMEBUFFER_BINDING
is non-zero, the read framebuffer is complete, and the value ofGL_SAMPLE_BUFFERS
for the read framebuffer is greater than zero.
这意味着,您不能使用 glReadPixels
多采样帧缓冲区。您将获得 GL_INVALID_OPERATION
操作错误。在glReadPixels
之后使用glGetError
获取错误信息。
要解决这个问题,您必须绕过传统的帧缓冲区。执行以下步骤:
- 创建第二个帧缓冲区对象,这是常规的(非多重采样)。
- 绑定多采样帧缓冲区以供读取 (
GL_READ_FRAMEBUFFER_APPLE
)。 - 为绘图绑定传统的帧缓冲区(
GL_DRAW_FRAMEBUFFER_APPLE
)。 - 使用
glBlitFramebuffer
复制将像素从多重采样(读取)帧缓冲区复制到常规(绘制)帧缓冲区。 - 复制完成后绑定常规framebuffer读取(
GL_READ_FRAMEBUFFER_APPLE
)。 - 最后使用
glReadPixels
从常规帧缓冲区读取。
作为替代方案,您当然可以直接从默认帧缓冲区读取像素。