Skip to main content
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

Copy to clipboard
//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

Copy to clipboard
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