Jump to content
  • Advertisement
Sign in to follow this  

Blinn-Phong rendering problems

This topic is 2834 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts


I'm trying to implement Blinn-Phong shading in a deferred renderer.
I have two problems:
-attenuation doesn't seem to work...
-specular highlight isn't where it should be

I'm working with viewspace data only so in the fragment shader in the lighting part everything is in viewspace.

so here are the shaders:

//vertex shader for full-screen quad
#version 410

//projection and modelview matrices
uniform mat4 m4_p, m4_mv;

in vec4 v4_vertex;
in vec2 v2_texture;

smooth out vec2 v2_texture_coords;
out vec4 position;

void main()
v2_texture_coords = v2_texture;
position = m4_mv * v4_vertex;
gl_Position = m4_p * m4_mv * v4_vertex;

//pixel shader for full-screen quad
#version 410

uniform sampler2D texture5; //albedo in RGBA
uniform sampler2D texture6; //normals in RG16F, encoded with spheremap encoding
uniform sampler2D texture7; //linear depth in R32F

uniform vec4 view_pos; //position of the camera in viewspace
uniform vec4 light_pos; //light position in viewspace
uniform vec4 light_diffuse_color; //light color
uniform float light_specular_power; //specular power (shininess)
uniform float light_radius; //light radius

const float near = -1.0f; //near plane distance
const float far = -10000.0f; //far plane distance

smooth in vec2 v2_texture_coords; //incoming interpolated texture coordinates
in vec4 position; //incoming viewspace full-screen quad position

out vec4 v4_color; //outgoing color

//spheremap decoder function
vec3 decode_normals_spheremap(vec4 n)
vec4 nn = n * vec4(2.0, 2.0, 0.0, 0.0) + vec4(-1.0, -1.0, 1.0, -1.0);
float l = dot(nn.xyz, -nn.xyw);
nn.z = l;
nn.xy *= sqrt(l);
return nn.xyz * 2.0 + vec3(0.0, 0.0, -1.0);

//linear depth decoder function
vec3 decode_linear_depth(vec4 linear_depth, vec4 in_position)
return vec3(in_position.xy * (far / in_position.z), far) * linear_depth.x;

void main()
//grab the raw data
vec4 raw_albedo = texture(texture5, v2_texture_coords);
vec4 raw_normal = texture(texture6, v2_texture_coords);
vec4 raw_depth = texture(texture7, v2_texture_coords);

//if a pixel doesn't have normals, then ignore lighting for it
if(length(raw_normal.xy) == 0.0)
v4_color = raw_albedo;

//decode normals and depth --> viewspace normals & position
raw_normal.xyz = decode_normals_spheremap(raw_normal);
raw_depth.xyz = decode_linear_depth(raw_depth, position);

* Light calculations

v4_color = vec4(vec3(0.0), 1.0);
vec3 light_dir = light_pos.xyz - raw_depth.xyz; //light vector from current viewspace pos to pointlight center
float distance = length(light_dir); //length of light vector

//don't do lighting for pixels outside the pointlight
/*if(distance > light_radius)

light_dir /= distance; //normalize the light vector
vec3 view_dir = normalize(view_pos.xyz - raw_depth.xyz); //view direction, am I calculating correctly?
vec3 half_vector = (light_dir + view_dir) * 0.5; //half vector, normalized

//attenuation explained here: http://imdoingitwrong.wordpress.com/tag/glsl/
float attenuation = 1.0 / pow((max(distance - light_radius, 0.0) / light_radius + 1.0), 2.0);

float n_dot_l = max(dot(raw_normal.xyz, light_dir), 0.0); //diffuse term
v4_color.xyz += light_diffuse_color.xyz * n_dot_l * attenuation; //add diffuse light

float n_dot_h = pow(max(dot(raw_normal.xyz, half_vector), 0.0), light_specular_power); //specular term
v4_color.xyz += light_diffuse_color.xyz * n_dot_h * attenuation; //add specular light

v4_color *= raw_albedo; //multiply by albedo

//for debugging, to see where's the light radius
if (distance > light_radius - 0.02 && distance < light_radius + 0.02)
v4_color = vec4(1.0, 0.0, 0.0, 1.0);

In the first picture only the diffuse term is shown, and you can see that it goes further than the light radius. In the second one only the specular term is shown and you can see that it's not in the middle of the red circle, where it supposed to be.

I solved the specular highlight problem (the problem was that I used to pass view_dir instead of view_pos, see below), but the attenuation still doesn't work properly.
I forgot to include how I'm passing the matrices and light parameters to the shader:

glDisable( GL_DEPTH_TEST );
fs_quad.pass_m4x4( objs::get()->ppl.get_projection_matrix(), "m4_p" );
fs_quad.pass_m4x4( objs::get()->ppl.get_model_view_matrix(), "m4_mv" );
fs_quad.pass_int( 5, "texture5" );
fs_quad.pass_int( 6, "texture6" );
fs_quad.pass_int( 7, "texture7" );
objs::get()->mvm.push_matrix(objs::get()->cam.get_camera_matrix( false ));
fs_quad.pass_vec4( objs::get()->ppl.get_model_view_matrix() * objs::get()->mm.import_vec3f_into_vec4f(objs::get()->cam.pos), "view_pos");
fs_quad.pass_vec4( objs::get()->ppl.get_model_view_matrix() * mymath::vec4f(0.0f, 5.0f, 4.0f, 1.0f), "light_pos");
fs_quad.pass_vec4(mymath::vec4f(1.0f, 1.0f, 1.0f, 1.0f), "light_diffuse_color");
fs_quad.pass_float(10.0f, "light_radius");
fs_quad.pass_float(3.0f, "light_specular_power");
glEnable( GL_DEPTH_TEST );

any idea what I'm doing wrong?

Best regards,

Share this post

Link to post
Share on other sites


I got it fixed I just had to change the attenuation from:
float attenuation = 1.0 / pow((max(distance - light_radius, 0.0) / light_radius + 1.0), 2.0);

float attenuation = 1.0 / pow(distance / light_radius + 1.0, 2.0);

Share this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!