bump sphere environment normal mapping shader

Vertex shader

#version 150
in vec4 gxl3d_Position;
in vec4 gxl3d_Normal;

out VertexData
{
  vec4 Position;
  vec4 OPosition;
  vec4 Normal;
  vec4 ONormal;
  vec4 UV;
} vertex;

// GLSL Hacker automatic uniforms
uniform mat4 gxl3d_ModelViewProjectionMatrix;
uniform mat4 gxl3d_ModelViewMatrix;

void main()
{
  vec4 P = gxl3d_ModelViewMatrix * gxl3d_Position;
  vertex.OPosition = P;
  gl_Position = gxl3d_ModelViewProjectionMatrix * gxl3d_Position;
  vertex.UV = normalize(P);
  vertex.Position = gxl3d_Position;
  vertex.Normal = gxl3d_ModelViewMatrix * gxl3d_Normal;
  vertex.ONormal = gxl3d_Normal;
}

Fragment shader

#version 150

in VertexData
{
  vec4 Position;
  vec4 OPosition;
  vec4 Normal;
  vec4 ONormal;
  vec4 UV;
} vertex;

uniform sampler2D textureMap;
uniform sampler2D normalMap;
uniform vec3 color;
uniform float normalScale;
uniform float texScale;
uniform float useSSS;
uniform float useScreen;

float random(vec3 scale,float seed)
{return fract(sin(dot(gl_FragCoord.xyz+seed,scale))*43758.5453+seed);}

out vec4 FragColor;

void main() 
{
  vec3 vNormal = vertex.Normal.xyz;
  vec3 vONormal = vertex.ONormal.xyz;
  vec4 vPosition = vertex.Position;
  vec4 vOPosition = vertex.OPosition;
  vec3 vU = vertex.UV.xyz;

  vec3 n = normalize( vONormal.xyz );
  vec3 blend_weights = abs( n );
  blend_weights = ( blend_weights - 0.2 ) * 7.;  
  blend_weights = max( blend_weights, 0. );
  blend_weights /= (blend_weights.x + blend_weights.y + blend_weights.z);

  vec2 coord1 = vPosition.yz * texScale;
  vec2 coord2 = vPosition.zx * texScale;
  vec2 coord3 = vPosition.xy * texScale;

  vec3 bump1 = texture2D(normalMap, coord1).rgb;  
  vec3 bump2 = texture2D(normalMap, coord2).rgb;  
  vec3 bump3 = texture2D(normalMap, coord3).rgb; 

  vec3 blended_bump = bump1 * blend_weights.xxx +  
                      bump2 * blend_weights.yyy +  
                      bump3 * blend_weights.zzz;

  vec3 tanX = vec3(vNormal.x, -vNormal.z, vNormal.y);
  vec3 tanY = vec3(vNormal.z, vNormal.y, -vNormal.x);
  vec3 tanZ = vec3(-vNormal.y, vNormal.x, vNormal.z);
  vec3 blended_tangent = tanX * blend_weights.xxx +  
                         tanY * blend_weights.yyy +  
                         tanZ * blend_weights.zzz; 

  vec3 normalTex = blended_bump * 2.0 - 1.0;
  normalTex.xy *= normalScale;
  normalTex.y *= -1.;
  normalTex = normalize( normalTex );
  mat3 tsb = mat3( normalize( blended_tangent ), 
                   normalize( cross( vNormal, blended_tangent ) ), 
                   normalize( vNormal ) );
  vec3 finalNormal = tsb * normalTex;

  vec3 r = reflect( normalize( vU ), normalize( finalNormal ) );
  float m = 2.0 * sqrt( r.x * r.x + r.y * r.y + ( r.z + 1.0 ) * ( r.z + 1.0 ) );
  vec2 calculatedNormal = vec2( r.x / m + 0.5,  r.y / m + 0.5 );

  vec3 base = texture2D( textureMap, calculatedNormal ).rgb;

  float rim = 1.75 * max( 0., abs( dot( normalize( vNormal ), 
                         normalize( -vOPosition.xyz ) ) ) );
  base += useSSS * color * ( 1. - .75 * rim );
  base += ( 1. - useSSS ) * 10. * base * color * clamp( 1. - rim, 0., .15 );

  if (useScreen == 1.) 
  {
    base = vec3( 1. ) - ( vec3( 1. ) - base ) * ( vec3( 1. ) - base );
  }

  float nn = .05 * random( vec3( 1. ), length( gl_FragCoord ) );
  base += vec3( nn );
    
  FragColor = vec4( base.rgb, 1. );
}