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
);
}