Deferred Shading Issues

Started by bogieman987, January 02, 2015, 23:41:35

Previous topic - Next topic

bogieman987

Hey guys,

So I decided to try and attempt setting up deferred rendering, and I've hit a slight snag.
In the end it seems that only the first texture gets rendered in the final.

There are no errors or anything the framebuffer passes completeness.
I would imagine it may be an issue with texture binding, but I've spent the last day looking hard through the code to make sure it's ok from what I understand at least.

In trying to set it up I somewhat used this tutorial.

I didn't do it exact because from what I learned, calling "glBindFramebuffer()", "GL_FRAMEBUFFER" makes it so the framebuffer created can both read and write data, so no need for any blitting or general copying of the data from one framebuffer to another.
Perhaps that's the problem, I don't know.

Anyway, here's the code. Though it's a bit messy for my liking, when I get everything working I'll refactor it.
GBuffer
System.out.println("---Creating Framebuffer---");
			
getRect().init();
getRect().spawn();
			
setFbo(GL30.glGenFramebuffers());
GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, getFbo());

// Texturebuffer for color
setTexture(GL11.glGenTextures());
GL13.glActiveTexture(GL13.GL_TEXTURE0);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, getTexture());
GL42.glTexStorage2D(GL11.GL_TEXTURE_2D, 1, GL30.GL_RGBA16F, getWidth(), getHeight());
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
GL30.glFramebufferTexture2D(GL30.GL_FRAMEBUFFER, GL30.GL_COLOR_ATTACHMENT0, 
		GL11.GL_TEXTURE_2D, getTexture(), 0);
// Texturebuffer for world position
setPosition(GL11.glGenTextures());
GL13.glActiveTexture(GL13.GL_TEXTURE1);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, getPosition());
GL42.glTexStorage2D(GL11.GL_TEXTURE_2D, 1, GL30.GL_RGBA16F, getWidth(), getHeight());
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
GL30.glFramebufferTexture2D(GL30.GL_FRAMEBUFFER, GL30.GL_COLOR_ATTACHMENT1, 
		GL11.GL_TEXTURE_2D, getPosition(), 0);
// Texturebuffer for normal
setNormal(GL11.glGenTextures());
GL13.glActiveTexture(GL13.GL_TEXTURE2);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, getNormal());
GL42.glTexStorage2D(GL11.GL_TEXTURE_2D, 1, GL30.GL_RGBA16F, getWidth(), getHeight());
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
GL30.glFramebufferTexture2D(GL30.GL_FRAMEBUFFER, GL30.GL_COLOR_ATTACHMENT2, 
		GL11.GL_TEXTURE_2D, getNormal(), 0);
// Texturebuffer for texture coordinates
setTexCoord(GL11.glGenTextures());
GL13.glActiveTexture(GL13.GL_TEXTURE3);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, getTexCoord());
GL42.glTexStorage2D(GL11.GL_TEXTURE_2D, 1, GL30.GL_RGBA16F, getWidth(), getHeight());
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
GL30.glFramebufferTexture2D(GL30.GL_FRAMEBUFFER, GL30.GL_COLOR_ATTACHMENT3, 
		GL11.GL_TEXTURE_2D, getTexCoord(), 0);
			
// Renderbuffer for depth
setDepth(GL30.glGenRenderbuffers());
GL30.glBindRenderbuffer(GL30.GL_RENDERBUFFER, getDepth());
GL30.glRenderbufferStorage(GL30.GL_RENDERBUFFER, GL14.GL_DEPTH_COMPONENT24, getWidth(), getHeight());
			
GL30.glFramebufferRenderbuffer(GL30.GL_FRAMEBUFFER, GL30.GL_DEPTH_ATTACHMENT, GL30.GL_RENDERBUFFER, 
		getDepth());

GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
			
// The buffers given would contain things like GL30.GL_COLOR_ATTACHMENT0 inside an int array where here 
// it's converted a buffer
int[] buffers = new int[] {GL30.GL_COLOR_ATTACHMENT0, GL30.GL_COLOR_ATTACHMENT1,
		GL30.GL_COLOR_ATTACHMENT2, GL30.GL_COLOR_ATTACHMENT3};
IntBuffer drawBuffers = BufferUtils.createIntBuffer(buffers.length);
for(int elem : buffers) {
	drawBuffers.put(elem);
}
drawBuffers.flip();
			
GL20.glDrawBuffers(drawBuffers);
			
errorCheck();
			
GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, 0);
			
System.out.println("---Created Framebuffer---");


Main part of rendering code
I accidentally screwed up the formatting a bit when copying it over :/
@Override
protected void render() {		
   try {
	// Render to framebuffer
	GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, getGBuffer().getFbo());
			
	clear();
	
	GL20.glUseProgram(getShaderProgs()[0].getShaderProg());
			
	// Projection Matrix
	getMatrixBuffer().setData(getCamera().getProjectionMatrix());
	GL20.glUniformMatrix4(getShaderProgs()[0].getUniforms().get(0).getLocation(), false, 
			getMatrixBuffer().getBuffer());
			
	// View Matrix
	getMatrixBuffer().setData(getCamera().getViewMatrix());
	GL20.glUniformMatrix4(getShaderProgs()[0].getUniforms().get(1).getLocation(), false, 
			getMatrixBuffer().getBuffer());
				
	if(GameObjectPool.getAssetPool() != null) {
		for( BaseGameObject elem : GameObjectPool.getAssetPool()) {
			// TODO Set up if expected model isn't loaded, game will load error model.
			getMatrixBuffer().setMassData(elem.getMeshMatrix().
					toArray(new Matrix4f[elem.getMeshMatrix().size()]));
														
			GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, elem.getMesh().getIVbo());
			GL15.glBufferData(GL15.GL_ARRAY_BUFFER, getMatrixBuffer().getBuffer(), GL15.GL_STATIC_DRAW);
			GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
					
			//TODO seperate texture, so if it fails, render error texture
		//	for(int i = 0; i < elem.getMaterial().getTextures().length; i++) {
		//		GL20.glUniform1i(getShaderProgs()[0].getUniform(uniNames[i + 2]).getLocation(), i);
		//		GL13.glActiveTexture(GL13.GL_TEXTURE0 + i);
		//		GL11.glBindTexture(GL11.GL_TEXTURE_2D, elem.getMaterial().getTextures()[i].getVboT());
		//	}
			GL20.glUniform1i(getShaderProgs()[0].getUniforms().get(2).getLocation(), 0);
			GL13.glActiveTexture(GL13.GL_TEXTURE0);
			GL11.glBindTexture(GL11.GL_TEXTURE_2D, elem.getMaterial().getTextures()[0].getVboT());

			GL30.glBindVertexArray(elem.getMesh().getVao());

			GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, elem.getMesh().getVboI());
					
			RenderMethods.DrawElementsInstanced(elem.getMesh().getVboI(), elem.getMesh().getIndiceCount(), 
					elem.getMeshMatrix().size());
		}
	}

	errorCheck();
   } catch (GLErrorException e) {
	e.printStackTrace();
   }
}

@Override
protected void postProc() {	
	// Render gbuffer
	GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, 0);
					
	clear();
					
//	RenderMethods.toggleWireframe();
										
	GL20.glUseProgram(getShaderProgs()[2].getShaderProg());

	// Bind object data
	GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, getGBuffer().getRect().getIVbo());
	GL15.glBufferData(GL15.GL_ARRAY_BUFFER, getMatrixBuffer().getBuffer(), GL15.GL_STATIC_DRAW);
	GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
					
	// Bind texture data
	GL20.glUniform1i(getShaderProgs()[2].getUniforms().get(0).getLocation(), 0);
	GL13.glActiveTexture(GL13.GL_TEXTURE0);
	GL11.glBindTexture(GL11.GL_TEXTURE_2D, getGBuffer().getTexture());
	// Bind position data
	GL20.glUniform1i(getShaderProgs()[2].getUniforms().get(1).getLocation(), 0);
	GL13.glActiveTexture(GL13.GL_TEXTURE1);
	GL11.glBindTexture(GL11.GL_TEXTURE_2D, getGBuffer().getPosition());
	// Bind normal data
	GL20.glUniform1i(getShaderProgs()[2].getUniforms().get(2).getLocation(), 0);
	GL13.glActiveTexture(GL13.GL_TEXTURE2);
	GL11.glBindTexture(GL11.GL_TEXTURE_2D, getGBuffer().getNormal());
	// Bind world pos data
	GL20.glUniform1i(getShaderProgs()[2].getUniforms().get(3).getLocation(), 0);
	GL13.glActiveTexture(GL13.GL_TEXTURE3);
	GL11.glBindTexture(GL11.GL_TEXTURE_2D, getGBuffer().getTexCoord());
								
	GL30.glBindVertexArray(getGBuffer().getRect().getVao());
					
	GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, getGBuffer().getRect().getVboI());
					
	RenderMethods.DrawElementsInstanced(getGBuffer().getRect().getVboI(), 
			getGBuffer().getRect().getIndiceCount(), getGBuffer().getRect().getMatrix().size());
					
}


First pass shaders
Vertex shader
#version 430 core

in vec4 in_Position;
in vec2 in_TexCoord;
in vec3 in_Normal;
in vec3 in_Tangent;
in mat4 in_ModelMatrix;

out VS_OUT {
	vec2 pass_TexCoord;
	vec3 pass_WorldPos;
	vec3 pass_Normal;
} vs_Out;

uniform mat4 proj_Matrix;
uniform mat4 view_Matrix;

void main(void) {	
	gl_Position = proj_Matrix * view_Matrix * in_ModelMatrix * in_Position;
	
	vs_Out.pass_TexCoord = in_TexCoord;
	vs_Out.pass_WorldPos = (in_ModelMatrix * in_Position).xyz;
	vs_Out.pass_Normal = (in_ModelMatrix * vec4(in_Normal, 0.0)).xyz;
}

Fragment shader
#version 430 core

uniform sampler2D albedo_Tex;

in VS_OUT {
	vec2 pass_TexCoord;
	vec3 pass_WorldPos;
	vec3 pass_Normal;
} fs_In;

layout (location = 0) out vec4 out_Color;
layout (location = 1) out vec4 out_WorldPos;
layout (location = 2) out vec4 out_Normal;
layout (location = 3) out vec4 out_TexCoord;

void main(void) {	
	out_Color = vec4(1.0, 1.0, 1.0, 1.0);
	
	out_Color = texture2D(albedo_Tex, fs_In.pass_TexCoord);	
	out_WorldPos = vec4(fs_In.pass_WorldPos, 0.0);
	out_Normal = vec4(fs_In.pass_Normal, 0.0);
	out_TexCoord = vec4(fs_In.pass_TexCoord, 0.0, 0.0);
}

Second pass shaders
Vertex shader
#version 430 core

in vec4 in_Position;
in vec2 in_TexCoord;
in mat4 in_ModelMatrix;

out VS_OUT {
	vec2 pass_TexCoord;
} vs_Out;

void main(void) {	
	gl_Position = in_Position;	
//	gl_Position = in_ModelMatrix * in_Position;	
	
	vs_Out.pass_TexCoord = in_TexCoord;
}

Fragment shader
#version 430 core

layout (location = 0) uniform sampler2D gbo_Texture;
layout (location = 1) uniform sampler2D gbo_Position;
layout (location = 2) uniform sampler2D gbo_Normal;
layout (location = 3) uniform sampler2D gbo_TexCoord;

in VS_OUT {
	vec2 pass_TexCoord;
} fs_In;

out vec4 out_Color;

void main(void) {
	if(fs_In.pass_TexCoord.y < 0.25) {
		out_Color = texture2D(gbo_Texture, fs_In.pass_TexCoord);
	//	out_Color = vec4(0.0, 1.0, 1.0, 1.0);
	} else if(fs_In.pass_TexCoord.y < 0.5) {
		out_Color = texture2D(gbo_Position, fs_In.pass_TexCoord);
	//	out_Color = vec4(1.0, 0.0, 1.0, 1.0);
	} else if(fs_In.pass_TexCoord.y < 0.75) {
		out_Color = texture2D(gbo_Normal, fs_In.pass_TexCoord);
	//	out_Color = vec4(1.0, 1.0, 0.0, 1.0);
	} else {
		out_Color = texture2D(gbo_TexCoord, fs_In.pass_TexCoord);
	//	out_Color = vec4(1.0, 1.0, 1.0, 1.0);
	}
}

If I uncomment the "out_Color = vec4(x.x, x.x, x.x, x.x);", I get the output I would expect. Except when I use the textures, they all seem bound to a single texture, the first one.

Any advice or pointing in the right direction would be a great help.
Will soon be an Oracle Certified Associate :D

Kai

Hi,

you need to set the correct texture unit index (0 through 3) for your uniforms (gbo_Texture, ...).
In lines 73-85 in your render() method you seem to be setting all of them to 0, which for all of them means "the first texture unit".
You need to set them to 0 through 3 respectively (the last argument to glUniform1i).

You might think that this is what your "location" layout qualifier does, but that is not so. The "location" layout qualifier tells OpenGL what "uniform location" this uniform should allocate (see https://www.opengl.org/wiki/Layout_Qualifier_%28GLSL%29#Explicit_uniform_location). This is something that you should rather let OpenGL decide and then query via glGetUniformLocation.

Regards,
Kai

bogieman987

Ah that explains it, I wasn't too sure what to put in those values, as even though it's similar to what I used earlier when passing data for projection and view matrices with the "glUniformMatrix4()" method, it's still different and I had no idea what I would put in terms of textures.

I do use glGetUniformLocation, after I get the value, I store it in a Uniform class, which is stored in an array of uniforms in a ShaderProgram class, where I initiate the shader program.
Which later gets called like so "getShaderProgs()[int].getUniforms().get(int).getLocation()".

I read somewhere, I can't remember where, that doing the layout thing, liked the texture to a specific color attachment, or something along those lines. Though it is entirely possible, and more likely, that I miss read and/or miss understood what was being said.

Anyways, thank you for the very quick response.
Will soon be an Oracle Certified Associate :D

Kai

QuoteI read somewhere, I can't remember where, that doing the layout thing, liked the texture to a specific color attachment...

Yeah, that is true for fragment shader output variables (see https://www.opengl.org/wiki/Layout_Qualifier_%28GLSL%29#Fragment_shader_buffer_output).
There you specify the fragment output location, which you would otherwise do in the host program using glBindFragDataLocation before linking the shader program containing the fragment shader.

But the layout qualifiers are really heavily overloaded, like almost everything in OpenGL ;).
For this they mean this, and for that they mean that.

bogieman987

Damn, they don't seem to like making it easier for new comers ::)
Though then again, anyone who really wants to learn it, will eventually learn most of the nooks and crannies.
Will soon be an Oracle Certified Associate :D

Kai

To complete on my previous post, I just had a read on that page about layout qualifiers again and it says you can use the binding qualifier to achieve what you originally wanted. That is, to bind the uniform of a sampler to a specific texture unit.
Doing that you do not need to set the uniform value in the host program anymore.

So, the relevant part of your fragment shader becomes:

layout (binding = 0) uniform sampler2D gbo_Texture;
layout (binding = 1) uniform sampler2D gbo_Position;
layout (binding = 2) uniform sampler2D gbo_Normal;
layout (binding = 3) uniform sampler2D gbo_TexCoord;


The downside of this is that you push the minimal required OpenGL version unnecessarily high (4.2), whereas for simple deferred shading you could get away with simple OpenGL 2.0, and thus make your solution reach more potential users.
But if you target OpenGL 4.3 anyways, there is nothing wrong with doing it this way.

bogieman987

Yeah, I'm kind of focusing towards cards from the Nvidia 400 series and the ATI HD 5000 series and up (Not sure about Intel GPUs), which according to Steam 72% of their user-base has and is still growing. At least until the next major DX and OpenGL release.
That and I'm doing this a project and learning experience, so I don't really care about how many people can play it, should I be more serious then that would definitely become something to think about.
Will soon be an Oracle Certified Associate :D