Welcome to the new Ogre Wiki!
If you haven't done so already, be sure to visit the Wiki Portal to read about how the wiki works. Especially the Ogre Wiki Overview page.
If you haven't done so already, be sure to visit the Wiki Portal to read about how the wiki works. Especially the Ogre Wiki Overview page.
MONSTER_2.cg
// Title: // MONSTER v2.0 // What is this? (for newcomers) // // Ever wrote a shader to support one particular setup, then another for another setup, // finally ending up with lots of shaders doing almost the same thing? // With #define-s and other preproc. directives, you can have "branching" in compile-time, // no need to slow the code down with conditional statements. // This also allows to write ONE shader code that is VERY close to optimal for many situations. // (Of course you need to recompile, but auto-generated versions are far easier this way.) // That is what you'll find here. // Check features below. // Notes: // - mainly for outdoor rendering, due to hemispherical lighting // (I wanted to have offset-mapping on every side of an object, which is quite // hard with directional lights, also they are too stark for an ambient outdoor // lighting) // - watch out for light positions rivalizing in distance from object's center: // a typical artifact source /closest light switches between 2 lights/ // - avoid crazy parameter combos // - notice how shader instruction count varies with shader complexity: // HLSL vertex: a full-blown vs is 58, while it is 38 with no normal mapping // and only 25 if light0-light2 are disabled also (hemi still on!) // BTW the minimal possible with MONSTER_2 is 4 instr. :D // HLSL pixel: full-blown gets to 73, won't compile, just as expected, // with no normal-mapping: 56. // with light0-light2 disabled (hemi and offset on): 29. // with just hemi (but fading, specular gloss, diffusetex): 12. // BTW the minimal is 2 instr. Pretty useless :D. // Limitations: // // As you will notice, many parameters are #define-s, for faster code, but if // real-time change is needed, they could be handed as uniforms as well. // (This applies inversely as well, so some parameters might be #defined instead of passing // them as uniforms, for faster code.) // // I also skipped the Ka, Kd, Ks, etc. constants present in many shaders, to // be used as coefficient when summing lighting parts, obviously for performance. // They can be 'faked' by properly adjusting the diffuse/gloss/AO textures' brighness // in an image editor. Add them if you wish, but they slow MONSTER down. // (Ka can be coded into AO map, Kd into diffuse map, Ks into gloss map) // They also contribute to instruction count, so beware. // // Also note that I placed no lighting restrictions on the user in this release. // It's a free for all. You decide what you want, but do not expect any compiler to // create you a shader that does *MAX* candy for *MAX* lights, given the instruction // count limits of ps_2_0 / arbfp1. // // No directional lights. Hemisphere is better, and leaving them makes syntax clearer too. // // One more thing: all lights have diffuse color = specular color as an optimization. // I believe it to be reasonable. // // I use 2 UV sets for now, 1 is for auto-generated AOmap, and the other is // for diffuse/normal maps. I you are skilled/lucky, you can go with 1 UV set as well. // Artist/model dependant. // Features: // // - improved lighting accuracy on low-poly meshes (2 tri quad for ex) // // - clearer code // // - 2 uv sets // // - faster attenuation // // - 1 hemispheric skylight with specular // /tune with: SKY_LIGHT_DIR, SKY_COLOR, GROUND_COLOR, SKY_EXPONENT/ // // - max. 3 local lights // /diffuse part, specular part, attenuation/ // // - per-pixel lighting / normal-mapping / offset-mapping // // - texturing: (diffuse + gloss), (normal + height), ambient occlusion // // - buggy distance-fadeout effect (someone should fix it, I can't get it right) // // - oFusion compatibility as usual // // - some typos, as usual :D // GLSL users: // // I do not compile this file as cg, because that way is not optimal. // Cg compiler sometimes generates longer code than HLSL. // If you need OpenGL, just change the definition in .material file to cg, // and the "target" word to "profiles" like: // // vertex_program Simple_Perpixel_Vert cg // .. // profiles vs_1_1 arbvp1 // //target vs_1_1 // // and of course do the same for fragment_program. // Or, for real-time support of both HLSL and GLSL, create 2 versions of MONSTER, // on with cg, one with HLSL, and use 2 techniques. // // BTW interesting thing is that GLSL code has only ~2/3 instructions. Dunno why. // This lets you have more complex version running with GLSL. // Want more lights? // // What to do if you want *MORE* dynamic lights affecting a single static mesh? // (obviously this works mainly for large meshes and small area, attenuated lights) // // 0. use deferred shading (needs a good card to be fast enough) // 1. use multiple passes (costy) // 2. use cheaper frag shader (looks less cool) or vertex-lights (ugly without tessellation) // 3. divide mesh to small parts in editor, bake it in static geometry, and you're done // (set up lots of lights swarming around the mesh, and each part will be affected by 2, // but the 2 closest, which will differ with the parts position) // ADDITIONAL DOCS: // // check earlier versions of MONSTER in Ogre WIKI, write mail, etc. // TODO: // // alpha-maps, environment-mapping, detail-texturing (both diffuse-map and offset-map) // volume-lighting, lightmaps, emissive-texture mapping, spot-lights, fog (volumetric?), // skinning, instancing, // ... // // Future dream-plan: // a demo app like GLSLdemo with texture/mesh browser, uniform sliders, and recompile option. // CONTACT: // // the name is guilderstein, email: forgamedev@yahoo.com, insert OGRE into subject please, // private message is better however // // That's all for now, go and shade :D //pre-defines for compiler, ignore them #define DIFFUSE_MAP 0 #define EXTRA_GLOSS_MAP 0 #define AMBIENT_OCC_MAP 0 #define NORMAL_MAP 0 #define EXTRA_HEIGHT_MAP 0 #define LIGHT_0 0 #define LIGHT_1 0 #define LIGHT_2 0 #define LIGHT_0_SPECULAR 0 #define LIGHT_1_SPECULAR 0 #define LIGHT_2_SPECULAR 0 #define HEMI_SKYLIGHT 0 #define HEMI_SKYLIGHT_SPECULAR 0 #define ATTENUATION 0 #define SPECULAR 0 #define SKY_LIGHT_DIR 0 #define GROUND_COLOR 0 #define SKY_COLOR 0 #define SKY_EXPONENT 0 #define EXPONENT_0 0 #define EXPONENT_1 0 #define EXPONENT_2 0 #define ATTEN_0 0 #define ATTEN_1 0 #define ATTEN_2 0 // general switches #define DISTANCE_FADING 0 //do not use fading, buggy #define TEXTURING 1 #define LIGHTING 1 #if TEXTURING #define DIFFUSE_MAP 1 #if DIFFUSE_MAP #define EXTRA_GLOSS_MAP 1 #endif #define AMBIENT_OCC_MAP 1 #if LIGHTING #define NORMAL_MAP 1 #if NORMAL_MAP #define EXTRA_HEIGHT_MAP 1 #endif #endif #endif // ATTEN values are ~ 1/light range, larger value -> stronger atten. #if LIGHTING #define ATTENUATION 1 #define SPECULAR 1 //diffuse in on if light is on #define LIGHT_0 1 #if SPECULAR #define LIGHT_0_SPECULAR 1 #endif #define LIGHT_1 1 #if SPECULAR #define LIGHT_1_SPECULAR 1 #endif #define LIGHT_2 1 #if SPECULAR #define LIGHT_2_SPECULAR 0 #endif #define HEMI_SKYLIGHT 1 #if SPECULAR #define HEMI_SKYLIGHT_SPECULAR 1 #endif #endif // per-light switches #if HEMI_SKYLIGHT #define SKY_LIGHT_DIR float3(0,1,0) #define GROUND_COLOR float3(0.1,0.1,0.1) #define SKY_COLOR float3(0.9,0.9,1.0) #if HEMI_SKYLIGHT_SPECULAR #define SKY_EXPONENT 8 #endif #endif #if LIGHT_0 #if LIGHT_0_SPECULAR #define EXPONENT_0 120 #endif #if ATTENUATION #define ATTEN_0 0.002 #endif #endif #if LIGHT_1 #if LIGHT_1_SPECULAR #define EXPONENT_1 120 #endif #if ATTENUATION #define ATTEN_1 0.002 #endif #endif #if LIGHT_2 #if LIGHT_2_SPECULAR #define EXPONENT_2 120 #endif #if ATTENUATION #define ATTEN_2 0.002 #endif #endif //diff: first texture (reg s0), uv1, UVs.xy, TEXCOORD0 //AO: second texture (reg s1), uv2, UVs.zw, TEXCOORD1 //norm: third texture (reg s2), uv1, UVs.xy, TEXCOORD0 ////////////////////////////////////////////////////////////////////////////////////////////// // VERTEX SHADER // ////////////////////////////////////////////////////////////////////////////////////////////// void MONSTER_vs ( /////////////////////// //VS INPUT PARAMETERS// /////////////////////// //texturing #if TEXTURING #if DIFFUSE_MAP float2 uv1 : TEXCOORD0, uniform float tile_factor, //tiles diffuse & normal maps via uv1 #elif NORMAL_MAP float2 uv1 : TEXCOORD0, uniform float tile_factor, //you can have only 1 on, and both on as well #endif //both normal and diffuse uses uv1 #if AMBIENT_OCC_MAP float2 uv2 : TEXCOORD1, //ao uses uv2 #endif out float4 oUVs : TEXCOORD1, //oUVs: oT1 //texturing means oUVs on, and both uv1 //and uv2 get passed in oUVs #if NORMAL_MAP float3 tangent : TEXCOORD2, #endif #endif //lighting #if LIGHTING //lightposX is in object space #if HEMI_SKYLIGHT #if NORMAL_MAP out float3 oSkyLightDir : TEXCOORD2, //oSkyDir: oT2 #endif //if no normal mapping is used, ps can use //the defined SKY_LIGHT_DIR otherwise we //need to transform it to tangent space #endif #if LIGHT_0 uniform float4 lightpos0, out float3 oLightDir0: TEXCOORD3, //oLDir0: oT3 #if LIGHT_0_SPECULAR out float3 oHalfAngle0: TEXCOORD6, //oHA0: oT6 #endif #endif #if LIGHT_1 uniform float4 lightpos1, out float3 oLightDir1: TEXCOORD4, //oLDir1: oT4 #if LIGHT_1_SPECULAR out float3 oHalfAngle1: TEXCOORD7, //oHA1: oT7 #endif #endif #if LIGHT_2 uniform float4 lightpos2, out float3 oLightDir2: TEXCOORD5, //oLDir2: oT5 #if LIGHT_2_SPECULAR out float3 oHalfAngle2: TEXCOORD0, #endif #endif //I don't have more oTX space for oHalfAngle2, //could interleave since many oTX uses only 3 float of 4, //but that is messy, and ps might overrun its instr. limit, too, //so LIGHT_2_SPECULAR is disabled by default #endif //eye/camera position in object space #if DISTANCE_FADING #if EXTRA_HEIGHT_MAP out float3 oEyeDir : TEXCOORD0, //oEye: oT0 //if offset mapping is used, oT0 is free, normal does not go to ps #endif out float4 oFadeColor : COLOR, uniform float fade_start_dist, uniform float fade_end_dist, uniform float3 eyepos, //we can have fading with offset mapping, and wo it #elif EXTRA_HEIGHT_MAP out float3 oEyeDir : TEXCOORD0, //oEye: oT0 uniform float3 eyepos, #elif SPECULAR uniform float3 eyepos, #endif //mixed basics #if !NORMAL_MAP #if LIGHTING out float3 oNorm: TEXCOORD0, //oNorm: oT0 #endif #endif float4 pos : POSITION, uniform float4x4 wvp, float3 norm : NORMAL, out float4 oPos : POSITION ) { /////////////////////// //VS CODE STARTS HERE// /////////////////////// //mixed basics oPos = mul(wvp, pos); #if !NORMAL_MAP #if LIGHTING oNorm = norm; #endif #endif #if DISTANCE_FADING float ratio = saturate(1-(distance(eyepos, pos.xyz)-fade_start_dist) / fade_end_dist); oFadeColor = float4(0,0,0,ratio); #endif //texturing #if TEXTURING oUVs = float4(0,0,0,0); #if DIFFUSE_MAP oUVs.xy = uv1 * tile_factor; #elif NORMAL_MAP oUVs.xy = uv1 * tile_factor; #endif #if AMBIENT_OCC_MAP oUVs.zw = uv2; #endif #endif //lighting & normal mapping #if LIGHTING #if NORMAL_MAP float3 binormal = cross(tangent, norm); float3x3 rotation = float3x3(tangent, binormal, norm); #if HEMI_SKYLIGHT oSkyLightDir = mul(rotation, SKY_LIGHT_DIR); #endif #if EXTRA_HEIGHT_MAP float3 EyeDir = eyepos - pos.xyz; EyeDir = mul(rotation, EyeDir); oEyeDir = EyeDir; #if SPECULAR float3 normed_EyeDir = normalize(EyeDir); #endif //if I pass a vector un-normalized to frag shader, //I get better interpolation, but normalization //is needed for halfvectors #elif SPECULAR float3 normed_EyeDir = normalize(eyepos - pos.xyz); //this allows having specular with only normal maps #endif #elif SPECULAR float3 normed_EyeDir = normalize(eyepos - pos.xyz); #endif #if LIGHT_0 #if ATTENUATION oLightDir0 = ATTEN_0 * (lightpos0 - pos).xyz; #else oLightDir0 = (lightpos0 - pos).xyz; #endif #if NORMAL_MAP oLightDir0 = mul(rotation, oLightDir0); #endif #if LIGHT_0_SPECULAR oHalfAngle0 = normalize(normalize(oLightDir0) + normed_EyeDir); #endif #endif #if LIGHT_1 #if ATTENUATION oLightDir1 = ATTEN_1 * (lightpos1 - pos).xyz; #else oLightDir1 = (lightpos1 - pos).xyz; #endif #if NORMAL_MAP oLightDir1 = mul(rotation, oLightDir1); #endif #if LIGHT_1_SPECULAR oHalfAngle1 = normalize(normalize(oLightDir1) + normed_EyeDir); #endif #endif #if LIGHT_2 #if ATTENUATION oLightDir2 = ATTEN_2 * (lightpos2 - pos).xyz; #else oLightDir2 = (lightpos2 - pos).xyz; #endif #if NORMAL_MAP oLightDir2 = mul(rotation, oLightDir2); #endif #if LIGHT_2_SPECULAR oHalfAngle2 = normalize(normalize(oLightDir2) + normed_EyeDir); #endif #endif #endif } // Note: instead of passing v2f the HalfAngle of each light, it (or reflection vector) could be calculated in fs! // oTx space vs. instr.count decision, and would make vs real fast! ////////////////////////////////////////////////////////////////////////////////////////////// // PIXEL SHADER // ////////////////////////////////////////////////////////////////////////////////////////////// void MONSTER_ps ( /////////////////////// //PS INPUT PARAMETERS// /////////////////////// //mixed basics #if !NORMAL_MAP #if LIGHTING float3 norm : TEXCOORD0, #endif #endif #if DISTANCE_FADING float opacity : COLOR, #endif //texturing #if TEXTURING float4 UVs : TEXCOORD1, //uv2 AND already scaled uv1 #if DIFFUSE_MAP uniform sampler2D DiffuseGlossMap : register(s0), //first texture #endif #if AMBIENT_OCC_MAP uniform sampler2D AoMap : register(s1), //second texture #endif #if NORMAL_MAP uniform sampler2D NormalHeightMap : register(s2), //third texture #endif #endif //lighting #if LIGHTING #if HEMI_SKYLIGHT #if NORMAL_MAP float3 TSkyLightDir : TEXCOORD2, #endif //again, if I do no normal mapping with hemi, I can go with //just using the #define-d SKY_LIGHT_DIR #endif #if LIGHT_0 uniform float3 lightColor0, float3 LightDir0 : TEXCOORD3, #if LIGHT_0_SPECULAR float3 HalfAngle0 : TEXCOORD6, #endif #endif #if LIGHT_1 uniform float3 lightColor1, float3 LightDir1 : TEXCOORD4, #if LIGHT_1_SPECULAR float3 HalfAngle1 : TEXCOORD7, #endif #endif #if LIGHT_2 uniform float3 lightColor2, float3 LightDir2 : TEXCOORD5, #if LIGHT_2_SPECULAR float3 HalfAngle2 : TEXCOORD0, #endif #endif #if EXTRA_HEIGHT_MAP uniform float2 scaleBias, float3 EyeDir : TEXCOORD0, //offset mapping needs no normal from vs, hence T0 is free #endif #endif //final color out float4 oColor : COLOR ) { /////////////////////// //PS CODE STARTS HERE// /////////////////////// //lighting and texturing #if LIGHTING #if !NORMAL_MAP float3 N = normalize(norm); #else #if EXTRA_HEIGHT_MAP EyeDir = normalize(EyeDir); //get offset uvs float height = tex2D(NormalHeightMap, UVs.xy).a; float2 newTexCoord = UVs.xy + EyeDir.xy * (height * scaleBias.x + scaleBias.y); float3 bumpVec = tex2D(NormalHeightMap, newTexCoord ).xyz * 2 - 1; //lookup with texcoord 0, and expand from range comressed #else float3 bumpVec = tex2D(NormalHeightMap, UVs.xy ).xyz * 2 -1; //same, but just normal-mapping #endif float3 N = normalize(bumpVec); #endif //okay, now we have a normal to do lighting //TODO/?/: send a HalfAngle_Sky from vs to get cheaper sky-specular, but that // would cost 1 additional texcoord, maybe taken from light_2 // /again, interleaving is an option, since many times I use only 3 // float values of texcoords to pass data vert2frag, but all texcoords // are float4 vectors; biggest problem is usage complexity/ //TODO: Issues with SKY_SPECULAR, now sky can only have spec. if offset is on #if HEMI_SKYLIGHT #if NORMAL_MAP float SKYdotN = dot(TSkyLightDir, N); #if EXTRA_HEIGHT_MAP #if HEMI_SKYLIGHT_SPECULAR float SKYdotH = dot(normalize(EyeDir + TSkyLightDir), N); float4 hemispec = pow(saturate(SKYdotH), SKY_EXPONENT); //try with lit()! #endif #endif #else float SKYdotN = dot(SKY_LIGHT_DIR, N); #endif float3 hemi = lerp(GROUND_COLOR, SKY_COLOR, 0.5 + 0.5 * SKYdotN); #endif #if LIGHT_0 LightDir0 = normalize(LightDir0); #if ATTENUATION float atten0 = saturate(1 - dot(LightDir0, LightDir0)); #endif float NdotL0 = dot(LightDir0, N); #if LIGHT_0_SPECULAR float NdotH0 = dot(HalfAngle0, N); float4 Lit0 = lit(NdotL0,NdotH0,EXPONENT_0); #endif #endif #if LIGHT_1 LightDir1 = normalize(LightDir1); #if ATTENUATION float atten1 = saturate(1 - dot(LightDir1, LightDir1)); #endif float NdotL1 = dot(LightDir1, N); #if LIGHT_1_SPECULAR float NdotH1 = dot(HalfAngle1, N); float4 Lit1 = lit(NdotL1,NdotH1,EXPONENT_1); #endif #endif #if LIGHT_2 LightDir2 = normalize(LightDir2); #if ATTENUATION float atten2 = saturate(1 - dot(LightDir2, LightDir2)); #endif float NdotL2 = dot(LightDir2, N); #if LIGHT_2_SPECULAR float NdotH2 = dot(float3(0,1,0), N); float4 Lit2 = lit(NdotL2,NdotH2,EXPONENT_2); #endif #endif #endif //color texturing #if TEXTURING #if EXTRA_HEIGHT_MAP #if EXTRA_GLOSS_MAP float4 diff = tex2D(DiffuseGlossMap, newTexCoord).xyzw; float3 diffusetex = diff.xyz; float gloss_power = diff.w; #elif DIFFUSE_MAP float3 diffusetex = tex2D(DiffuseGlossMap, newTexCoord).xyz; //lookup with offsetted texcoord 0 #endif #else #if EXTRA_GLOSS_MAP float4 diff = tex2D(DiffuseGlossMap, UVs.xy).xyzw; float3 diffusetex = diff.xyz; float gloss_power = diff.w; #elif DIFFUSE_MAP float3 diffusetex = tex2D(DiffuseGlossMap, UVs.xy).xyz; #endif //lookup with texcoord 0 #endif #if AMBIENT_OCC_MAP float occlusionfactor = tex2D(AoMap, UVs.zw).x; //lookup with texcoord 1 //Clumpsy solution, since it is a grayscale map anyway, //it could go into for ex. diffuse's alpha channel if no //specular gloss mapping is done //Though you will need to have either 2 lookup with the 2 uv sets on //the same texture, OR have 1 uv set for all maps, and go with 1 lookup #endif #endif //All is set up, now comes the most complex part, final color computation: //Though many variations are possible, I go with this one: // (at maximum, and in readable form) // // oColor = hemi * occlusionfactor //-> ambient lighting // + sky_color * sky_specular_coeff //-> ambient specular // + sum( atten[i] * lightcolor[i] * diffuse_coeff[i]) * diffusetex // + sum( atten[i] * lightcolor[i] * specular_coeff[i]) * gloss_power // //Try modulating (hemi * AO) also with diffusetex, etc. //Though syntax might seem chaotic, compiler does a great job in optimizing out float3(0,0,0) for ex. oColor = float4 ( float3(0,0,0) #if !LIGHTING #if TEXTURING #if DIFFUSE_MAP + diffusetex #if AMBIENT_OCC_MAP //just ao * occlusionfactor.xxx #endif #elif AMBIENT_OCC_MAP + occlusionfactor.xxx #endif //TODO: add normal map output as diffuse for debug purposes #endif #endif #if HEMI_SKYLIGHT + hemi #if AMBIENT_OCC_MAP * occlusionfactor #endif #if EXTRA_HEIGHT_MAP #if HEMI_SKYLIGHT_SPECULAR + hemispec #if EXTRA_GLOSS_MAP * gloss_power #endif #endif #endif #endif #if LIGHT_0 + lightColor0 * ( #if ATTENUATION atten0 * ( #if LIGHT_0_SPECULAR Lit0.y #if DIFFUSE_MAP * diffusetex #endif + Lit0.z #if EXTRA_GLOSS_MAP * gloss_power )) #else )) #endif #else NdotL0 )) #endif #elif LIGHT_0_SPECULAR //no atten, but spec and diff Lit0.y #if DIFFUSE_MAP * diffusetex #endif + Lit0.z #if EXTRA_GLOSS_MAP * gloss_power) #else ) #endif #else //no. atten, just diffuse NdotL0 #if DIFFUSE_MAP * diffusetex ) #else ) #endif #endif #endif #if LIGHT_1 + lightColor1 * ( #if ATTENUATION atten1 * ( #if LIGHT_1_SPECULAR Lit1.y #if DIFFUSE_MAP * diffusetex #endif + Lit1.z #if EXTRA_GLOSS_MAP * gloss_power )) #else )) #endif #else NdotL1 )) #endif #elif LIGHT_1_SPECULAR //no atten, but spec and diff Lit1.y #if DIFFUSE_MAP * diffusetex #endif + Lit1.z #if EXTRA_GLOSS_MAP * gloss_power) #else ) #endif #else //no. atten, just diffuse NdotL1 #if DIFFUSE_MAP * diffusetex ) #else ) #endif #endif #endif #if LIGHT_2 + lightColor2 * ( #if ATTENUATION atten2 * ( #if LIGHT_2_SPECULAR Lit2.y #if DIFFUSE_MAP * diffusetex #endif + Lit2.z #if EXTRA_GLOSS_MAP * gloss_power )) #else )) #endif #else NdotL2 )) #endif #elif LIGHT_2_SPECULAR //no atten, but spec and diff Lit2.y #if DIFFUSE_MAP * diffusetex #endif + Lit2.z #if EXTRA_GLOSS_MAP * gloss_power) #else ) #endif #else //no. atten, just diffuse NdotL2 #if DIFFUSE_MAP * diffusetex ) #else ) #endif #endif #endif , #if DISTANCE_FADING opacity #else 1 #endif ); }
Contributors to this page: jacmoe
.
Page last modified on Monday 28 of June, 2010 19:52:14 GMT by jacmoe
.
The content on this page is licensed under the terms of the Creative Commons Attribution-ShareAlike License.
As an exception, any source code contributed within the content is released into the Public Domain.
Sidebar
Search box
Online users
72
online users

