Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 3 of 3

Thread: Translating a light's "screen coordinate" in the fragment shader

  1. #1
    Newbie Newbie
    Join Date
    Feb 2014
    Posts
    2

    Question Translating a light's "screen coordinate" in the fragment shader

    I have a 2D sprite-based scene and I'm implementing lights that hover just above the 2D plane. Each sprite has a normal map, so I have a fragment shader that shades each sprite according to the lights' position and color.

    I pass the lights' coordinates in via a uniform - the coordinates are in exact screen pixel coordinates (e.g. 900, 600), so I apply my ortho matrix to them to get the normalized position. My problem is that the "radius" of the lights is affected by the size of the screen/window, and I'm not sure why. I want the lights to be the same size no matter what.

    I have removed all but the necessary code and posted it on an interactive GLSL editor - you can modify the window size to see the undesired effect (sorry, can't post URLs?): glsl.heroku.com/e#14464.0

    I'll also post the code here:
    Code :
    uniform vec2 resolution;
     
    void main(void)
    {
    	//orthographic matrix
    	mat4 ortho_matrix = mat4(
            2.0/resolution.x, 0, 0, 0,
            0, 2.0/-resolution.y, 0, 0,
            0, 0, -1, 0,
            -1, 1, 0, 1
        	);
     
    	//surface normal of the 2D plane (looking straight down)
    	vec3 surface_normal = normalize(mix(vec3(-1), vec3(1), vec3(0.5, 0.5, 1.0)));
     
    	//screen position of the light
    	vec2 light_screen_pos = vec2(650, 150);
     
    	//translate light's position to normalized coordinates
    	//the z value makes sure it is slightly above the 2D plane
    	vec4 light_ortho_pos = ortho_matrix * vec4(light_screen_pos, -0.03, 1.0);
     
    	//calculate the light for this fragment
     	vec3 light_direction = light_ortho_pos.xyz - vec3(gl_FragCoord.x / resolution.x, gl_FragCoord.y / resolution.y, 0);
    	float dist = length(light_direction);
    	light_direction = normalize(light_direction);
    	vec3 light = clamp(dot(surface_normal, light_direction), 0.0, 1.0) * vec3(0.5, 0.5, 0.5);
    	vec3 cel_light = step(0.15, (light.r + light.g + light.b) / 3.0) * light;
     
    	gl_FragColor = vec4(pow(light + cel_light, vec3(0.4545)), 1.0);
    }

    Thanks for any advice or insight.

  2. #2
    Intern Contributor Brokenmind's Avatar
    Join Date
    Feb 2014
    Location
    Aachen / Germany
    Posts
    71
    You should not delimit the light's radius according to the screen size (although that would make more sense, I admit). In your code above, you compute the direction (on which some calculations depend) like this:
    Code :
    vec3 light_direction = light_ortho_pos.xyz - vec3(gl_FragCoord.x / resolution.x, gl_FragCoord.y / resolution.y, 0);
    This makes the light dependent on the screen size. I changed the code (nice tool by the way) to the following:
    Code :
    vec3 light_direction = light_ortho_pos.xyz - vec3(gl_FragCoord.x / 100.0, gl_FragCoord.y / 100.0, 0);
    This at least made the light a circle which appeared to be independent from the size. Maybe this effect occurs due to some double balancing of the aspect ratio, but I'm not sure. I hope this helps

  3. #3
    Newbie Newbie
    Join Date
    Feb 2014
    Posts
    2
    Quote Originally Posted by Brokenmind View Post
    You should not delimit the light's radius according to the screen size (although that would make more sense, I admit). In your code above, you compute the direction (on which some calculations depend) like this:
    Code :
    vec3 light_direction = light_ortho_pos.xyz - vec3(gl_FragCoord.x / resolution.x, gl_FragCoord.y / resolution.y, 0);
    This makes the light dependent on the screen size. I changed the code (nice tool by the way) to the following:
    Code :
    vec3 light_direction = light_ortho_pos.xyz - vec3(gl_FragCoord.x / 100.0, gl_FragCoord.y / 100.0, 0);
    This at least made the light a circle which appeared to be independent from the size. Maybe this effect occurs due to some double balancing of the aspect ratio, but I'm not sure. I hope this helps
    Thank you. After some more experimentation, I realized that the light direction needed to be scaled according to the screen resolution. I just did something like:

    Code :
    light_direction *= vec3(resolution.x / brightness, resolution.y / brightness, 1.0);

    That makes the light a circle and keeps it independent of screen size.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •