GLSL渲染到纹理不起作用

时间:2015-07-21 19:49:03

标签: opengl glsl

我正在尝试进行计算传递,我将渲染到稍后将在绘图传递中使用的纹理。我的初始实现基于着色器存储缓冲区对象,并且运行良好。但我想应用一种计算方法,该方法将利用GPU的混合硬件,因此我开始将SSBO实现移植到RTT实现。不幸的是,代码已停止工作。现在,当我回读纹理时,它会得到错误的值。

这是我的纹理和帧缓冲区设置代码:

glGenFramebuffers(1, &m_fbo);
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);

// Create render textures
glGenTextures(NUM_TEX_OUTPUTS, m_renderTexs);
m_texSize = square_approximation(m_numVertices);
cout << "Textures size: " << glm::to_string(m_texSize) << endl;
GLenum drawBuffers[NUM_TEX_OUTPUTS];
for (int i = 0 ; i < NUM_TEX_OUTPUTS; ++i)
{
    glBindTexture(GL_TEXTURE_2D, m_renderTexs[i]);
    // 1st 0: level, 2nd 0: no border, 3rd 0: no initial data
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_texSize.x, m_texSize.y, 0, GL_RGBA, GL_FLOAT, 0);
    // XXX: do we need this?
    // Poor filtering. Needed !
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glBindTexture(GL_TEXTURE_2D, 0);

    // 0: level
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, m_renderTexs[i], 0);
    drawBuffers[i] = GL_COLOR_ATTACHMENT0 + i;
}
glDrawBuffers(NUM_TEX_OUTPUTS, drawBuffers);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
    cout << "Error when setting frame buffer" << endl;
    // throw exception?
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);

这是启动计算传递的代码:

m_shaderProgram.use();

// setup openGL
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glViewport(0, 0, m_texSize.x, m_texSize.y); // setup viewport (equal to textures size)
// make a single patch have the vertex, the bases and the neighbours
glPatchParameteri(GL_PATCH_VERTICES, m_maxNeighbours + 5);

// Wait all writes to shader storage to finish
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);

glUniform1i(m_shaderProgram.getUniformLocation("curvTex"), m_renderTexs[2]);
glUniform2i(m_shaderProgram.getUniformLocation("size"), m_texSize.x, m_texSize.y);
glUniform2f(m_shaderProgram.getUniformLocation("vertexStep"), (umax - umin)/divisoes,
            (vmax-vmin)/divisoes);

// Bind buffers 
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibo);
glBindBufferBase(GL_UNIFORM_BUFFER, m_mvp_location, m_mvp_ubo);

// Make textures active
for (int i = 0; i < NUM_TEX_OUTPUTS; ++i)
{
    glActiveTexture(GL_TEXTURE0 + i);
    glBindTexture(GL_TEXTURE_2D, m_renderTexs[i]);
}

// no need to pass index array 'cause ibo is bound already
glDrawElements(GL_PATCHES, m_numElements, GL_UNSIGNED_INT, 0);

然后我使用以下内容回读纹理:

bool readTex(GLuint tex, void *dest)
{
    glBindTexture(GL_TEXTURE_2D, tex);
    glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, dest);
    glBindTexture(GL_TEXTURE_2D, 0);

    // TODO: check glGetTexImage return values for error
    return true;
}

for (int i = 0; i < NUM_TEX_OUTPUTS; ++i)
{
    if (m_tensors[i] == NULL) {
        m_tensors[i] = new glm::vec4[m_texSize.x*m_texSize.y];
    }
    memset(m_tensors[i], 0, m_texSize.x*m_texSize.y*sizeof(glm::vec4));
    readTex(m_renderTexs[i], m_tensors[i]);
}

最后,片段着色器代码为:

#version 430
#extension GL_ARB_shader_storage_buffer_object: require

layout(pixel_center_integer) in vec4 gl_FragCoord;

layout(std140, binding=6) buffer EvalBuffer {
    vec4 evalDebug[];
};

uniform ivec2 size;

in TEData {
    vec4 _a;
    vec4 _b;
    vec4 _c;
    vec4 _d;
    vec4 _e;
};

layout(location = 0) out vec4 a;
layout(location = 1) out vec4 b;
layout(location = 2) out vec4 c;
layout(location = 3) out vec4 d;
layout(location = 4) out vec4 e;

void main()
{
    a= _a;
    b= _b;
    c= _c;
    d= _d;
    e= _e;
    evalDebug[gl_PrimitiveID] = gl_FragCoord;
}

片段坐标是正确的(每个片段指向纹理中的x,y坐标),所有输入值(_a到_e)都是如此,但是在回读时我没有看到它们正确地输出到纹理。我也尝试访问着色器中的纹理以查看它是否只是一个回读错误,但我的调试SSBO返回全部为零。

我错过了一些设置步骤吗? 我已经在linux和windows(titan和540M geforces)上测试过,我使用的是openGL 4.3。

1 个答案:

答案 0 :(得分:1)

正如derhass在上面的评论中指出的那样,问题在于纹理格式。我假设通过传递GL_FLOAT作为数据类型,它将为每个RGBA通道使用32位浮点数。事实并非如此。 正如derhass所说,这里的数据类型参数不会改变纹理格式。我不得不将internalFormat参数更改为我想要的(GL_RGBA32F),以便它可以按预期工作。 所以,在将glTexImage2D调用改为:

之后
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, m_texSize.x, m_texSize.y, 0, GL_RGBA, GL_FLOAT, 0);

我能够正确地将结果渲染到纹理并将其读回。 :)