iOS GLKit and back to default framebuffer

2019-04-13 19:16发布

问题:

I am running the boiler plate OpenGL example code that XCode creates for an OpenGL project for iOS. This sets up a simple ViewController and uses GLKit to handle the rest of the work.

All the update/draw functionality of the application is in C++. It is cross platform.

There is a lot of framebuffer creation going on. The draw phase renders to a few frame buffers and then tries to set it back to the default framebuffer.

glBindFramebuffer(GL_FRAMEBUFFER, 0);

This generates an GL_INVALID_ENUM. Only on iOS.

I am completely stumped as to why. The code runs fine on all major platforms except iOS. I'm wanting to blame GLKit. Any examples of iOS OpenGL setup that do not use GLKit?

UPDATE

The following snippet of code lets me see the default framebuffer that GLKit is using. For some reason it comes out as "2". Sure enough if I use "2" in all my glBindFrameBuffer calls it works. This is very frustrating.

[view bindDrawable ];

GLint defaultFBO;
glGetIntegerv(GL_FRAMEBUFFER_BINDING_OES, &defaultFBO);
LOGI("DEFAULT FBO: %d", defaultFBO);  

What reason on earth would cause GLKit to not generate its internal framebuffer at 0? This is the semantic all other implementations of OpenGL use, 0 is the default FBO.

回答1:

On iOS there is no default framebuffer. See Framebuffer Objects are the Only Rendering Target on iOS. I don't know much about GLKit, but on iOS to render something on screen you need to create framebuffer, and attach to it renderbuffer, and inform Core Animation Layer that this renderbuffer will be the "screen" or "default framebuffer" to draw to. Meaning - everything you'll draw to this framebuffer, will appear on screen. See Rendering to a Core Animation Layer.



回答2:

I feel it's necessary to point out here that the call to glBindFramebuffer(GL_FRAMEBUFFER, 0); does not return rendering to the main framebuffer although it would appear to work for machines that run Windows, Unix(Mac) or Linux. Desktops and laptops have no concept of a main default system buffer. This idea started with handheld devices. When you make an openGL bind call with zero as the parameter then what you are doing is setting this function to NULL. It's how you disable this function. It's the same with glBindTexture(GL_TEXTURE_2D, 0); It is possible that on some handheld devices that the driver automatically activates the main system framebuffer when you set the framebuffer to NULL without activating another. This would be a choice made by the manufacturer and is not something that you should count on, this is not part of the openGL ES spec. For desktops and laptops, this is absolutely necessary since disabling the framebuffer is required to return to normal openGL rendering.

On an iOS device, you should make the following call, glBindFramebuffer(GL_FRAMEBUFFER, viewFramebuffer);, providing that you named your system framebuffer 'viewFramebuffer'. Look for through your initialization code for the following call, glGenFramebuffers(1, &viewFramebuffer); Whatever you have written at the end there is what you bind to when returning to your main system buffer.

If you are using GLKit then you can use the following call, [((GLKView *) self.view) bindDrawable]; The 'self.view' may be slightly different depending on your particular startup code.
Also, for iOS, you could use, glBindFramebuffer(GL_FRAMEBUFFER, 2); but this is likely not going to be consistent across future devices released by Apple. They may change the default value of '2' to be '3' or something else in the future so you'd want to use the actual name instead of an integer value.



回答3:

  • (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {

//your use secondary/offscreen frame buffer to store render result

    [self.shader drawOffscreenOnFBO];

//back to default frame buffer of GLKView

    [((GLKView *) self.view) bindDrawable];

//draw on main screen [self.shader drawinmainscreen];

}

refernece .....http://districtf13.blogspot.com/