Trouble understanding diffuse lighting shader

Hi,

I’ve been poking around at various (read, nearly every) tutorial and book I can find on writing shaders. I’m having a bit of a hard time getting a foothold. Most of my problems stem from the way the shader program behaves compared to how I would expect it to behave.

The shader code is here - http://pastebin.com/eaDs6uP9

My problem is with the three commented lines for lightDir. My understanding is that the position field of the light structure is its direction (since it’s a directional light). If I force it to vec3(-1, -1, -1) it works as intended. I had a line written in this exact spot that I thought the light was coming from inside the screen pointed towards the user, because what I actually observed was that it was coming from the user towards the sphere, and I had added a -1 * lightDir because it was necessary to make the forced vec3(-1, -1, -1) work. But now it doesn’t even do that. It doesn’t seem consistent to me, the way this behaves.

I feel like I’ve run out of permutations to throw this into the editor. It’s gone on that long. The orange book is no help because its ‘easy’ example is to jump into specular, bump mapped procedurally generated goddamn bricks. I just want a diffuse shader, then maybe a texture atlas-ing example, and I can get on my way. In fact, while I was writing this, I went back to check something - and I get completely different behavior when I uncomment the vec3(-1.0, -1.0, -1.0) lightDir line. There’s no reason for that to happen, I isolated it to specific behaviors.

Has anyone seen this issue before? If so, how did you fix it?

Thanks,
-Alex

Edit - forgot the j3md

MaterialDef My MaterialDef {

MaterialParameters {
   Vector4 Color;
}

Technique {
    VertexShader GLSL120:   Shaders/TestVertexShader.vert
    FragmentShader GLSL120: Shaders/TestFragmentShader.frag

    WorldParameters {
        WorldViewProjectionMatrix
        WorldViewMatrix
        NormalMatrix\
    }
}

}

I think I changed inNormal to Normal, which was what caused the black screen.

The specific issue I’m having is here -

// These two lines should be identical
// Because I set the direction of my sun (the only light in the scene)
// to -1.0, -1.0, -1.0
vec3 lightDir = -1.0 * vec3(gl_LightSource[0].position);
//vec3 lightDir = -1.0 * vec3(-1.0, -1.0, -1.0);

// Java code
DirectionalLight sun = new DirectionalLight();
sun.setColor(ColorRGBA.White);
sun.setDirection(new Vector3f(-1, -1, -1).normalizeLocal());
rootNode.addLight(sun);

However the above is not true. According to the JME3 shaders document, https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:jme3_shaders the gl_LightSource[0].position should be the direction of the directionalLight. It’s not, since the vec3(-1, -1, -1) works and the other doesn’t. Why is this?

-Alex

JME does not use things like: gl_LightSource

It has its own.

You can look at the existing lighting shader to see how it is done there. That’s how I learned: fork lighting, break it, fix it, try again.

@acampbell said: I think I changed inNormal to Normal, which was what caused the black screen.

The specific issue I’m having is here -

// These two lines should be identical
// Because I set the direction of my sun (the only light in the scene)
// to -1.0, -1.0, -1.0
vec3 lightDir = -1.0 * vec3(gl_LightSource[0].position);
//vec3 lightDir = -1.0 * vec3(-1.0, -1.0, -1.0);

// Java code
DirectionalLight sun = new DirectionalLight();
sun.setColor(ColorRGBA.White);
sun.setDirection(new Vector3f(-1, -1, -1).normalizeLocal());
rootNode.addLight(sun);

However the above is not true. According to the JME3 shaders document, https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:jme3_shaders the gl_LightSource[0].position should be the direction of the directionalLight. It’s not. What gives?

-Alex

g_LightPosition != gl_LightSource[0].position

Moreover, JME encodes the lighting parameters differently depending on what type of light it is. I suggest you look at Lighting.vert very carefully.

@acampbell said: According to the JME3 shaders document, https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:jme3_shaders the gl_LightSource[0].position should be the direction of the directionalLight.
uh? where do you see that? I never wrote that. Listen to @pspeed, we don't use gl_LightSource[0].

Our system does one shader pass for each light and light information are passed as global parameters (g_Something).
you have :
g_LightDirection : light direction
g_LightColor : light color
g_LightPosition : ligth position
g_AmbientLightColor : ambient light color

Several things to know though :

  • g_AmbientLightColor is separated from g_LightColor because ambient is resolved with the first non ambient light pass (to avoid having an extra pass for ambient)
  • g_LightColor alpha channel is fed with an int representing the light type : 0 for directional, 1 for point, 2 for spot
    Directional lights :
    There is a huge inconsistency for directional light (kept for the sake of backward compatibility), the light direction in world space is passed in the g_LightPosition uniform.
    gLightDirection is set to 0,0,0,0.
    Point lights :
    No inconsistency here g_LightPosition contains the light position in world space. The alpha channel is fed with the inverse radius of the light (inverse to avoid having to compute 1/radius for every pixel which is expensive in the shader world).
    gLightDirection is set to 0,0,0,0. since the point light emit in all direction.
    Spot lights :
    g_LightPosition contains the light position in world space. The alpha channel is fed with the inverse range of the light (same principle as the radius for point lights).
    g_LightDirection contains the light direction in view space. Mind the “in view space”. that’s done to save some varying because some low hardware supports only 32 float varyings.
    the alpha channel of g_LightDirection is fed with the packed values of the cosine of the inner and outer angles of the spot lights.
    I won’t go into the detail of how it’s packed, but here is the way to unpack them :
    [java]
    float innerAngleCos = floor(g_LightDirection.w) * 0.001;
    float outerAngleCos = fract(g_LightDirection.w);
    [/java]

the relevant code for all this is here : Google Code Archive - Long-term storage for Google Code Project Hosting.

@nehon When porting lighting to shader nodes can we fix that inconsistency- since shader nodes aren’t backwardsly compatible anyway… ?

If we do it’s gonna break backward compatibility of those who have their own forked lighting shader.
What we could do though is feed both the g_LightDirection and g_LightPosition with the direction and use the consistent variable in the new shader node.