PerPixel Lighting         A simple, everytime accurate per-pixel cg shader for Ogre, right out of box

For now, just quick and dirty :-)

Intro

Hello!

Because I know how hard it was for me to get into this shader topic, I decided to post some here. First of all, the basics. The following lines will give you a simple, everytime accurate per-pixel cg shader for Ogre, right out of box.
Efficiency is traded for quality this time. If you want more FPS, things get more complicate. See links at the bottom of this page.

EDIT: I have added support for textures with this simple perpixel method. The same code can be used with the more advanced perpixel lighting from this tutorial, perpixel lighting part II.

Result:

Screen of tank model with Simple_Perpixel as shader and material

Shader: file ARNOLD.cg

//The simplest (EXACT, see remarks) perpixel lighting I could do is:
 //(though it still supports ambient and specular terms, so it could still be simpler :)
 
 //Note: lighting is done in object-space, in the frag shader
 
 void Simple_Perpixel_Vert(
                        //ADDED BY EUGEN - support for texture with the per pixel lighting
                        float2 uv : TEXCOORD0,
                         float4 position : POSITION, 
                         float3 normal   : NORMAL,
                 //vert shader input
 
                         uniform float4 lightPosition,
             uniform float3 eyePosition,
                 //both in object space
 
                         uniform float4x4 worldviewproj, 
             
                         out float4 oClipPos    : POSITION,
                 //pass to clipping
 
             out float4 oPos    : TEXCOORD0,
             out float3 oNorm    : TEXCOORD1,
                         out float4 oLightPos    : TEXCOORD2,            
             out float3 oEyePos    : TEXCOORD3,
                        //ADDED BY EUGEN - support for texture with the per pixel lighting
                        out float2 oUv       : TEXCOORD4
                 //pass to frag shader
              ) 
 { 
     oClipPos = mul(worldviewproj, position); 
 
     oPos = position;
     oNorm     = normal; 
     oLightPos = lightPosition;
     oEyePos = eyePosition;
        //ADDED BY EUGEN - support for texture with the per pixel lighting
        oUv = uv;
 
         //Remarks:
 
         //since we want exact calculations in every case,
         //calculate light and eye directions in frag shader,
         //don't let the rasterizer interpolate them from here
 
         //more costy than doing directions here, per-vertex, but
         //produces accurate lighting in VERY low tessellation cases,
         //light close to surface (for.ex. closer than poly size)
 } 
 
 
 void Simple_PerPixel_Frag(
 
                  float4 pos         : TEXCOORD0,
             float3 normal        : TEXCOORD1, 
              float4 lightpos        : TEXCOORD2,
             float3 eyepos        : TEXCOORD3,
                        //ADDED BY EUGEN - support for texture with the per pixel lighting
                        float2 uv        : TEXCOORD4,
 
             uniform float4 lightDiffuse,
             uniform float4 lightSpecular,
             uniform float exponent,
 
             uniform float4 ambient,
             uniform sampler2D texture,
 
                         out float4 oColor : COLOR 
 ) 
 {
     float3 N = normalize(normal);
 
         //Remarks: 
 
         //we could do this normalize() in vert shader, or skip it
         //see some info at lighthouse3d GLSL explanations    
 
     float3 EyeDir = normalize(eyepos - pos.xyz);
     float3 LightDir = normalize(lightpos.xyz -  (pos * lightpos.w));
     float3 HalfAngle = normalize(LightDir + EyeDir);
 
     float NdotL = dot(LightDir, N);
     float NdotH = dot(HalfAngle, N);
     float4 Lit = lit(NdotL,NdotH,exponent);
 
     //cg docs say using their lit function is the fastest
 
        //ADDED BY EUGEN - support for texture with the per pixel lighting
        float3 textColour = expand(tex2D(texture, uv).xyz);
 
        //ADDED BY EUGEN - support for texture with the per pixel lighting
        oColor = lightDiffuse * Lit.y + lightSpecular * Lit.z + ambient + float4(textColour, 1);
 }

Material: file ARNOLD.material

vertex_program Simple_Perpixel_Vert cg 
 { 
       source ARNOLD.cg 
 
       default_params 
       { 
                  param_named_auto lightPosition light_position_object_space 0
         param_named_auto eyePosition camera_position_object_space
 
                  param_named_auto worldviewproj worldviewproj_matrix
       } 
 
       entry_point Simple_Perpixel_Vert 
       profiles vs_1_1 arbvp1 
 } 
 
 fragment_program Simple_PerPixel_Frag cg 
 { 
       source ARNOLD.cg 
 
       default_params 
       {
                  param_named_auto lightDiffuse light_diffuse_colour 0
         param_named_auto lightSpecular light_specular_colour 0
 
         param_named exponent float 127
             //VERY high value, to produce large highlights
 
         param_named ambient float4 0.0 0.0 0.0 1.0
             //faint environment lighting
       } 
 
       entry_point Simple_PerPixel_Frag
       profiles ps_2_0 arbfp1
 }
 
 material Simple_Perpixel 
 { 
       technique 
       {
         // Base ambient pass, needing to avoid transparent artifacts
         // at for.ex. knot mesh
 //        pass
 //        {    
 //            vertex_program_ref Ambient
 //            {
 //            }
 //        }
         pass 
         { 
             // do this for each light
 //            iteration once_per_light
 //            scene_blend add
 
                     vertex_program_ref Simple_Perpixel_Vert
                     { 
                     } 
 
                     fragment_program_ref Simple_PerPixel_Frag
                     { 
                     } 
                        //EUGEN - support for textures with the perpixel lighting
                        texture_unit
                        {
                                //use your own texture here, this is just an example
                                texture totem.dds
                        }
              } 
       } 
 }
 
 //(uncomment lines to add multipass multilight support: plus you need Ambient vert shader  
 // from below, plus take out the ”+ambient” part of final color line in Simple_PerPixel_Frag)
 // And perhaps the file parser will complain if perpixel material is listed before ambient stuff
 // so you might list ambient things in the start of this file.
 
 void Ambient_vp(
         float4 position : POSITION,
 
           out float4 oPosition : POSITION,
           out float4 colour    : COLOR,
 
           uniform float4x4 worldViewProj,
           uniform float4 ambient)
 {
     oPosition = mul(worldViewProj, position);
     colour = ambient;
 }
 
 vertex_program Ambient cg
 {
     source ARNOLD.cg
 
     default_params
     {
         param_named_auto worldViewProj worldviewproj_matrix
         param_named ambient float4 0.2 0.2 0.2 1.0
     }
 
     entry_point Ambient_vp
     profiles vs_1_1 arbvp1
 }

Closing

Don't ask why ARNOLD :-)
Forum username is: guilderstein
Contact: Send message in Ogre forums or mailto: forgamedev at yahoo.com AND insert "OGRE" in subject

PerPixel Lighting II - More adv. per-pixel method, lotsa theory
PerPixel Lighting With Offset(Parallax) Mapping - For nice bumps, with specular
The Monster - All-in-one deity, working with oFusion


Alias: PerPixel_Lighting