Rendering Static and Dynamic Graphics OpenGL

2019-04-16 00:11发布

问题:

I am working on an IOS game using the OpenGL pipeline. I have been able to render the graphics I want to the screen, however, I am calling glDrawElements too many times and have some concerns about running into performance issues eventually. I have several static elements in my game that do not need to be render on every render cycle. Is there a way I can render static elements to one frame buffer and dynamic elements to another?

Here's the code I have tried:

static BOOL renderThisFrameBuffer = YES;
    if (renderThisFrameBuffer) {
        glBindFramebuffer(GL_FRAMEBUFFER, interFrameBuffer);
        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glEnable(GL_BLEND);
        glEnable(GL_DEPTH_TEST);

        // Set up projection matrix
        CC3GLMatrix *projection = [CC3GLMatrix matrix];
        float h = 4.0f * OpenGLView.frame.size.height / OpenGLView.frame.size.width;
        [projection populateFromFrustumLeft:-2 andRight:2 andBottom:-h/2 andTop:h/2 andNear:4 andFar:50];
        glUniformMatrix4fv(projectionUniform, 1, 0, projection.glMatrix);

        glViewport(0, 0, OpenGLView.frame.size.width, OpenGLView.frame.size.height);

        for (BoardSpace *boardSpace in spaceArray){
            [boardSpace drawWithMatrix:modelView];
        }

        [context presentRenderbuffer:GL_RENDERBUFFER];
        glBindFramebuffer(GL_FRAMEBUFFER, constFrameBuffer);
        renderThisFrameBuffer = false;
    }

In this case I have created two frame buffers previously: interFrameBuffer for static elements and constFrameBuffer for dynamic elements. Am I missing something?

回答1:

It should be possible. The most straightforward approach is that you render your static elements to an FBO once. Then on each redraw, copy the content of the static FBO to your default framebuffer, and then draw the dynamic elements on top of it.

The feature set of ES 2.0 is kind of borderline to support this. For example, you don't have glBlitFramebuffer(), which would be a convenient way to copy the FBO content to the default framebuffer. But you can do the copy with a simple shader program that feeds through the coordinates in the vertex shader, and only uses a texture sample operation in the fragment shader. Then bind the texture you rendered the static content to, and draw a screen sized quad.

It gets more tricky if your dynamic rendering needs the depth buffer from the static rendering. That would for example be the case if dynamic content is obscured by static content. In that case, you would also need to copy the depth buffer. From quickly refreshing my memory of the specs, I don't see anything that would make this possible in ES 2.0. glBlitFramebuffer() is not there. And it looks like ES 2.0 does not support depth textures. You're entering ES 3.0 territory if you want to go there.

With all of this, you obviously want to make sure that it really helps your performance. Copying the framebuffer is not free. It only pays off if it's cheaper than rendering your static elements. Benchmarking of both approaches is definitely in order before you make a decision.