[Custom GLSL Shader] Normal map does not show up when using multiple lights

I have a custom GLSL shader that I made by combining different shaders from the Blender wikibooks site. It does exactly what I want to to except for the lack of surface normals. I’ve gone of the code several times, but I’m unable to determine the cause. Maybe GLSL is unable to handle multiple lights with a normal map, but the default (non game) renderer has no problems with them. Any advice on how to fix the problem?

import bgefrom bge.logic import getOuterScaleColor//these functions are defined in an initialization script that runs before this one
from bge.logic import getBellyScaleColor
from bge.logic import getEyeColor
cont = bge.logic.getCurrentController()


own = cont.owner


VertexShader = """
attribute vec4 tangent;


varying vec4 position; 
            // position of the vertex (and fragment) in view space 
//varying vec3 varyingNormalDirection; 
            // surface normal vector in view space
varying vec4 texCoords; // the texture coordinates


varying mat3 localSurface2View;


void main()
{                              
    position = gl_ModelViewMatrix * gl_Vertex; 
    //varyingNormalDirection = 
               normalize(gl_NormalMatrix * gl_Normal);
    localSurface2View[0] = normalize(gl_NormalMatrix 
               * tangent.xyz);
    localSurface2View[2] = 
               normalize(gl_NormalMatrix * gl_Normal);
    localSurface2View[1] = normalize(
               cross(localSurface2View[2], localSurface2View[0])
               * tangent.w);


    texCoords = gl_MultiTexCoord0;
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}"""


FragmentShader = """
const int numberOfLights = gl_MaxLights; 
            // up to gl_MaxLights (often 8)


varying mat3 localSurface2View;


varying vec4 position; 
            // position of the vertex (and fragment) in view space 
//varying vec3 varyingNormalDirection; 
            // surface normal vector in view space
uniform sampler2D bgTexture;
uniform sampler2D guideTexture;


uniform sampler2D specularity;




uniform sampler2D normalMap;


uniform vec3 skinColor1;
uniform vec3 skinColor2;
uniform vec3 eyeColor;


varying vec4 texCoords;


//varying vec4 bg_tex_at_loc;


void main()
{
    vec4 bg_tex_at_loc = texture2D(bgTexture, texCoords.xy);
    vec4 guide_tex_at_loc = texture2D(guideTexture, texCoords.xy);
    
    vec4 prim_spec_at_loc = texture2D(specularity, texCoords.xy);
    


    
   
    
    vec3 localTexture = vec3(bg_tex_at_loc) * (1.0 - guide_tex_at_loc.g) + (skinColor1 * guide_tex_at_loc.g);
    
    localTexture = localTexture * (1.0 - guide_tex_at_loc.r) + (skinColor2 * guide_tex_at_loc.r);
    
    localTexture = localTexture * (1.0 - guide_tex_at_loc.b) + (eyeColor * guide_tex_at_loc.b);
    


    
    float shineLocalTexture = (prim_spec_at_loc.r);
    
    vec4 encodedNormal = texture2D(normalMap, vec2(texCoords)); 
    
    vec3 localCoords = 
               normalize(vec3(2.0, 2.0, 1.0) * vec3(encodedNormal) 
               - vec3(1.0, 1.0, 0.0)); 
               // constants depend on encoding
    
    
    vec3 normalDirection = normalize(localSurface2View * localCoords);
    
    vec3 viewDirection = -normalize(vec3(position)); 
    vec3 lightDirection = vec3(0.0, 0.0, 0.0);
    float attenuation = 1.0;
 
            // initialize total lighting with ambient lighting
    vec3 totalLighting = vec3(gl_LightModel.ambient) 
               * localTexture;
 
    for (int index = 0; index < numberOfLights; index++) //For loop for dealing with multiple lights
               // for all light sources
    {
        if (0.0 == gl_LightSource[index].position.w) 
                  // directional light?
        {
            attenuation = 1.0; // no attenuation
            lightDirection = 
                     normalize(vec3(gl_LightSource[index].position));
        } 
        if (0.0 != gl_LightSource[index].position.w 
        && gl_LightSource[index].spotCutoff > 90.0) 
                  // point light? 
        {
            vec3 positionToLightSource = 
                     vec3(gl_LightSource[index].position - position);
            float distance = length(positionToLightSource);
            attenuation = 1.0 / distance; // linear attenuation                    
            lightDirection = normalize(positionToLightSource);
        }
        if (0.0 != gl_LightSource[index].position.w 
        && gl_LightSource[index].spotCutoff <= 90.0) 
                 // spotlight?
        {
            vec3 positionToLightSource = 
                     vec3(gl_LightSource[index].position - position);
            float distance = length(positionToLightSource);
            attenuation = 1.0 / distance; // linear attenuation 
            lightDirection = normalize(positionToLightSource);
 
            float clampedCosine = max(0.0, dot(-lightDirection, 
                  gl_LightSource[index].spotDirection));
            if (clampedCosine < gl_LightSource[index].spotCosCutoff) 
                     // outside of spotlight cone?
            {
                attenuation = 0.0;
            }
            else
            {
                attenuation = attenuation * pow(clampedCosine, 
                        gl_LightSource[index].spotExponent);   
            }
        }
 
        vec3 diffuseReflection = attenuation 
                  * vec3(gl_LightSource[index].diffuse)
                  * localTexture
                  * max(0.0, dot(normalDirection, lightDirection));
 
        vec3 specularReflection;
        if (dot(normalDirection, lightDirection) < 0.0) 
                  // light source on the wrong side?
        {
                  specularReflection = vec3(0.0, 0.0, 0.0); 
                     // no specular reflection
        }
        else // light source on the right side
        {
            specularReflection = attenuation 
                     * vec3(gl_LightSource[index].specular) 
                     * (shineLocalTexture * vec3(gl_FrontMaterial.specular))
                     * pow(max(0.0, dot(reflect(-lightDirection, 
                     normalDirection), viewDirection)),  
                     gl_FrontMaterial.shininess);
        }
 
        totalLighting = totalLighting + diffuseReflection 
                  + specularReflection;
    }
    gl_FragColor = vec4(totalLighting, 1.0);
}"""




mesh = own.meshes[0]
for mat in mesh.materials:
    shader = mat.getShader()
    if shader != None:
        if not shader.isValid():
            shader.setSource(VertexShader, FragmentShader, 1)
        shader.setSampler('guideTexture', 0)
        shader.setSampler('bgTexture', 1)
        shader.setSampler('specularity', 2)
        shader.setSampler('normalMap', 3)
        shader.setUniformfv('skinColor1', getOuterScaleColor())
        shader.setUniformfv('skinColor2', getBellyScaleColor())
        shader.setUniformfv('eyeColor', getEyeColor())

Attachments

GLSLNormalMap.blend (784 KB)

I don’t know if it fix your problem but it looks like that it does, in the console is an error you have forgotten to import bge in your second python script, so some of the uniforms values for the shader are not right.

Odd, I got no console error when I ran it, and when I did add

import bge

to my initialization script the normal map doesn’t show.

Yess thats crazy because I test it and it works.

Here is the console error

And after I add import bge normalmap works.
On the left without shader so it’s the bge material without specularity and with normalmap and on the right is with shader and there are also dark spots on the material which should be the normalmap


Hi,

  1. in older Blender’s versions, you do not had to import bge manually (it was done automatically). So I’m wondering what Blender’s version do you use…

  2. I’m not sure but the error mentionned by Maujoe can be avoided (IMHO, it’s more clear if you do this) if you transform your Text script into a module (Text.py and in shader you do: from Text import *)

  3. … (Sorry I said bullsh… I had the impression that the normal maps were “shifted” but it was just an impression :o )

  4. I don’t know if it’s normal, but UV was not selected in texture panel for 1 texture…

Hope something might help. http://www.pasteall.org/blend/39301

I’m using 2.73. I tried running the blend that you posted, but the normal map refuses to work. Everything else about the shader works, however.

And I think I just figured it out. I should have put:

mesh = own.meshes[0]for mat in mesh.materials:
    shader = mat.getShader()
    if shader != None:
        if not shader.isValid():
            shader.setSource(VertexShader, FragmentShader, 1)
            shader.setAttrib(bge.logic.SHD_TANGENT)
            shader.setSampler('guideTexture', 0)
            shader.setSampler('bgTexture', 1)
            shader.setSampler('specularity', 2)
            shader.setSampler('normalMap', 3)
            shader.setUniformfv('skinColor1', getOuterScaleColor())
            shader.setUniformfv('skinColor2', getBellyScaleColor())
            shader.setUniformfv('eyeColor', getEyeColor())

at the end of the Shader script. The indignity of ones work being undone by a failure to add enough tabs…