Per-pixel lightning

Just tested some per-pixel lightning shaders in jME today and thought it might be worth showing.



These are the maps I used:







And this is three screenshots of it in action.




Wow, looks sweet! Congrats! Any chance to make it public ? :smiley:

can you make  a video to show of the effect better? :slight_smile:

Cool! You're not just going to tease us with that are you? You're going to post the shaders and a test case aren't you?

Wow… it's quite simple to make those shaders and/or search on the forum and internet for them. (spec/normal are quite popular so they are everywhere).

Here's what I use for terrain:



uniform int n_lights;

varying vec3 vLightVector[gl_MaxLights];

#ifdef FIRST_SPEC
   varying vec3 vHalfAngle;
#else
   varying vec3 vHalfAngle[gl_MaxLights];
#endif

void main(){
   gl_Position = ftransform();
   gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;

   vec3 normal = normalize(gl_Normal);
   vec3 binormal;

   vec3 c1 = cross(normal, vec3(0.0, 1.0, 0.0));
   vec3 c2 = cross(normal, vec3(0.0, 0.0, 1.0));
   
   if(length(c1)>length(c2)){
      binormal = c1;
   }else{
        binormal = c2;
    }

   vec3 tangent = cross(normal, binormal);
  
   vec3 vNormal    = gl_NormalMatrix * normal;
   vec3 vBinormal  = gl_NormalMatrix * binormal;
   vec3 vTangent   = gl_NormalMatrix * tangent;

   vec3 eye_Vertex = (gl_ModelViewMatrix * gl_Vertex).xyz;

   for (int i = 0; i < 4; i++){
      if (i < n_lights){
         vec3 temp_light_vector = gl_LightSource[i].position.xyz - eye_Vertex;

         vLightVector[i].x = dot( temp_light_vector, vTangent );
         vLightVector[i].y = dot( temp_light_vector, vBinormal );
         vLightVector[i].z = dot( temp_light_vector, vNormal );

         #ifndef FIRST_SPEC
             vec3 halfTemp = gl_LightSource[i].halfVector.xyz;

             vHalfAngle[i].x = dot(halfTemp, vTangent);
             vHalfAngle[i].y = dot(halfTemp, vBinormal);
             vHalfAngle[i].z = dot(halfTemp, vNormal);
         #endif
      }
   }

   #ifdef FIRST_SPEC
   vec3 halfTemp = gl_LightSource[i].halfVector.xyz;

   vHalfAngle.x = dot(halfTemp, vTangent);
   vHalfAngle.y = dot(halfTemp, vBinormal);
   vHalfAngle.z = dot(halfTemp, vNormal);
   #endif
}



uniform int n_lights;

uniform sampler2D bump_map;
uniform sampler2D base_map;
uniform sampler2D spec_map;

varying vec3 vLightVector[gl_MaxLights];

#ifdef FIRST_SPEC
   varying vec3 vHalfAngle;
#else
   varying vec3 vHalfAngle[gl_MaxLights];
#endif

void main(void){
   vec2 vTexCoord = gl_TexCoord[0].xy;

   vec4 base     = texture2D( base_map, vTexCoord );
   vec3 bump     = normalize( ( texture2D( bump_map, vTexCoord ).xyz * 2.0 ) - 1.0 );
   vec3 specular = texture2D( spec_map, vTexCoord ).xyz;

   #ifdef FIRST_SPEC
       float n_dot_h = max(0.0, dot(bump, normalize(vHalfAngle) ) );
       vec3 sum_specular = pow(n_dot_h, gl_FrontMaterial.shininess ) * gl_LightSource[0].specular.xyz;;
   #else
       vec3 sum_specular = vec3(0.0);
   #endif

   vec3 sum_diffuse = vec3(0.0);

   for (int i = 0; i < 4; i++){
       if (i < n_lights){
          sum_diffuse += max(0.0, dot(bump, normalize( vLightVector[i] )) ) * gl_LightSource[i].diffuse.xyz;;

          #ifndef FIRST_SPEC
          float n_dot_h = max(0.0, dot(bump, normalize(vHalfAngle[i]) ) );
          sum_specular += pow(n_dot_h, gl_FrontMaterial.shininess ) * gl_LightSource[i].specular.xyz;
          #endif
       }
   }

   vec3 color0 = (vec3(0.1) + sum_diffuse) * base.xyz + sum_specular * specular;
   gl_FragColor = vec4(color0.xyz, base.a);
}



It generates tangent/binormal so it wont work on some meshes. It's quite simple to edit it to get them from vertex attributes though.
Haladria said:

Just tested some per-pixel lightning shaders in jME today and thought it might be worth showing.


plz plz plz ... shaders and testcase  :)

I'd love to get something like that going.

thx in advance,
Andy

i'm in need of a spec/normal/diffuse-shader that doesn't ignore the distance to the light source and works with more than just one. is there a simple one out there somewhere?

You can use the one I posted with some small changes. Just loop thru all ( 8 ) lightsources with a for loop and for the point lights adjust the effect from the light with the opengl light attenuation formula:


att = 1.0 / (gl_LightSource[0].constantAttenuation + gl_LightSource[0].linearAttenuation * dist + gl_LightSource[0].quadraticAttenuation * dist * dist);

there is similar code in the jme TestNormalmap and normalmap.vert/.frag

I've missed that one totally, probably because it was located in loader instead of glsl directory. Seems like the shader is reading the tangent from gl_Color but where is that value set in the test case?

Modified version of the 1 light Parallax shader from jmetest to support pointlight with attenuation and ‘heightmap’ texture:



http://imagebin.org/28719





//attribute vec3 modelTangent;
//attribute vec3 modelBinormal;

varying vec3 viewDirection;
varying vec3 lightDirection;
varying float att;

void main(void)
{
   /* Transform vertices and pass on texture coordinates */
   gl_Position = ftransform();
   gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
   
   /* Transform vertex into viewspace */
   vec4 vertexViewSpace = gl_ModelViewMatrix * gl_Vertex;
   
   /* Get view and light directions in viewspace */
   vec3 localViewDirection = -vertexViewSpace.xyz;

   vec3 localLightDist = gl_LightSource[0].position.xyz - vertexViewSpace.xyz;
   
   float dist = length(localLightDist.xyz);
   att = 1.0 / (gl_LightSource[0].constantAttenuation + gl_LightSource[0].linearAttenuation * dist + gl_LightSource[0].quadraticAttenuation * dist * dist);   
   
   vec3 localLightDirection = normalize(localLightDist);
   
   /* Calculate tangent info - stored in colorbuffer */
   vec3 normal = gl_NormalMatrix * gl_Normal;
   vec3 tangent = gl_NormalMatrix * (gl_Color.xyz*2.0-1.0);
   vec3 binormal = cross( tangent, normal );
   
   /* Transform localViewDirection into texture space */
   viewDirection.x = dot( tangent, localViewDirection );
   viewDirection.y = dot( binormal, localViewDirection );
   viewDirection.z = dot( normal, localViewDirection );

   /* Transform localLightDirection into texture space */
   lightDirection.x = dot( tangent, localLightDirection );
   lightDirection.y = dot( binormal, localLightDirection );
   lightDirection.z = dot( normal, localLightDirection );
}




uniform sampler2D baseMap;
uniform sampler2D normalMap;
uniform sampler2D specularMap;
uniform sampler2D heightMap;

varying vec3 viewDirection;
varying vec3 lightDirection;
varying float att;

uniform float heightValue;

void main(void)
{
   /* Normalize view and light directions(need per-pixel normalized length) */
   vec3 normalizedViewDirection = normalize( viewDirection );
   vec3 normalizedLightDirection = normalize( lightDirection );

   /* Extract colors from baseMap and specularMap */
//   vec4  baseColor      = texture2D( baseMap, gl_TexCoord[0].xy );
   vec4  specularColor  = texture2D( specularMap, gl_TexCoord[0].xy );
   vec4  heightColor  = texture2D( heightMap, gl_TexCoord[0].xy );

   float height = length(heightColor.xyz) * heightValue - heightValue * 0.5;
   vec2 newTexcoord = gl_TexCoord[0].xy - normalizedViewDirection.xy * height;
   vec4 baseColor = texture2D( baseMap, newTexcoord );

   
   /* Calculate diffuse - Extract and expand normal and calculate dot angle to lightdirection */
   vec3  normal = normalize( ( texture2D( normalMap, gl_TexCoord[0].xy ).xyz * 2.0 ) - 1.0 );
   float NDotL = dot( normal, normalizedLightDirection );
      
   /* Calculate specular - Calculate reflection vector and dot angle to viewdirection  */
   vec3  reflection = normalize( ( ( 2.0 * normal ) * NDotL ) - normalizedLightDirection );
   float RDotV = max( 0.0, dot( reflection, normalizedViewDirection ) );
            
   /* Sum up lighting models with OpenGL provided light/material properties */
   vec4  totalAmbient   = ( gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient ) * baseColor;
   vec4  totalDiffuse   = gl_FrontLightProduct[0].diffuse * max( 0.0, NDotL ) * baseColor;
   vec4  totalSpecular  = gl_FrontLightProduct[0].specular * specularColor * ( pow( RDotV, gl_FrontMaterial.shininess ) );

   /* Set final pixel color as sum of lighting models */
   vec4 attMul = vec4(att,att,att,1.0);
    gl_FragColor = totalAmbient * attMul + totalDiffuse * attMul + totalSpecular * attMul;
}

Thanks timong! Looks good.