使用framebuffer向纹理发出绘图(纹理空白)

时间:2016-04-10 02:39:22

标签: c++ opengl glsl sdl-2 glew

我会先说这是我对这些话题的新手,并且在过去几天为学校项目提供了速成课程。我很抱歉这很长,但由于我不确定问题出在哪里,我想我会尽量彻底。

我正在尝试使用帧缓冲区来绘制一些RGBA纹理,这些纹理稍后用于其他绘图(我使用纹理中的值作为矢量来绘制粒子 - 纹理存储值,例如它们的位置和速度)。

然而,正如我所知,我绘制后的纹理是空白的。纹理中的采样值返回(0,0,0,1)。这似乎也可以通过我后来的绘图程序得到证实,因为它出现所有粒子都在原点被重叠绘制(这个观察基于我的混合函数和一些硬编码的测试颜色值)

我正在使用带有SDL2的OpenGL 4和glew。

我会尝试以有序的方式发布所有相关内容:

framebuffer类创建framebuffer并附加(3)纹理。 它有:

GLuint buffer_id_这是帧缓冲区的id,初始化为0,unsigned int width, height,它是纹理的宽度和高度,以像素为单位numTextures,这是要为其创建的纹理数量帧缓冲区(在本例中为3),以及与帧缓冲区关联的所有纹理的std::vector<GLuint> textures_

bool Framebuffer::init() {
    assert( numTextures <= GL_MAX_COLOR_ATTACHMENTS );
    // Get the buffer id.
    glGenFramebuffers( 1, &buffer_id_ );
    glBindFramebuffer( GL_FRAMEBUFFER, buffer_id_ );
    // Generate the textures.
    for (unsigned int i = 0; i < numTextures; ++i) {
        GLuint tex;
        glGenTextures( 1, &tex );
        glBindTexture(GL_TEXTURE_2D, tex);
        // Give empty image to OpenGL.
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_FLOAT, 0);
        // Use GL_NEAREST, since we don't want any kind of averaging across values:
        // we just want one pixel to represent a particle's data.
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        // This probably isn't necessary, but we don't want to have UV coords past the image edges.
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        textures_.push_back(tex);
    }
    glBindTexture(GL_TEXTURE_2D, 0);
    // Bind our textures to the framebuffer.
    GLenum drawBuffers[GL_MAX_COLOR_ATTACHMENTS];
    for (unsigned int i = 0; i < numTextures; ++i) {
        GLenum attach = GL_COLOR_ATTACHMENT0 + i;
        glFramebufferTexture(GL_FRAMEBUFFER, attach, textures_[i], 0);
        drawBuffers[i] = attach;
    }
    glDrawBuffers( numTextures, drawBuffers );

    if ( glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE ) {
        std::cerr << "Error: Failed to create framebuffer." << std::endl;
        return false;
    }
    glBindFramebuffer( GL_FRAMEBUFFER, 0 );
    return true;
}

两个匹配的帧缓冲区由粒子系统构成,因此一个可以用作着色器程序的输入,另一个可以用作输出。

bool AmbientParticleSystem::initFramebuffers() {
    framebuffers_[0] = new Framebuffer(particle_texture_width_, particle_texture_height_, NUM_TEXTURES_PER_FRAMEBUFFER);
    framebuffers_[1] = new Framebuffer(particle_texture_width_, particle_texture_height_, NUM_TEXTURES_PER_FRAMEBUFFER);

    return framebuffers_[0]->init() && framebuffers_[1]->init();
}

然后我尝试将初始状态绘制到第一个帧缓冲区:

void AmbientParticleSystem::initParticleDrawing() {
    glBindFramebuffer( GL_FRAMEBUFFER, framebuffers_[0]->getBufferID() );
    // Store the previous viewport.
    GLint prevViewport[4];
    glGetIntegerv( GL_VIEWPORT, prevViewport );
    glViewport( 0, 0, particle_texture_width_, particle_texture_height_ );
    glClear( GL_COLOR_BUFFER_BIT );
    glDisable( GL_DEPTH_TEST );
    glBlendFunc( GL_ONE, GL_ZERO);

    init_shader_->use(); // This sets glUseProgram to the init shader.
    GLint attrib = init_variable_ids_[constants::init::Variables::IN_VERTEX_POS]->id;
    glEnableVertexAttribArray( attrib );
    glBindBuffer( GL_ARRAY_BUFFER, full_size_quad_->getBufferID() );
    glVertexAttribPointer( attrib, full_size_quad_->vertexSize,
                GL_FLOAT,   // type
                GL_FALSE,   // normalized?
                0,          // stride
                (void*)0 ); // Array buffer offset
    glDrawArrays( GL_TRIANGLES, 0, full_size_quad_->numVertices );

// Here I'm just printing some sample values to confirm it is blank/black.
    glBindTexture( GL_TEXTURE_2D, framebuffers_[0]->getTexture(0) );
    GLfloat *pixels = new GLfloat[particle_texture_width_ * particle_texture_height_ * 4];
    glGetTexImage( GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, pixels);

    std::cout << "some pixel entries:\n";
    std::cout << "pixel0:     " << pixels[0] << "  " << pixels[1] << "  " << pixels[2] << "  " << pixels[3] << std::endl;
    std::cout << "pixel10:    " << pixels[40] << "  " << pixels[41] << "  " << pixels[42] << "  " << pixels[43] << std::endl;
    std::cout << "pixel100:   " << pixels[400] << "  " << pixels[401] << "  " << pixels[402] << "  " << pixels[403] << std::endl;
    std::cout << "pixel10000: " << pixels[40000] << "  " << pixels[40001] << "  " << pixels[40002] << "  " << pixels[40003] << std::endl;
// They all print 0, 0, 0, 1
    delete pixels;

    glBindBuffer( GL_ARRAY_BUFFER, 0 );
    glDisableVertexAttribArray( attrib );
    init_shader_->stopUsing();
    glBindFramebuffer( GL_FRAMEBUFFER, 0 );
    // Return the viewport to its previous state.
    glViewport(prevViewport[0], prevViewport[1], prevViewport[2], prevViewport[3] );
}

你可以看到这里也是我尝试获取一些像素值的地方,它们都返回(0,0,0,1)。

此处使用的full_size_quad_由以下内容定义:

// Create quad for textures to draw onto.
static const GLfloat quad_array[] = {
    -1.0f,  -1.0f,  0.0f,   
     1.0f,   1.0f,  0.0f,
    -1.0f,   1.0f,  0.0f,
    -1.0f,  -1.0f,  0.0f,
     1.0f,  -1.0f,  0.0f,
     1.0f,   1.0f,  0.0f,
};
std::vector<GLfloat> quad(quad_array, quad_array + 18);
full_size_quad_ = new VertexBuffer(3, 6, quad);

VertexBuffer是我自己的类,我不会认为我需要在这里展示。它只是glGens和glBinds顶点数组和缓冲区。

此处使用的着色器对顶点着色器具有此功能:

#version 400 core

in vec3 inVertexPos;

void main() {
    gl_Position = vec4(inVertexPos, 1.0);
}

和片段着色器:

#version 400 core

layout(location = 0) out vec4 position;
layout(location = 1) out vec4 velocity;
layout(location = 2) out vec4 other;

uniform vec2 uResolution;

// http://stackoverflow.com/questions/4200224/random-noise-functions-for-glsl
float rand(vec2 seed) {
  return fract(sin(dot(seed.xy,vec2(12.9898,78.233))) * 43758.5453);
}

void main() {
  vec2 uv = gl_FragCoord.xy/uResolution.xy;

  vec3 pos = vec3(uv.x, uv.y, rand(uv));
  vec3 vel = vec3(-2.0, 0.0, 0.0);
  vec4 col = vec4(1.0, 0.3, 0.1, 0.5);

  position = vec4(pos, 1.0);
  velocity = vec4(vel, 1.0);
  other = col;
}

uResolution是纹理的宽度和高度,以像素为单位,设置为:

init_shader_->use();
glUniform2f( init_uniform_ids_[constants::init::Uniforms::U_RESOLUTION]->id, particle_texture_width_, particle_texture_height_ );

出于好奇,我尝试将position = vec4(pos, 1.0);更改为不同的值,但我的像素打印仍为0 0 0 1。

我现在已经调试了大约20到30个小时,在这里查了十几个不同的教程和其他问题,但过去几个小时我觉得我没有任何理由。

这里有什么东西可以解释为什么纹理看起来是空白/黑色,还是其他需要解决的东西?我正在使用这个项目来了解着色器,所以我对这一切都很陌生。任何帮助都会非常感激。

1 个答案:

答案 0 :(得分:0)

通过完全重写代码解决了这个问题。

我仍然不能100%确定问题出在哪里,但我想我可能会遇到一些不匹配的启用/禁用来电。