2
votes

I'm trying a simple lighting shader which supports point and directional lights. Directional lights are done, but I'm struggling with the point lights. How can I get the vertex world position to calculate the light direction?? I'm using Libgdx and a sprite batcher, and also an orthographic camera. For now I've just made a (dirty) hack passing the position of the current sprite to be rendered (center position) to the fragment shader, and its working. For what I've read in glsl I could get the modelview matrix and multiply it with the current vertex position (with libgdx I guess that would be the "a_position" attribute) but I was unable to do it...

Vertex shader:

attribute vec4 a_position;
attribute vec2 a_texCoord0;
uniform mat4 u_projTrans;
varying vec3 position;

void main() {
    vTexCoord = a_texCoord0;
    position = a_position.xyz;
    gl_Position =  u_projTrans * a_position;
}

Fragment shader:

varying vec2 vTexCoord;
varying vec3 position;

uniform sampler2D u_texture0;   //diffuse map
uniform sampler2D u_texture1;   //normal map
uniform vec4 light_pos[2];
uniform vec4 light_color[2];

//uniform vec3 spritepos; // "Hack" variable with the sprite position...

void main() {
float attenFactor;
vec4 lightAmbientDiffuse= vec4(0.0,0.0,0.0,0.0);
vec4 lightSpecular      = vec4(0.0,0.0,0.0,0.0);
vec3 ambient_light      = vec3(0.1,0.1,0.1);
vec3 eyeDir             = vec3(0.0,0.0,-1.0);
vec3 lightDir;

float shininess = 10.0;

int totalLights = 2;
vec3 normal = normalize((texture2D(u_texture1, vTexCoord.st).rgb * 2.0) - 1.0);

vec3 pos = position;
// pos = spriteposition; //this is what I do that makes it work
for (int i=0; i<totalLights; i++) {
        if (light_pos[i].w != 0.0) {
            float dist = distance(light_pos[i].xyz, pos);
            float constantAttenuation = 0.01;
            float linearAttenuation = 0.2;
            float quadraticAttenuation = 0.5;
            attenFactor = 1.0 / (constantAttenuation + linearAttenuation * dist + quadraticAttenuation * dist * dist );
            lightDir = normalize(light_pos[i].xyz - pos);
        }       
        else { // Directional light
            attenFactor = 1.0;
            lightDir = normalize(light_pos[i].xyz);
        }

        lightAmbientDiffuse += vec4(ambient_light * attenFactor, 0.0);      
        lightAmbientDiffuse += vec4(light_color[i].rgb * max(dot(normal, lightDir), 0.0) * attenFactor, 1.0);

        vec3 r = normalize(reflect(-lightDir, normal));
        lightSpecular += light_color[i] * pow(max(dot(r, -eyeDir), 0.0), shininess) * attenFactor;
    }

    vec4 texColor = texture2D(u_texture0, vTexCoord.st);
    gl_FragColor  = texColor * (lightAmbientDiffuse) + lightSpecular;
 }

The pos variable is the uniform I send from my application.

1
If you're using an orthogonal camera, the a_position is the world-position of the current vertex. I think you might confuse it with fragment-position. So you should define another varying vector, vec2 might be enough in your case, because you're working in a 2Dspace. Then you'll be able to pass the position interpolated to your fragmentshader. varying vec2 v_position; before the main-function. Inside the mainfunction: v_position = a_position. - TheWhiteLlama
@TheWhiteLlama I tried that, declaring a varying vec3 v_position, and then assigning the world position: v_position = a_position.xyz;. But that way it looks that the point light is just on the left of my sprites, and moving them (my sprites) doesn't change the illumination. I thought that way I would have the light world position, and also the vertex world position, but it's not working :S I guess I'm missing something... - Istarion
can you pls add the full fragment-shader and the full vertex shader of your program? There are still some parts missing, that could be relevant for the solution :) - TheWhiteLlama
@TheWhiteLlama Yeah of course, sorry I thought that could be enough. You can see I'm using a normal texture, I don't use the vertex normals... - Istarion
how do you pass in your uniform vectors for the point lights? Would also be interesting! - TheWhiteLlama

1 Answers

0
votes

Okay this is how it goes. I made you a libgdx project that will work fine in IntelliJ https://dl.dropboxusercontent.com/u/13497625/stackoverflow/StackOverFlow_Pointlights.zip

open the project, run the build.gradle. set in your run-configurations your working-directory to the android/assets folder. EDIT: oh and maybe don't forget to specify the right path to your android sdk aswell!

Probably there was something wrong with your uniform passing, etc. I changed your shader a little bit, because there were some varyings missing in the fragmentshader that were existing in the vertexshader.

Another thing is, you don't have to use .st at the end of your texturecoord-vector, because it is already a vec2 and does not have to be casted to another size. I think the convention would be to use .uv instead of .st anyway!

a tip for naming the variables:

v_name for varyings
u_name for uniforms
a_name for attributes
m_name for values in the main function

good luck with your project!