hey0 hey0 - 3 months ago 8
C++ Question

Deferred Shading OpenGL implementation

I'm currently trying to implement deferred shading in OpenGL 3.2 and have a problem that I just can't seem to solve no matter what I try.

I implemented it in two steps(geometry pass and lighting pass) like one would expect. After compiling and running it the screen shows the scene I prepared almost like one would expect it to look like. The colors of the objects are correct and they are also positioned where and how I wanted them to be.

The thing is, that the light calculations seem to have no influence on the color, what so ever. After a lot of hours I found out, that the textures for the positions and normals seem to contain the same content like the color texture.

If one changes the last line in the lighting fragment shader from

fragColor = lightIntensity * color;
to
fragColor = lightIntensity * norm;
or
fragColor = lightIntensity * pos;
it has absolutely no impact on how the screen is rendered.

I have tried a lot to figure out what is going wrong but honestly have no idea what it could be.

It would be awesome if someone could help me.

My render method looks like this:

void render()
{

//geometry pass
gBuffer->bindForWriting();
geometryShader->use(true);
calculateGBuffer();


//lighting pass
gBuffer->bindForReading(lightShader->programID());
lightShader->use(true);
drawOnScreen();

}


The initialization of the
gBuffer
object is like this:

void GBuffer::initializeFBO(int viewWidth, int viewHeight)
{

//initialize fbo and corresponding textures;
glGenFramebuffers(1, &fbo_ID);
glBindFramebuffer(GL_FRAMEBUFFER, fbo_ID);

glGenTextures(1, &colorTexture_ID);
glBindTexture(GL_TEXTURE_2D, colorTexture_ID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, viewWidth, viewHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture_ID, 0);

glGenTextures(1, &posTexture_ID);
glBindTexture(GL_TEXTURE_2D, posTexture_ID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, viewWidth, viewHeight, 0, GL_RGB, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, posTexture_ID, 0);

glGenTextures(1, &normTexture_ID);
glBindTexture(GL_TEXTURE_2D, normTexture_ID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, viewWidth, viewHeight, 0, GL_RGB, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, normTexture_ID, 0);

GLuint attachments[3] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 };
glDrawBuffers(3, attachments);

glGenRenderbuffers(1, &depthBuffer_ID);
glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer_ID);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, viewWidth, viewHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer_ID);



//Check Status
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
qDebug() << "error while initializing framebuffer" << glCheckFramebufferStatus(GL_FRAMEBUFFER);
else{
qDebug() << "framebuffer successfully created";
initialized = true;
}

glBindFramebuffer(GL_FRAMEBUFFER, 0);

}


The methods
bindForReading
and
bindForWriting
:

void GBuffer::bindForWriting()
{
glBindFramebuffer(GL_FRAMEBUFFER, fbo_ID);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}

void GBuffer::bindForReading(GLuint programID)
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, colorTexture_ID);
GLuint samplerTexture_ID = glGetUniformLocation(programID, "colorTexture");
glUniform1i(samplerTexture_ID, 0);

glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, posTexture_ID);
samplerTexture_ID = glGetUniformLocation(programID, "positionTexture");
glUniform1i(samplerTexture_ID, 1);

glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, normTexture_ID);
samplerTexture_ID = glGetUniformLocation(programID, "normTexture");
glUniform1i(samplerTexture_ID, 2);

}


And at last the 4 Shaders:

Geometry Vertex Shader:

#version 150
#extension GL_ARB_separate_shader_objects : enable
uniform mat4 MVPMatrix;
uniform mat4 modelMatrix;

in vec4 in_position;
in vec4 in_color;
in vec2 in_texcoord;
in vec3 in_norm;

out vec4 color_varying;
out vec3 frag_position;
out vec3 norm_vec;
out vec2 texcoord_varying;

void main()
{
gl_Position = MVPMatrix * in_position;
vec4 worldPosition = (modelMatrix * in_position);
frag_position = worldPosition.xyz;
norm_vec = in_norm;

color_varying = in_color;
texcoord_varying = in_texcoord;
}


Geometry Fragment Shader:

#version 150
#extension GL_ARB_explicit_attrib_location : enable

in vec4 color_varying;
in vec3 frag_position;
in vec3 norm_vec;
in vec2 texcoord_varying;

layout (location = 0) out vec4 fragColor;
layout (location = 1) out vec3 fragPosition;
layout (location = 2) out vec3 frag_norm_vec;

uniform sampler2D myTexture;

void main()
{
vec4 texel = texture(myTexture, texcoord_varying);
fragColor = texel * color_varying;
fragPosition = frag_position;
frag_norm_vec = normalize(norm_vec);
}


Lighting VertexShader:

#version 150
#extension GL_ARB_explicit_attrib_location : enable
layout (location = 0) in vec2 in_position;

out vec2 texCoord;

void main()
{
gl_Position = vec4(in_position, 0, 1.0f);

texCoord = in_position;
if(texCoord.x == -1.0f)
texCoord.x = 0.0f;
if(texCoord.y == -1.0f)
texCoord.y = 0.0f;
}


Lighting Fragment Shader(without lighting calculation to make it shorter)

#version 150
#extension GL_ARB_separate_shader_objects : enable

out vec4 fragColor;
in vec2 texCoord;


uniform sampler2D colorTexture;
uniform sampler2D positionTexture;
uniform sampler2D normTexture;

void main()
{
//extract fragment data from fbo
vec3 pos = texture(positionTexture, texCoord).rgb;
vec3 norm = texture(normTexture, texCoord).rgb;
vec4 color = texture(colorTexture, texCoord);


fragColor = lightIntensity * color;
}


Sry for the code spamming but I can't narrow down the error.

Answer

The problem is most likely in your order of operations here:

gBuffer->bindForReading(lightShader->programID());
lightShader->use(true);

where, in bindForReading(), you have calls like this one:

samplerTexture_ID = glGetUniformLocation(programID, "positionTexture");
glUniform1i(samplerTexture_ID, 1);

The glUniform*() calls set uniform values on the currently active program. Since you make the lightShader active after you make these calls, the uniform values will be set on the previously active program, which probably doesn't even have these uniforms.

Simply changing the order of these calls might already fix this:

lightShader->use(true);
gBuffer->bindForReading(lightShader->programID());

Also, you're using GL_RGB16F as the format of two of your buffers. The OpenGL implementation you use may support this, but this is not a format that is required to be color-renderable in the spec. If you want your code to work across platforms, you should use GL_RGBA16F, which is guaranteed to be color-renderable.

Comments