[SOLVED] Custom Lighting Shader Effected by Camera

Hi there! I’m slowly learning GLSL, and I’m currently following a tutorial and creating a Phong light shader.

The illumination is working, so if I create a light node and attach it to the root node, the model is illuminated. However, I have hit a stumbling block with camera movement.

When I rotate the default camera (the one you start with in the Basic Game template) - akin to looking around - the light on the model shifts ever so slightly. I have compared it to jME’s Lighting shader and it does not exhibit the same issue.

I am not sure whether this is the way it is supposed to work, and I would appreciate it if anyone could shed some light on this. Thank you! :slight_smile:

For reference, the code is below:

.j3md file:

MaterialDef Solid {

        //This is the complete list of user defined uniforms to be used in the
        //shaders	
        MaterialParameters {
                Vector3 Color
        }

        Technique {

                LightMode MultiPass

                //This is where the vertex and fragment shader files are
                //specified
                VertexShader GLSL100:   Shaders/solid.vert
                FragmentShader GLSL100: Shaders/solid.frag

                //This is where you specify which global uniform you need for your
                //shaders
                WorldParameters {
                        NormalMatrix
                        WorldViewMatrix
                        WorldViewProjectionMatrix
                }
        }

}

.vert file:

//the global uniform World view projection matrix
//(more on global uniforms below)
uniform mat3 g_NormalMatrix;
uniform mat4 g_WorldViewMatrix;
uniform mat4 g_WorldViewProjectionMatrix;

//The attribute inPosition is the Object space position of the vertex
attribute vec3 inPosition;
attribute vec3 inNormal;

varying vec3 outNormal;
varying vec4 outEye;

varying vec4 copy;

void main(){
    //Transformation of the object space coordinate to projection space
    //coordinates.
    //- gl_Position is the standard GLSL variable holding projection space
    //position. It must be filled in the vertex shader
    //- To convert position we multiply the worldViewProjectionMatrix by
    //by the position vector.
    //The multiplication must be done in this order.

    outNormal = normalize(g_NormalMatrix * inNormal);
    outEye = -normalize(g_WorldViewProjectionMatrix * vec4(inPosition, 0.0));

    gl_Position = g_WorldViewProjectionMatrix * vec4(inPosition, 1.0);

}

.frag file:

uniform vec3 m_Color;
uniform vec4 g_LightPosition;
uniform vec4 g_AmbientLightColor;

uniform mat4 g_WorldViewMatrix;

varying vec3 outNormal;
varying vec4 outEye;

void main(){

    vec4 diffuse = vec4(m_Color, 1.0);
    vec4 ambient = g_AmbientLightColor;
    vec4 specular = vec4(0.25, 0.25, 0.25, 1.0);
    float shininess = 10.0;

    vec4 light = normalize(g_LightPosition);
    vec3 direction = -normalize(light.xyz);

    // set the specular term to black
    vec4 spec = vec4(0.0, 0.0, 0.0, 0.0);

    // normalize both input vectors
    vec3 n = normalize(outNormal);
    vec3 e = normalize(vec3(outEye));

    float intensity = max(dot(n, direction), 0.0);

    // if the vertex is lit compute the specular color
    if (intensity > 0.0) {
        // compute the half vector
        vec3 h = normalize(direction + e);
        // compute the specular term into spec
        float intSpec = max(dot(h, n), 0.0);
        spec = specular * pow(intSpec, shininess);
    }

    gl_FragColor = max(pow(intensity * diffuse + spec, 1), ambient);

}

Images for reference:

Before

After

Notice how on the right side of the object, the shadow is much more prevalent in the second picture. That’s my problem :confused:

A small update on this issue. I have continued looking for help online, and it seems like it is a case of the light following the camera (such as http://stackoverflow.com/questions/5571534/opengl-light-source-that-follows-the-camera). In fact, in addition to the pictures I uploaded before, the light will also seem as if it is emanating from the camera.

Seeing as the light moves with the camera, I figured it is a case of he light not being transformed to the projection. I multiplied the light etc… with all of the different matrices to no avail.

I have found a few solutions online, but they mostly use the light’s position (which is not available with directional light), or did not work (such as normalizing sources, which I tried). Any help would be greatly appreciated - this is driving me crazy! :frowning:

outEye is a vector computed in projection space, while “direction” is in world space.
when you do

 vec3 h = normalize(direction + e);

it makes no sense, because the verctors are not in the same space. I’m pretty sure this is the source of your issue.
Compute outEye in world space in the vert shader:

outEye = -normalize(g_WorldMatrix * vec4(inPosition, 0.0));

and see if it works better

Thanks, I see where you’re coming from - I’ve been trying to look for vectors that are not in the same space. However, that didn’t solve the problem. It’s still the same as before.

We can’t see that new code so we really can’t comment.

Oops, sorry!

.vert:

uniform mat3 g_NormalMatrix;
uniform mat4 g_WorldMatrix;
uniform mat4 g_WorldViewProjectionMatrix;

uniform vec4 g_LightPosition;
uniform vec4 g_LightColor;

attribute vec3 inPosition;
attribute vec3 inNormal;

varying vec3 outNormal;
varying vec4 outEye;
varying vec3 outPos;
varying vec4 outLight;

void main(){
    outNormal = normalize(g_NormalMatrix * inNormal);
    outEye = -normalize(g_WorldMatrix * vec4(inPosition, 0.0));

    gl_Position = g_WorldViewProjectionMatrix * vec4(inPosition, 1.0);
    outPos = gl_Position;

    outLight = g_LightPosition;

}

.frag:

uniform vec3 m_Color;
uniform vec4 g_LightPosition;
uniform vec4 g_AmbientLightColor;

varying vec3 outNormal;
varying vec4 outEye;
varying vec3 outPos;
varying vec4 outLight;

void main(){

    vec4 diffuse = vec4(m_Color, 1.0);
    vec4 ambient = g_AmbientLightColor;
    vec4 specular = vec4(0.25, 0.25, 0.25, 1.0);
    float shininess = 10.0;

    vec3 light = normalize(outLight.xyz);
    vec3 direction = -normalize(light.xyz);

    vec4 spec = vec4(0.0, 0.0, 0.0, 0.0);

    vec3 n = normalize(outNormal);
    vec3 e = normalize(vec3(outEye));

    float intensity = max(dot(n, direction), 0.0);

    if (intensity > 0.0) {
        vec3 h = normalize(direction + e);
        float intSpec = max(dot(h, n), 0.0);
        spec = specular * pow(intSpec, shininess);
    }

    gl_FragColor = max(intensity * diffuse + spec, ambient);

}

Thanks for the help by the way :slight_smile:

PS Just so you know, this change actually messes up the specular

this

will result in a normal in view space.
use the WorlMatrix too

EDIT: Though you have to cheat a bit

 outNormal = normalize(g_WorldMatrix * vec4(inNormal,0.0)).xyz;
1 Like

Thanks! That’s exactly what I did. Specular still a bit messed up, but nothing I can’t handle :slight_smile: Thanks mate! :slight_smile:

EDIT:

Just in case anyone encounters the same problem, or wants a quick start into a lighting shader, using content from Lighthouse3D and jME’s wiki:

.vert:

uniform mat3 g_NormalMatrix;
uniform mat4 g_WorldMatrix;
uniform mat4 g_WorldViewProjectionMatrix;

uniform vec4 g_LightPosition;
uniform vec4 g_LightColor;

attribute vec3 inPosition;
attribute vec3 inNormal;

varying vec3 outNormal;
varying vec4 outEye;
varying vec3 outPos;
varying vec4 outLight;

void main(){
    outNormal = normalize(g_WorldMatrix * vec4(inNormal, 1.0)).xyz;
    outEye = -normalize(g_WorldMatrix * vec4(inPosition, 0.0));

    gl_Position = g_WorldViewProjectionMatrix * vec4(inPosition, 1.0);
    outPos = gl_Position;

    outLight = g_LightPosition;
}

.frag:

uniform vec3 m_Color;
uniform vec4 g_LightPosition;
uniform vec4 g_AmbientLightColor;
uniform vec3 g_CameraPosition;

uniform mat3 g_NormalMatrix;

varying vec3 outNormal;
varying vec4 outEye;
varying vec3 outPos;
varying vec4 outLight;

void main(){

    vec4 diffuse = vec4(m_Color, 1.0);
    vec4 ambient = g_AmbientLightColor;
    vec4 specular = vec4(1.0, 1.0, 1.0, 1.0);
    float shininess = 0.1;

    vec3 light = normalize(outLight.xyz);
    vec3 direction = -normalize(light.xyz);

    vec4 spec = vec4(0.0, 0.0, 0.0, 0.0);

    vec3 n = normalize(outNormal);
    vec3 e = normalize(vec3(outEye));

    float intensity = max(dot(n, direction), 0.0);

    if (intensity > 0.0) {
        vec3 h = normalize(direction + e);
        float intSpec = max(dot(h, n), 0.0);
        spec = specular * pow(intSpec, shininess);
    }

    gl_FragColor = max(intensity * diffuse + spec, ambient);

}

As an addendum to my previous post:

There was a small flaw which resulted in the directional light being rendered as a point light.

I haven’t wrapped my head around all the math involving GLSL yet, but I figured that it had to do with the fact that normals and the half-vector (eye) were being translated to the World space. The updated shader is as follows, and it seems like it’s working correctly now (including the specular):

.vert:

uniform mat3 g_NormalMatrix;
uniform mat4 g_WorldMatrix;
uniform mat4 g_WorldViewProjectionMatrix;

uniform vec4 g_LightPosition;
uniform vec4 g_LightColor;

attribute vec3 inPosition;
attribute vec3 inNormal;

varying vec3 outNormal;
varying vec4 outEye;
varying vec4 outLight;

void main(){
    outNormal = normalize(vec4(inNormal, 1.0)).xyz;
    outEye = -normalize(g_WorldViewProjectionMatrix * vec4(inPosition, 0.0));

    gl_Position = g_WorldViewProjectionMatrix * vec4(inPosition, 1.0);

    outLight = g_LightPosition;
}

.frag:

uniform vec3 m_Color;
uniform vec4 g_LightPosition;
uniform vec4 g_AmbientLightColor;

uniform mat3 g_NormalMatrix;
uniform mat3 g_NormalMatrixInverse;
uniform mat4 g_WorldMatrix;
uniform mat4 g_WorldMatrixInverse;

varying vec3 outNormal;
varying vec4 outEye;
varying vec4 outLight;

void main(){

    vec4 diffuse = vec4(m_Color, 1.0);
    vec4 ambient = g_AmbientLightColor;
    vec4 specular = vec4(0.25, 0.25, 0.25, 1.0);
    float shininess = 10.0;

    vec3 light = normalize(outLight.xyz);
    vec3 direction = -normalize(light);

    vec4 spec = vec4(0.0, 0.0, 0.0, 0.0);

    vec3 n = normalize(outNormal).xyz;
    vec3 e = normalize(vec3(outEye));

    float intensity = max(dot(n, direction), 0.0);

    if (intensity > 0.0) {
        vec3 h = normalize(direction + e);
        float intSpec = max(dot(h, n), 0.0);
        spec = specular * pow(intSpec, shininess);
    }

    gl_FragColor = max(intensity * diffuse + spec, ambient);

}
1 Like