关于objective C:渲染到纹理,然后在iOS中渲染纹理到屏幕

Render to texture, then render texture to screen in iOS

我正在尝试将一个简单的场景渲染到一个 FBO 中,该 FBO 由作为颜色附件的纹理支持,然后在 iOS 中使用此纹理在屏幕上绘制一个四边形。
这将帮助我对最终场景进行一些后期处理。 SO上有一些问题可以解决类似(但不完全相同)的问题,我已经尝试了我能理解的任何东西。没有任何效果。

我有两个着色器程序。第一个 _program 简单地获取顶点位置并用单一颜色渲染它们。第二个 quadProgram 采用纹理、纹理坐标和四边形坐标。 (为了简洁起见,我省略了这些着色器的代码。)

两个着色器都能正常工作。他们独立地产生正确的结果。但是,当我尝试将"渲染纹理"渲染到四边形而不是使用样本木材纹理时,我只是得到一个黑屏。这是相关的代码位。我像这样设置一切:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
- (void)setupGL
{
    [EAGLContext setCurrentContext:self.context];

    _program = [self createProgramWithVertexShader:@"Shader" fragShader:@"Shader"];
    GLuint GLKVertexAttribPosition = glGetAttribLocation(_program,"position");

    quadProgram = [self createProgramWithVertexShader:@"PostShader" fragShader:@"PostShader"];
    quadTexCoord = glGetAttribLocation(quadProgram,"a_texcoord");
    quadPosition = glGetAttribLocation(quadProgram,"a_position");
    diffuseTexture = glGetUniformLocation(quadProgram,"s_diffuse");

    glEnable(GL_DEPTH_TEST);

    glGenVertexArraysOES(1, &_vertexArray);
    glBindVertexArrayOES(_vertexArray);

    glGenBuffers(1, &_vertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(gCubeVertexData), gCubeVertexData, GL_STATIC_DRAW);

    glEnableVertexAttribArray(GLKVertexAttribPosition);
    glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(0));

    glBindVertexArrayOES(0);

    // ============
    // ---- for render to texture
    width = self.view.bounds.size.width;
    height = self.view.bounds.size.height;

    // create fbo
    glGenFramebuffers(1, &framebuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);

    // create and attach backing texture
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,  width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);

    // create and attach depthbuffer
    glGenRenderbuffers(1, &depthRenderbuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer);

    // Check if framebuffer was loaded correctly
    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER) ;
    if(status != GL_FRAMEBUFFER_COMPLETE) {
        NSLog(@"failed to make complete framebuffer object %x", status);
    }

    // sample texture
    NSError *theError;

    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"wood_floor_256" ofType:@"jpg"]; // 1

    spriteTexture = [GLKTextureLoader textureWithContentsOfFile:filePath options:nil error:&theError]; // 2
}

然后是我的主循环:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
- (void)update
{
    // First save the default frame buffer.
    static GLint default_frame_buffer = 0;
    glGetIntegerv(GL_FRAMEBUFFER_BINDING, &default_frame_buffer);

    // render to texture
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
    glClearColor(0.65f, 0.65f, 0.65f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glBindVertexArrayOES(_vertexArray);

    glUseProgram(_program);

    glDrawArrays(GL_TRIANGLES, 0, 36);

    // render to screen
    glBindFramebuffer(GL_FRAMEBUFFER, default_frame_buffer);
    glClearColor(0.65f, 0.65f, 0.65f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glUseProgram(quadProgram);

    const float quadPositions[] = {  1.0,  1.0, 0.0,
        -1.0,  1.0, 0.0,
        -1.0, -1.0, 0.0,
        -1.0, -1.0, 0.0,
        1.0, -1.0, 0.0,
        1.0,  1.0, 0.0 };
    const float quadTexcoords[] = { 1.0, 1.0,
        0.0, 1.0,
        0.0, 0.0,
        0.0, 0.0,
        1.0, 0.0,
        1.0, 1.0 };

    // stop using VBO and other bufs.
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    glBindVertexArrayOES(0);

    glBindTexture(GL_TEXTURE_2D, texture);
    glActiveTexture(GL_TEXTURE_2D);

    // setup buffer offsets
    glVertexAttribPointer(quadPosition, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), quadPositions);
    glVertexAttribPointer(quadTexCoord, 2, GL_FLOAT, GL_FALSE, 2*sizeof(float), quadTexcoords);

    // ensure the proper arrays are enabled
    glEnableVertexAttribArray(quadPosition);
    glEnableVertexAttribArray(quadTexCoord);

    // draw
    glDrawArrays(GL_TRIANGLES, 0, 2*3);
}

我什至不知道如何判断支持 texture 是否包含渲染的屏幕。

渲染到纹理部分应该渲染到 FBO 中:
iPad render

如果我替换这两行:

1
2
    glBindTexture(GL_TEXTURE_2D, texture);
    glActiveTexture(GL_TEXTURE_2D);

1
2
glBindTexture(spriteTexture.target, spriteTexture.name);
glEnable(spriteTexture.target);

我得到以下信息:

ipadwood

这表明使用纹理将四边形渲染到屏幕的代码是正确的。

我不知道如何将第一个屏幕渲染到四边形。


由于你使用的纹理不是,它需要一个非默认的包裹参数。

在另一个 glTexParameteri 调用下方添加以下内容。它应该可以解决问题:

1
2
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);