繁体   English   中英

使用帧缓冲区将绘图发布到纹理(纹理空白)

[英]Issue drawing to textures with framebuffer (texture blank)

首先,我会说我是这些主题的新手,并在最近几天为学校项目开设了速成课程。 抱歉,这很长,但是由于我不确定问题出在哪里,因此我将尽力而为。

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

但是,据我所知,绘制后的纹理是空白的。 纹理中的采样值会返回(0,0,0,1)。 这似乎也被我以后的绘制程序所证实,因为似乎所有粒子都在原点重叠绘制(此观察结果基于我的混合函数和一些硬编码的测试颜色值)。

我正在将OpenGL 4与SDL2一起使用,并出现问题。

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

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个小时,并在这里查找了十几种不同的教程和其他问题,但是最近几个小时我觉得自己没有取得什么进展。

这里有什么能突出显示纹理为何为空白/黑色或其他需要解决的突出之处? 我正在使用这个项目来学习着色器,所以我对所有这些都是新手。 任何帮助将不胜感激。

通过完全重写代码来解决此问题。

我仍然不能100%知道问题出在哪里,但我认为我可能有一些不匹配的启用/禁用呼叫。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM