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.
All_In_Wonder.cg
//TITLE: // // FAST_MONSTER_SHADER //DESCRIPTION: // lots of tuneable params, in 1-pass, less accurate (see PURE THEORY) //TODO: // // Alpha testing, specular level in diffuse alpha, environment lookup, ambient occlusion map, // 2-texture using cheap and nice detail texturing (even for offset-maps), etc. could be still // added, happy tweaking pioneers out there. // Though less fast, multipass solution would allow for more instructions in 1 pass, if all // the goodies listed above won't fit into 64 instuction limit of ps2.0 . //WARNING: PURE THEORY :) // // This version has 1 defect, which is precision: // Non-linear interpolation of per-vertex lightdir and eyedir(->halfangle) in vertex // shader causes distortions when light is about poly-size distance from a large poly (or closer) // but this is unperceptible when cam is farther (eg. in most cases). // When cam approaches surface that close, shader switching is the optimal solution // though that other shader being nice and accurate, is quite costy, and cannot be realized // for 3 lights in 1 pass, because far more calculations (lightdir and eyedir) are in // fragment shader, and instruction count is limited to 64 in ps2.0 // // Remaining options: // - not use this precise one (aka. never let cam that close to a poly) // - use a second shader like this monster, but only for 1 light, and make it // multipass (a bit slower) // (I will try if 2 lights can be pushed below instruction count limit though // 'cause there might be cases when 2 lights would be enought) // - never use more than 1(maybe 2 if I can do it) lights that close, thus monster remains // an 1-pass shader, though still quite costy (about -10..-15 FPS max.) // // (Also note that distance for attenuation is calculated at per-vertex level - attenuation // can't be because it is non-linear, so remains to the frag shader, but as always, I will // try how it looks, and if you are fine with just linear attenuation, who knows? Might work // as well, and fast :) // // (thanks for all this info on distorsion Sinbad!) //BUGS(?) AND FLAWS: // // Ogre log complains about not being able to hand the shader all uniforms and custom // parameters when running the shader with reduced parameter count // - hardly effects performance or quality :) - but if you put comments ('//') into // material parser before those unused params, all is perfect // // Please report any bugs, performance bottlenecks, possible optimizations. See CONTACT. //HOW I COMPUTE THINGS (just to be consistent with techicals) // // For this shader, I put performance over quality. // This means: - NdotL, pow((NdotH),exponent)) -> no reflection vector // - less accuracy when light is close to surface (see PURE THEORY on this) // - attenuation has just linear component varying(k1), and is calculated in // vertex shader, and interpolated to frag shader automatically // - specular exponents are the same for the 3 lights, change it if u wish // // ALSO NOTE WELL: // - I use no material light reflection coefficients, they are doing (1,1,1) to // all kinds of lights (diff, amb, spec) // - diffuse texture is modulating diffuse light component only // - there in no such thing as ambient light component here, just big global ambient // colour as a general environment lighting imitation // - I attenuate diffuse and specular both, and only them // // - at maximum-complexity, it does perpixel offset-mapping with modulative // diffuse texturing, and with ambient, diffuse, and specular components, // also attenuation // Expect extensions later. // // - Since I have only 7 texcoords in vs2.0/ps2.0, and for attenuation, I need // to pass distance to frag shader, and not calculate it there, to be fast, // I need an 8th. // To have attenuation, I decided that it will use the slot of halfvector of // light3. // IF YOU USE ATTENUATION, YOU WON'T GET SPECULAR OF THE 3RD LIGHT! // To add, this version suffers from the precision bug (mentioned in THEORY), // so expect proper attenuation only when perpixel is proper, too. // (You might change this to let it have specular, IF it does not have diffuse, // if wish, but I believe this way is more common. // Or, do you know a situation when specular of 3rd light is needed with atten?) // // As you see, this shader is quite efficient (mainly being 1-pass), supports 3 lights, // but techniques used are quite simple. //CONTACT: // // the name is guilderstein, email: forgamedev@yahoo.com, insert OGRE into subject please //USAGE SUGGESTIONS: // // PLEASE AVOID OBSCURE/ESOTERIC USAGE PARAMETERS // (like OFFSET on, but ANY_TEXTURE off) // I guess you will try it just to make it sweat, anyway :) // // REQUIREMENTS: (VERY IMPORTANT FOR EFFICIENCY AND CORRECT RESULTS) // 1. Can be used with no lights just DIFFUSE_TEXTURE, but turn off OFFSET/NORMAL-mapping, // ATTENUATION, DIFFUSE, and SPECULAR! // 2. When doing OFFSET/NORMAL-mapping, leave ANY_TEXTURE and at least LIGHT0 // AND DIFFUSE or SPECULAR on ! // 3. DIFFUSE_TEXTURE needs ANY_TEXTURE on. LIGHTx needs at least DIFFUSE or SPECULAR. // DIFFUSE and SPECULAR needs LIGHTx. // 4. When using with fewer than 3 lights, turn off lights in this order: 2,1,0 ! // 5. Use ATTENUATION with AT_LEAST light0 AND diffuse OR specular on ! // 6. Due to technical constraints, using ATTENUATION means no specular from light2 ! // 7. Try to use it with healty parameter-combos, at all time ! // // // // YOU'VE BEEN WARNED :D // // // //Tried working configs: full, full with just offset 0, full but just perpixel, // any above with less lights (not 0, see above!), // many combos with diffuse, specular, and ambient with above ones // zero lights with just texturing (good for debugging, etc.) // // Attenuation might have issues. No guarantee for that. Yet. // // So shall be workin' if you keep yourself to the 6 rules above. // // If you want to look at the code/know what happens when you turn sg. on/off, I suggest // using MSVC8. Though cannot compile, and you get syntax highlighting only for C parts, // it grays out unused code for you - real-time, during you write it. // Quite handy if you ask me :). //LIMITATIONS, PROS, CONTRAS, FUTURE // // The good: // // - VERY fast, thanks to being 1 pass // (in fact, when run with the same options, faster than every other shader I wrote :) // - Compile time tuneable options, 1 fast shader for LOTS of scenarios. // Just reload the shader after changing some 0s to 1s in first few lines with a key // binding or anything in Ogre. // // The bad: // // - Limited to 3 lights, and with attenuation, you mush make other restrictions, due to its // massive instruction count (read on about this) // - Not exact in when lights are close to surfaces which have very few, very large polys // (though this is rare case, and you can switch it that situation to another shader) // // And the ugly: // // - Anytime you add another feature, either new limitations arise, to keep it below instruction // count, being a ps2.0 shader (64 is way_not_enough), or // - Another ugly thing: this beast needs LOTS of data to traverse between vert and frag // shaders, and bingding semantics are limited, again way_tooo_much // (8 texcoords, 1 pos, 1 normal, few worthless extras like color) // // So, it can run full speed, full feature wo. attenuation. Thats the deal. // With atten on, you much cut it somewhere. Either set offset and ambient to 0 // (you can still have normal-mapping though), or use only 2 lights. // AND apart from that, I need another binding semantic, but I do not have any left, so light2's // specular is the sacrifice. // (again, in major number of environments, the 3rd closest lights specular contrib can be // omitted, given attenuation is more important, at least I think so) // // // In closing, about future: more features, and 2 more versions: 1 slow but featurefull multipass // one, and 1 slow VERY accurate one, which you can use in front of players looking at 1 poly // walls. //TWEAK HERE // // #define PER_VERTEX 1 -> TODO /?/ // #define SPOT_LIGHTS 1 -> TODO // #define DETAIL_BUMP_TEXTURE 1 -> TODO (bump means normal map, height in alpha optional) // #define DETAIL_DIFFUSE_TEXTURE 1 -> TODO // #define SPECULAR_POWER_TEXTURE 1 -> TODO (stored in diffuse texture's alpha) // #define ENVIRONMENT_MAPPING 1 -> TODO // #define AMBIENT_OCCLUSION 1 -> TODO (modulates envir. lighting aka. ambient) // #define OPACITY_TEXTURE 1 -> TODO (offset-mapped decals, for.ex) // // Other suggestions? #define ATTENUATION 1 #define ANY_TEXTURE 1 #define DIFFUSE_TEXTURE 1 #define AT_LEAST_PERPIXEL 1 #define AT_LEAST_NORMAL_MAPPING 1 #define OFFSET_MAPPING 1 #define AMBIENT 1 #define DIFFUSE 1 #define SPECULAR 1 #define LIGHT0 1 #define LIGHT1 1 #define LIGHT2 0 // Helper: Expand a range-compressed vector float3 expand(float3 v) { return (v - 0.5) * 2; } ///////////////////////////////////////////////////////////////////////////////////////////////// // VERT COMES ///////////////////////////////////////////////////////////////////////////////////////////////// //quite chaotic form, maybe more logical arrangement possible void WonderShader_Lim3_Fast_Vert ( float4 position : POSITION, float3 normal : NORMAL, out float4 oPosition : POSITION, #if ANY_TEXTURE float2 uv : TEXCOORD0, out float2 oUv : TEXCOORD0, uniform float scale, #endif #if AT_LEAST_NORMAL_MAPPING float3 tangent : TEXCOORD1, #elif AT_LEAST_PERPIXEL //just normal perpixel, use texcoord7 to transmit to frag (holds eyedir in offset case) out float3 oNorm : TEXCOORD7, #endif // Still in frag shader! // #if AMBIENT // uniform float4 ambient, // out float4 oColor : COLOR, // #endif #if LIGHT0 uniform float4 lightPosition0, // object space #if DIFFUSE out float3 oLightDir0 : TEXCOORD1, #endif #if SPECULAR out float3 oHalfAngle0 : TEXCOORD4, #endif #endif #if LIGHT1 uniform float4 lightPosition1, // object space #if DIFFUSE out float3 oLightDir1 : TEXCOORD2, #endif #if SPECULAR out float3 oHalfAngle1 : TEXCOORD5, #endif #endif #if LIGHT2 uniform float4 lightPosition2, // object space #if DIFFUSE out float3 oLightDir2 : TEXCOORD3, #endif #endif #if ATTENUATION out float4 dist : TEXCOORD6, // .x, .y, and .z is used for light distances #elif SPECULAR out float3 oHalfAngle2 : TEXCOORD6, #endif #if OFFSET_MAPPING //needs eye no matter specular uniform float3 eyePosition, // object space out float3 oEyeDir : TEXCOORD7, #elif SPECULAR //no need to output eye, even if normal-mapping is on uniform float3 eyePosition, // object space #endif uniform float4x4 worldviewproj ) { oPosition = mul(worldviewproj , position); #if ANY_TEXTURE oUv = uv * scale; #endif #if AT_LEAST_NORMAL_MAPPING float3 binormal = cross(tangent, normal); float3x3 rotation = float3x3(tangent, binormal, normal); #elif AT_LEAST_PERPIXEL oNorm = normal; #endif #if OFFSET_MAPPING //no matter specular, I need eye for offsetting float3 eyeDir = eyePosition - position.xyz; eyeDir = normalize(mul(rotation, eyeDir)); oEyeDir = eyeDir; #elif SPECULAR //I need eye only if specular other than offset, plus no eye output now float3 eyeDir = normalize(eyePosition - position.xyz); #if AT_LEAST_NORMAL_MAPPING //eye needs adjustment if normal-mapping eyeDir = normalize(mul(rotation, eyeDir)); #endif #endif //if DIFFUSE is commented out, we only need temp_lightDirX for oHalfAngle //and if both DIFFUSE and SPECULAR is out, we shall not calculate any lighting #if LIGHT0 #if ATTENUATION float3 temp_lightDir0 = lightPosition0.xyz - (position * lightPosition0.w); dist.x = length(temp_lightDir0); temp_lightDir0 = temp_lightDir0 / dist.x; //normalize it this way // oatten.x = 1/(atten.y + dist0*atten.z + dist0*dist0*atten.w); //some attenuation calc, could be faster with some approximation //I think at least leaving only kl component #else float3 temp_lightDir0 = normalize(lightPosition0.xyz - (position * lightPosition0.w)); #endif #if AT_LEAST_NORMAL_MAPPING temp_lightDir0 = normalize(mul(rotation, temp_lightDir0)); #if DIFFUSE oLightDir0 = temp_lightDir0; #endif #elif DIFFUSE //just normal perpixel oLightDir0 = temp_lightDir0; #endif #if SPECULAR oHalfAngle0 = normalize(eyeDir + temp_lightDir0); #endif #endif #if LIGHT1 #if ATTENUATION float3 temp_lightDir1 = lightPosition1.xyz - (position * lightPosition1.w); dist.y = length(temp_lightDir1); temp_lightDir1 = temp_lightDir1 / dist.y; //normalize it this way // oatten.y = 1/(atten.y + dist1*atten.z + dist1*dist1*atten.w); //some attenuation calc, could be faster with some approximation //I think at least leaving only kl component #else float3 temp_lightDir1 = normalize(lightPosition1.xyz - (position * lightPosition1.w)); #endif #if AT_LEAST_NORMAL_MAPPING temp_lightDir1 = normalize(mul(rotation, temp_lightDir1)); #if DIFFUSE oLightDir1 = temp_lightDir1; #endif #elif DIFFUSE //just normal perpixel oLightDir1 = temp_lightDir1; #endif #if SPECULAR oHalfAngle1 = normalize(eyeDir + temp_lightDir1); #endif #endif #if LIGHT2 #if ATTENUATION float3 temp_lightDir2 = lightPosition2.xyz - (position * lightPosition2.w); dist.z = length(temp_lightDir2); temp_lightDir2 = temp_lightDir2 / dist.z; //normalize it this way // oatten.z = 1/(atten.y + dist2*atten.z + dist2*dist2*atten.w); //some attenuation calc, could be faster with some approximation //I think at least leaving only kl component #else float3 temp_lightDir2 = normalize(lightPosition2.xyz - (position * lightPosition2.w)); #if SPECULAR oHalfAngle2 = normalize(eyeDir + temp_lightDir2); #endif #endif #if AT_LEAST_NORMAL_MAPPING temp_lightDir2 = normalize(mul(rotation, temp_lightDir2)); #if DIFFUSE oLightDir2 = temp_lightDir2; #endif #elif DIFFUSE //just normal perpixel oLightDir2 = temp_lightDir2; #endif #endif } ///////////////////////////////////////////////////////////////////////////////////////////////// // FRAG COMES ///////////////////////////////////////////////////////////////////////////////////////////////// void WonderShader_Lim3_Fast_Frag( #if DIFFUSE_TEXTURE uniform sampler2D diffuseMap : register(s1), float2 uv : TEXCOORD0, #elif ANY_TEXTURE float2 uv : TEXCOORD0, #endif #if LIGHT0 #if DIFFUSE float3 LightDir0 : TEXCOORD1, uniform float4 lightDiffuse0, #endif #if SPECULAR float3 HalfAngle0 : TEXCOORD4, uniform float4 lightSpecular0, #endif #endif #if LIGHT1 #if DIFFUSE float3 LightDir1 : TEXCOORD2, uniform float4 lightDiffuse1, #endif #if SPECULAR float3 HalfAngle1 : TEXCOORD5, uniform float4 lightSpecular1, #endif #endif #if LIGHT2 #if DIFFUSE float3 LightDir2 : TEXCOORD3, uniform float4 lightDiffuse2, #endif #endif #if OFFSET_MAPPING float3 EyeDir : TEXCOORD7, uniform float4 scaleBias, uniform sampler2D normalHeightMap : register(s0), #elif AT_LEAST_NORMAL_MAPPING uniform sampler2D normalHeightMap : register(s0), #elif AT_LEAST_PERPIXEL //no normal-mapping, use standard normal, in eyedir's place float3 normalvec : TEXCOORD7, #endif #if SPECULAR uniform float exponent0, // uniform float exponent1, // uniform float exponent2, #endif #if AMBIENT uniform float4 ambient, #endif #if ATTENUATION //if on, supposed to have light0 on as well! float4 dist : TEXCOORD6, uniform float4 atten0, #if LIGHT1 uniform float4 atten1, #endif #if LIGHT2 uniform float4 atten2, #endif #elif SPECULAR #if LIGHT2 float3 HalfAngle2 : TEXCOORD6, uniform float4 lightSpecular2, #endif #endif out float4 oColor : COLOR ) { #if OFFSET_MAPPING float height = tex2D(normalHeightMap, uv).a; float scale = scaleBias.x; float bias = scaleBias.y; float displacement = (height * scale) + bias; float3 uv2 = float3(uv, 1); float2 newTexCoord = ((EyeDir * displacement) + uv2).xy; float3 bumpVec = expand(tex2D(normalHeightMap, newTexCoord ).xyz); float3 N = normalize(bumpVec); #if DIFFUSE_TEXTURE float3 diffusetex = tex2D(diffuseMap, newTexCoord).xyz; #endif #elif AT_LEAST_NORMAL_MAPPING float3 bumpVec = expand(tex2D(normalHeightMap, uv).xyz); float3 N = normalize(bumpVec); #if DIFFUSE_TEXTURE float3 diffusetex = tex2D(diffuseMap, uv).xyz; #endif #elif AT_LEAST_PERPIXEL float3 N = normalize(normalvec); #if DIFFUSE_TEXTURE float3 diffusetex = tex2D(diffuseMap, uv).xyz; #endif #elif DIFFUSE_TEXTURE float3 diffusetex = tex2D(diffuseMap, uv).xyz; #endif //If different exponents for different specular-lights, change 3 places here! #if LIGHT0 #if DIFFUSE float NdotL0 = dot(normalize(LightDir0), N); #if SPECULAR //both float NdotH0 = dot(normalize(HalfAngle0), N); float4 Lit0 = lit(NdotL0,NdotH0,exponent0); #else //just diffuse float4 Lit0; Lit0.y = saturate(NdotL0); #endif #elif SPECULAR //just specular float NdotH0 = dot(normalize(HalfAngle0), N); float4 Lit0; Lit0.z = pow(saturate(NdotH0),exponent0); #endif #endif #if LIGHT1 #if DIFFUSE float NdotL1 = dot(normalize(LightDir1), N); #if SPECULAR //both float NdotH1 = dot(normalize(HalfAngle1), N); float4 Lit1 = lit(NdotL1,NdotH1,exponent0); #else //just diffuse float4 Lit1; Lit1.y = saturate(NdotL1); #endif #elif SPECULAR //just specular float NdotH1 = dot(normalize(HalfAngle1), N); float4 Lit1; Lit1.z = pow(saturate(NdotH1),exponent0); #endif #endif #if LIGHT2 #if DIFFUSE float NdotL2 = dot(normalize(LightDir2), N); #if SPECULAR //both #if !ATTENUATION float NdotH2 = dot(normalize(HalfAngle2), N); float4 Lit2 = lit(NdotL2,NdotH2,exponent0); #else float4 Lit2; Lit2.y = saturate(NdotL2); #endif #else //just diffuse float4 Lit2; Lit2.y = saturate(NdotL2); #endif #elif SPECULAR //just specular #if !ATTENUATION float NdotH2 = dot(normalize(HalfAngle2), N); float4 Lit2; Lit2.z = pow(saturate(NdotH2),exponent0); #else float4 Lit2; Lit2 = float4(1,0,0,1); #endif #endif #endif oColor = #if ATTENUATION //since usage rules specify it, we have at least light0 on with at least either //diffuse or specular also on ! // - if you want no lighting, just textures, turn attenuation off! //But yes, you can have diffusetex with just specular :) //Note that you can't have specular of light2 with attenuation on. See docs. // Final color formula with atten // oColor = atten0 * (diffusetex * lightDiffuse0 * Lit0.y + lightSpecular0 * Lit0.z) // atten1 * (diffusetex * lightDiffuse1 * Lit1.y + lightSpecular1 * Lit1.z) // atten2 * (diffusetex * lightDiffuse2 * Lit2.y + lightSpecular2 * Lit2.z) // + ambient; #if !DIFFUSE //we start with the no diffuse just diffusetex case, here only spec is attenuated #if DIFFUSE_TEXTURE float4(diffusetex,1) + #endif #endif 1/(atten0.y + atten0.z*dist.x + atten0.w*dist.x*dist.x)* ( //we always have light0 on here, and spec0 or diffuse0 with it #if SPECULAR lightSpecular0 * Lit0.z #if DIFFUSE + #else //light0 has only spec, light0 done ) #endif #endif #if DIFFUSE lightDiffuse0 * Lit0.y //without + sign, we are good at no specular case as well #if DIFFUSE_TEXTURE * float4(diffusetex,1)) //light0 done #else ) //light0 done #endif #endif #if LIGHT1 //optional, but if we have it, we have either diff1 or spec1, difftex can be 0/1 + 1/(atten1.y + atten1.z*dist.y + atten1.w*dist.y*dist.y) * ( #if SPECULAR lightSpecular1 * Lit1.z #if DIFFUSE + #else //light1 has only spec, light1 done ) #endif #endif #if DIFFUSE lightDiffuse1 * Lit1.y //without + sign here, we are good at no specular case as well #if DIFFUSE_TEXTURE * float4(diffusetex,1)) //light1 done #else ) //light1 done #endif #endif #endif #if LIGHT2 //ditto goes for diff2, and difftex (no specular here) + 1/(atten2.y + atten2.z*dist.z + atten2.w*dist.z*dist.z) * ( #if DIFFUSE lightDiffuse2 * Lit2.y //without + sign here, we are good at no specular case as well #if DIFFUSE_TEXTURE * float4(diffusetex,1)) //light2 done #else ) //light2 done #endif #endif #endif #else // And wo. atten // oColor = diffusetex // * (lightDiffuse0 * Lit0.y + lightDiffuse1 * Lit1.y + lightDiffuse2 * Lit2.y) // + lightSpecular0 * Lit0.z + lightSpecular1 * Lit1.z + lightSpecular2 * Lit2.z // + ambient; float4(0,0,0,0) //this is needed to simplify preprocessor stuff, no FPS cost :) #if DIFFUSE_TEXTURE //at least diffuse texture, no lighting yet + float4(diffusetex,1) #if DIFFUSE //modulate texture with lighting *( #if LIGHT0 lightDiffuse0 * Lit0.y #endif #if LIGHT1 + lightDiffuse1 * Lit1.y #endif #if LIGHT2 + lightDiffuse2 * Lit2.y #endif ) #endif #elif DIFFUSE //just diffuse lighting, no modulation #if LIGHT0 + lightDiffuse0 * Lit0.y #endif #if LIGHT1 + lightDiffuse1 * Lit1.y #endif #if LIGHT2 + lightDiffuse2 * Lit2.y #endif #endif #if SPECULAR #if LIGHT0 + lightSpecular0 * Lit0.z #endif #if LIGHT1 + lightSpecular1 * Lit1.z #endif #if LIGHT2 + lightSpecular2 * Lit2.z #endif #endif #endif #if AMBIENT + ambient #endif ; }
Contributors to this page: jacmoe
.
Page last modified on Tuesday 29 of June, 2010 00:20:58 UTC 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
Last changes
- Hydrax
- QtOgre
- SoC2012 Complete the DirectX 11 render system
- SoC2012 Volume Rendering with LOD aimed at terrain
- SoC2012 Improve and Demo the Terrain System
- Mogre and WPF
- SoC2012 Implementation of Off-Screen Particles
- Advanced Ogre Framework
- Ogre overlays using Qt
- Architecture and Design in Games
Search box
Online users
62
online users

