2016-04-10 91 views
0

我会在前言中说我对这些主题颇为陌生,并且在过去几天为一个学校项目给了自己一次速成课程。我很抱歉,这是相当长的,但由于我不知道问题出在哪里,我想我会努力彻底。使用framebuffer绘制纹理贴图(纹理空白)

我试图使用framebuffer绘制到一些RGBA纹理,稍后用于其他绘图(我使用纹理中的值作为矢量绘制粒子 - 纹理存储值,如它们的位置和速度)。

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

我使用SDL2和glew的OpenGL 4。

我会尝试发布有序推进相关的一切:

帧缓冲器类创建帧缓冲和随员(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和glBind的顶点数组和缓冲区。

这里使用的着色器具有这对顶点着色器:

#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);到DIF不同的值,但我的像素打印仍然给0 0 0 1。

我一直在调试这个约20-30小时,抬头一打左右不同的教程和其他问题在这里,但最后几个小时,我不觉得我获得的任何理由。这里

任何脱颖而出为什么纹理显示为空白/黑色,否则任何事情,需要解决?我正在使用这个项目来了解着色器,所以我对这些都很陌生。任何帮助将非常感激。

+0

使用恒定'GL_MAX_COLOR_ATTACHMENTS'来控制缓冲器的循环的迭代的分配和数量是*** *** WRONG。这是一个您查询以查找实际数字的ID,它的基本形式不是任何类型的限制,它将是一个非常大的数字,您可能会遇到运行时问题,试图分配和运行一个循环很多次:)首先查询值。 –

+0

@ AndonM.Coleman感谢您的收获。现在我用'glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS,&maxAttach);'查询它。我想我真的很幸运,因为我只有3个纹理,所以我从来没有遇到任何问题。 – Claytorpedo

+0

虽然没有改变,我想?想到的第二个问题是,你已经绑定了一个已经附加到你的活动帧缓冲区进行写入的读取纹理。在纹理当前处于活动状态时绑定纹理作为帧缓冲区的图像附件不太可能做任何事情,您可能会得到不连贯的值。要从当前绑定的FBO中读取像素数据,您需要使用'glReadPixels(...)'将readbuffer设置为适当的颜色附件。 –

回答

0

这与代码的完全重新编写解决。

我仍然不是100%肯定问题出在哪里了,但我想我可能有一些不匹配的启用/禁用电话。