History: PerPixel Lighting
Preview of version: 9
For now, just quick and dirty ๐
Table of contents
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 PerPixel II link.
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 ๐
the name is: guilderstein
contact: send message in Ogre, mailto: forgamedev at yahoo.com, AND insert OGRE is subject
Links to my other shaders
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