Help with basic deferred lighting please - Solved

Started by
18 comments, last by hannesp 9 years, 2 months ago
  • GL_FRAMEBUFFER_UNSUPPORTED is returned if the combination of internal formats of the attached images violates an implementation-dependent set of restrictions.

https://www.opengl.org/sdk/docs/man3/xhtml/glCheckFramebufferStatus.xml

i'm not sure what is the problem here

see for possible formats https://www.opengl.org/sdk/docs/man/html/glTexImage2D.xhtml

but anyway, you want 16 or 32 bit values for position and normals, also with 3 not 4 values

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, width, height, 0, GL_RGB, GL_FLOAT, NULL); // position, 3 float values

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, width, height, 0, GL_RGB, GL_FLOAT, NULL); // normals, 3 float values
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_FLOAT, NULL); // diffuse color, 3 float values, or 4 values with alpha (GL_RGBA)

for more details consider my deferred rendering code https://github.com/oggs91/CGUE2014-15/blob/master/src/DeferredPipeline.cpp line 333

Advertisement

but anyway, you want 16 or 32 bit values for position and normals, also with 3 not 4 values

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, width, height, 0, GL_RGB, GL_FLOAT, NULL); // position, 3 float values

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, width, height, 0, GL_RGB, GL_FLOAT, NULL); // normals, 3 float values
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_FLOAT, NULL); // diffuse color, 3 float values, or 4 values with alpha (GL_RGBA)

for more details consider my deferred rendering code https://github.com/oggs91/CGUE2014-15/blob/master/src/DeferredPipeline.cpp line 333

Ok thanks - looks like my video card only supports GL_RGBA16F. But, making progress.

This is now rendered using this shader:


#version 330

uniform sampler2D   tDepth;
uniform sampler2D   tDiffuse;
uniform sampler2D   tPosition;
uniform sampler2D   tNormals;

uniform vec4        lightPosition;
uniform mat4        u_viewProjectionMat;
//vec3 lightPosition = vec3(0, 10, 0);

vec3 lightDiffuse = vec3(0.5, 0.5, 0.5);
vec4 lightSpecular = vec4(1.0, 0.0, 1.0, 64.0);

vec3 ambient = vec3(0.3, 0.3, 0.3);

uniform float nearPlane;
uniform float farPlane;
uniform float viewWidth;
uniform float viewHeight;
uniform vec2 texelSize;

in vec2 fragTexCoord0;

out vec4 outColor;

void main()
{
	vec3 normal = texture2D(tNormals, fragTexCoord0.xy).rgb;
	vec3 color   = texture2D(tDiffuse, fragTexCoord0.xy).rgb;
	vec3 position = texture2D(tPosition, fragTexCoord0.xy).rgb;

	float dist = 20.0f / distance(position, lightPosition.xyz);
	//
	// lighting
	//
	vec3 lightVector = normalize(lightPosition.xyz - position);
	vec3 halfVector  = normalize(lightVector + normalize(-position));

	float nl = dot(lightVector, normal);

	vec3 diffuse = lightDiffuse * max(0.0, nl);
	vec3 specular = vec3(0.0);

	if (nl > 0.0)
	    specular = lightSpecular.rgb * pow(max(0.0, dot(halfVector, normal)), lightSpecular.w);

	outColor.rgb = 1.0 * (color.rgb * diffuse * dist + specular * dist);
	outColor.a = 1.0f;

    outColor.rgb = outColor.rgb + halfVector;
}

2a2tyx.png

So the shader is working down to calculating the halfVector, but anything below that results in a black image - I suspect that the normals that are being read from the texture are all 0 - but they are present in the GBuffer as evidenced by displaying the texture. Any thoughts?

Edit: I can see the image changing as the light rotates around above the tank.

Edit: Hahah - nice surprise in the middle of your demo video !

replace

vec3 halfVector = normalize(lightVector + normalize(-position));

with

vec3 viewVector = normalize(position - cameraPosition);

vec3 halfVector = normalize(lightVector + viewVector);

like light position you also have to pass the camera position as a uniform to the shader

remember you are doing lighting there in worldspace, not in viewspace. in viewspace the direction to the viewer would be -position

Edit: Hahah - nice surprise in the middle of your demo video !

thx biggrin.png

Still not working - but I think I have worked out the problem.

Running the shader below, I always get a red square - ie: no diffuse color. Running


float nl = dot(lightVector, normal);

seems to always result in nl being a 0 - which my basic understanding of maths is that dot(lightVector, 0) - will always result in a 0.

The normals are there - as can be seen in the top right texture, and I have checked them as the file is loaded. I have modified the normal line to make sure they are in worldspace ( I think ).

Does the transformation of the normals look right to you?



#version 330

uniform sampler2D   tDepth;
uniform sampler2D   tDiffuse;
uniform sampler2D   tPosition;
uniform sampler2D   tNormals;

uniform vec4        lightPosition;
uniform vec3        cameraPosition;

uniform mat4        u_modelMat;
uniform mat4        u_viewProjectionMat;
//vec3 lightPosition = vec3(0, 10, 0);

vec3 lightDiffuse = vec3(0.5, 0.5, 0.5);
vec4 lightSpecular = vec4(1.0, 1.0, 1.0, 200.0);

vec3 ambient = vec3(0.3, 0.3, 0.3);

uniform float nearPlane;
uniform float farPlane;
uniform float viewWidth;
uniform float viewHeight;
uniform vec2 texelSize;

in vec2 fragTexCoord0;

out vec4 outColor;

void main()
{

    vec3 normal = normalize(transpose(inverse(mat3(u_modelMat))) * texture2D(tNormals, fragTexCoord0.xy).rgb);

//	vec3 normal = texture2D(tNormals, fragTexCoord0.xy).rgb;
	vec3 color   = texture2D(tDiffuse, fragTexCoord0.xy).rgb;
	vec3 position = texture2D(tPosition, fragTexCoord0.xy).rgb;

	float dist = 50.0f / distance(position, lightPosition.xyz);
	//
	// lighting
	//
	vec3 lightVector = normalize(lightPosition.xyz - position);
    vec3 viewVector = normalize(position - cameraPosition);
    vec3 halfVector = normalize(lightVector + viewVector);

	float nl = dot(lightVector, normal);

	vec3 diffuse = lightDiffuse * max(0.0, nl);
	vec3 specular = vec3(0.0);

//	diffuse = vec3(1,1,1);

	if (nl > 0.0)
    specular = lightSpecular.rgb * pow(max(0.0, dot(halfVector, normal)), lightSpecular.w);

	outColor.rgb = 1.0 * (color.rgb * diffuse * dist + specular * dist);
	outColor.a = 1.0f;

//
// Testing - gives a full red square
//
        if (diffuse.x == 0)
            outColor.r = 1.0;

//        outColor.rgb = 1.0 * (color.rgb * diffuse * dist);
//    outColor.rgb = outColor.rgb + halfVector.xyz;
//    outColor.a = 1.0f;
}

vec3 normal = normalize(transpose(inverse(mat3(u_modelMat))) * texture2D(tNormals, fragTexCoord0.xy).rgb);

this has to be done in the geometry pass, your lighting pass does not know which fragment comes from what object ( u_modelMat is for a specific object )

your normal transformation was ok i think in post #3

anyway to find out why the dot product is always zero draw lightVector and normal as RGB an inspect the two resulting images (you can also make abs() to show negative values too ) ... if you can't conclude whats wrong post the output images smile.png

anyway to find out why the dot product is always zero draw lightVector and normal as RGB an inspect the two resulting images (you can also make abs() to show negative values too ) ... if you can't conclude whats wrong post the output images smile.png

Ok - understood - change reverted.

Here are the images:


    outColor.rgb = outColor.rgb + lightVector.xyz;

a9w8z6.png


    outColor.rgb = outColor.rgb + normal.xyz;

sfyyxv.png

This one is a changing solid color


    outColor.rgb = lightVector.xyz;

r1d285.png

I'm stumped.....

Ok - so I am using a new fragment shader - not producing light or specular, but at least I can see something with this one !

2ely4i9.png

I am still suspecting the normals - debugging the shader I can see a result visualising the surfaceToLight, surfaceToCamera and ambient vectors.

When adding the result of this line to the normal texture colors - there is no change to them ( meaning it is adding 0 values to the surfaceColor values)


float diffuseCoefficient = max(0.0, dot(normal, surfaceToLight));

Shader



#version 330

uniform mat4 u_modelMat;
uniform vec3 cameraPosition;

uniform float materialShininess;
uniform vec3 materialSpecularColor;

uniform sampler2D   tDiffuse;
uniform sampler2D   tPosition;
uniform sampler2D   tNormals;

in vec2 fragTexCoord0;

uniform struct Light
{
   vec3 position;
   vec3 intensities; //a.k.a the color of the light
   float attenuation;
   float ambientCoefficient;
} light;

out vec4 finalColor;

void main()
{

    vec3 normal =       texture(tNormals, fragTexCoord0.xy).rgb;
	vec3 surfaceColor = texture(tDiffuse, fragTexCoord0.xy).rgb;
	vec3 surfacePos =   texture(tPosition, fragTexCoord0.xy).rgb;

    vec3 surfaceToLight = normalize(light.position - surfacePos);
    vec3 surfaceToCamera = normalize(cameraPosition - surfacePos);

    //ambient
    vec3 ambient = light.ambientCoefficient * surfaceColor.rgb * light.intensities;

    //diffuse
    float diffuseCoefficient = max(0.0, dot(normal, surfaceToLight));
    vec3 diffuse = diffuseCoefficient * surfaceColor.rgb * light.intensities;

    //specular
    float specularCoefficient = 0.0;
    if(diffuseCoefficient > 0.0)
        specularCoefficient = pow(max(0.0, dot(surfaceToCamera, reflect(-surfaceToLight, normal))), materialShininess);
    vec3 specular = specularCoefficient * materialSpecularColor * light.intensities;

    //attenuation
    float distanceToLight = length(light.position - surfacePos);
    float attenuation = 1.0 / (1.0 + light.attenuation * pow(distanceToLight, 2));

    //linear color (color before gamma correction)
    vec3 linearColor = ambient + attenuation*(diffuse + specular);

    //final color (after gamma correction)
    vec3 gamma = vec3(1.0/2.2);

    finalColor = vec4(pow(linearColor, gamma), 0.5);
}

Just about to give it up, and just use forward rendering pipeline.....

EDIT: Here's the same shader working with the same scene but using Forward Rendering:

9acx9j.png

Since the other two pictures seem to look okay, I also suspect your normals - you stil can't see anything besides a black screen, when you do "finalColor = normal" ? That would mean your texture isn't properly bound.

Don't give up :) Could you provide the piece of code where you bind your gbuffer stuff?

If you can see more than a black screen by now, try to remap your normals from -1 to 1 instead of 0 to 1 by doing *2-1. Can't see if this could be the problem, give it a try.

Since the other two pictures seem to look okay, I also suspect your normals - you stil can't see anything besides a black screen, when you do "finalColor = normal" ? That would mean your texture isn't properly bound.

Don't give up smile.png Could you provide the piece of code where you bind your gbuffer stuff?

If you can see more than a black screen by now, try to remap your normals from -1 to 1 instead of 0 to 1 by doing *2-1. Can't see if this could be the problem, give it a try.

You God Damn legend !!! - fixed...

I had this when binding the textures:


    if (m_diffuseID > 0)
    {
        GL_CHECK(glActiveTexture(GL_TEXTURE0));
        GL_CHECK(glBindTexture(GL_TEXTURE_2D, gl_returnTexID(GBUFFER_TEXTURE_TYPE_DIFFUSE)));
        GL_CHECK(glUniform1i ( m_diffuseID, 0 ));
    }

    if (m_positionID > 0)
    {
        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE2, gl_returnTexID(GBUFFER_TEXTURE_TYPE_POSITION));
        GL_CHECK(glUniform1i ( m_positionID, 1 ));
    }

    if (m_normalsID > 0)
    {
        glActiveTexture(GL_TEXTURE2);
        glBindTexture(GL_TEXTURE3, gl_returnTexID(GBUFFER_TEXTURE_TYPE_NORMAL));
        GL_CHECK(glUniform1i ( m_normalsID, 2 ));
    }

Instead of this -


    if (m_diffuseID > 0)
    {
        GL_CHECK(glActiveTexture(GL_TEXTURE0));
        GL_CHECK(glBindTexture(GL_TEXTURE_2D, gl_returnTexID(GBUFFER_TEXTURE_TYPE_DIFFUSE)));
        GL_CHECK(glUniform1i ( m_diffuseID, 0 ));
    }

    if (m_positionID > 0)
    {
        GL_CHECK(glActiveTexture(GL_TEXTURE1));
        GL_CHECK(glBindTexture(GL_TEXTURE_2D, gl_returnTexID(GBUFFER_TEXTURE_TYPE_POSITION)));
        GL_CHECK(glUniform1i ( m_positionID, 1 ));
    }

    if (m_normalsID > 0)
    {
        GL_CHECK(glActiveTexture(GL_TEXTURE2));
        GL_CHECK(glBindTexture(GL_TEXTURE_2D, gl_returnTexID(GBUFFER_TEXTURE_TYPE_NORMAL)));
        GL_CHECK(glUniform1i ( m_normalsID, 2 ));
    }

You mentioning that the textures wasn't bound made me double check it, and add in the Macro checking for error codes - and sure enough, got a


[ GL_INVALID_ENUM: An unacceptable value is specified for an enumerated argument. ]
OpenGL Error: [ 187 ] - [ 1280 ] - [ lt_renderFullscreenQuad ]

I was using the GL_TEXTURE? instead of GL_TEXTURE_2D for the positions and the normals when trying to bind the textures.

Thank you so much.

Ah, now I can see it, too - hard to spot without code highlighting and with those damn OpenGL ints. The classic one :) You're welcome, share your progress when your engine surpasses UE4 :P

This topic is closed to new replies.

Advertisement