使用FBO和着色器OpenGL渲染到纹理

时间:2014-11-30 18:50:57

标签: opengl glsl shader fbo render-to-texture

我想在我的FBO中加载两个纹理,一个纹理包含HDR图像,我的第一个目标是将图像从第一个纹理“复制”到第二个(这是空的),并称为“ DownSamplingTex < / em>的”。

所以我创建了FBO,在COLOR_ATTACHMENT_0中加载我想写的纹理,然后绑定它;然后初始化我的着色器程序并渲染一个四边形,我想在GL_TEXTURE_0中读取绑定的纹理。

然后我取消绑定FBO并绑定' DownSamplingTex ',并绘制四边形。

我不知道这个过程是否正确,我的输出是黑屏。

这是渲染代码:

glBindFramebuffer(GL_FRAMEBUFFER, fboA);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
FBOtex->bind();  // Set read texture bound in GL_TEXTURE_0
glDrawBuffer(GL_COLOR_ATTACHMENT0);  // draw to write texture (DownSamplingTex)
fboShad->bind();    // use program of FBO shader
  fboShad->setUniformValue4f("MVP", glm::value_ptr(MVP));  // Shader attribute
  drawQuad();   // Draw
  fboShad->unbind();
 FBOtex->unbind();
// Main FB rendering
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
fboShad->bind();
  fboShad->setUniformValue4f("MVP", glm::value_ptr(MVP)); 
  DownSamplingTex->bind();
  drawQuad(); 
  DownSamplingTex->unbind();
fboShad->unbind();

顶点着色器:

#version 420

in vec4 vUV;
in vec4 vVertex;
smooth out vec2 vTexCoord;

uniform mat4 MVP;

void main()
{
   vTexCoord = vUV;
   gl_Position = MVP*vVertex;
}

片段着色器:

#version 420
smooth in vec2 vTexCoord;
layout(location = 0) out vec4 color;
layout(binding=0) uniform sampler2D texHDR;

void main(void)
{
   color = texture(texHDR,vTexCoord);
}

在' drawQuad()'里面我用 glGetAttribLocation() glVertexAttribPointer()设置 vVertex 值。

std::vector<GLfloat> quadVerts = {
    -1, -1, 0, 0, 1,
    -1, 1, 0, 0, 0,
    1, 1, 0, 1, 0,
    -1, -1, 0, 0, 1,
    1, 1, 0, 2, 0,
    1, -1, 0, 1, 1 };

GLuint quadVbo;
glGenBuffers(1, &quadVbo);
glBindBuffer(GL_ARRAY_BUFFER, quadVbo);
glBufferData(GL_ARRAY_BUFFER, 6*3*4, &quadVerts[0], GL_STATIC_DRAW);
GLuint vVertex = fboShad->getLocation("vVertex");
GLuint vUV = fboShad->getLocation("vUV");
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 3 * sizeof(GLfloat), NULL);

glEnableVertexAttribArray(vVertex);
glVertexAttribPointer(vVertex, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 3, 0);
glEnableVertexAttribArray(vUV);
glVertexAttribPointer(vUV, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (void*)(3 * sizeof(GLfloat)));
glDrawArrays(GL_TRIANGLES, 0, 6);

glBindBuffer(GL_ARRAY_BUFFER, 0);
glDisableVertexAttribArray(vVertex);
glDisableVertexAttribArray(vUV);

我不知道这个过程中是否存在错误,或者在片段着色器中使用属性可能不正确(我认为' layout(binding = 1)',如果你使用带有FBO绑定的着色器,采用GL_COLOR_ATTACHMENT_1纹理);或者使用'vTexCoords'作为顶点的.xy值。

1 个答案:

答案 0 :(得分:1)

我认为您将采样器绑定与片段数据输出位置混淆。虽然可以使用layout (...)限定符分配这两个内容,但它们非常不同。

layout (location = X) out vec3 color将输出color分配给 GL_COLOR_ATTACHMENT0 + X

layout (binding = Y) sampler2D texHDR告诉GLSL使用纹理图像单元 GL_TEXTURE0 + Y

您的片段着色器仅写入单个输出,因此在这种情况下没有实际的理由可以拥有多个颜色附件。您将图像附加到FBO,以便从片段着色器写入它们,而不是从它们作为纹理读取它们。实际上,在不使用特殊扩展(例如 GL_NV_texture_barrier)的情况下,连接到FBO进行写入的同时从纹理读取是未定义的行为。


在这种情况下你真正想做的是:

Modified Fragment Shader:

#version 420
smooth in vec2 vTexCoord;
//out vec4 vFragColor;

layout(location=0) out     vec3      color;  // Fragment Data Output Location
layout(binding=0)  uniform sampler2D texHDR; // Texture Image Unit Binding

void main(void)
{
//vFragColor = texture(textureMap, vTexCoord);
//color = vec4(1.0,0.5,0.5,0.5);
   color = texture(texHDR,vTexCoord);
}

现在,你想要阅读的纹理应绑定到GL_TEXTURE0(这是默认设置,除非你手动调用glActiveTexture (...) somehwere)并且你要输出的纹理应该附加到你的Framebuffer对象GL_COLOR_ATTACHMENT0

这里要记住的最重要的事情是bindinglocation限定符是完全独立的:颜色附件0与纹理图像单元0不对应。