1 // ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader
2 // written by Forest 'LordHavoc' Hale
4 // common definitions between vertex shader and fragment shader:
6 #ifdef __GLSL_CG_DATA_TYPES
16 uniform float SceneBrightness;
18 varying vec2 TexCoord;
19 varying vec2 TexCoordLightmap;
21 varying vec3 CubeVector;
22 varying vec3 LightVector;
23 varying vec3 EyeVector;
25 varying vec3 EyeVectorModelSpace;
28 varying vec3 VectorS; // direction of S texcoord (sometimes crudely called tangent)
29 varying vec3 VectorT; // direction of T texcoord (sometimes crudely called binormal)
30 varying vec3 VectorR; // direction of R texcoord (surface normal)
35 // vertex shader specific:
38 uniform vec3 LightPosition;
39 uniform vec3 EyePosition;
40 uniform vec3 LightDir;
42 // TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3)
46 gl_FrontColor = gl_Color;
47 // copy the surface texcoord
48 TexCoord = vec2(gl_TextureMatrix[0] * gl_MultiTexCoord0);
49 #if !defined(MODE_LIGHTSOURCE) && !defined(MODE_LIGHTDIRECTION)
50 TexCoordLightmap = vec2(gl_MultiTexCoord4);
53 #ifdef MODE_LIGHTSOURCE
54 // transform vertex position into light attenuation/cubemap space
55 // (-1 to +1 across the light box)
56 CubeVector = vec3(gl_TextureMatrix[3] * gl_Vertex);
58 // transform unnormalized light direction into tangent space
59 // (we use unnormalized to ensure that it interpolates correctly and then
60 // normalize it per pixel)
61 vec3 lightminusvertex = LightPosition - gl_Vertex.xyz;
62 LightVector.x = dot(lightminusvertex, gl_MultiTexCoord1.xyz);
63 LightVector.y = dot(lightminusvertex, gl_MultiTexCoord2.xyz);
64 LightVector.z = dot(lightminusvertex, gl_MultiTexCoord3.xyz);
67 #ifdef MODE_LIGHTDIRECTION
68 LightVector.x = dot(LightDir, gl_MultiTexCoord1.xyz);
69 LightVector.y = dot(LightDir, gl_MultiTexCoord2.xyz);
70 LightVector.z = dot(LightDir, gl_MultiTexCoord3.xyz);
73 // transform unnormalized eye direction into tangent space
75 vec3 EyeVectorModelSpace;
77 EyeVectorModelSpace = EyePosition - gl_Vertex.xyz;
78 EyeVector.x = dot(EyeVectorModelSpace, gl_MultiTexCoord1.xyz);
79 EyeVector.y = dot(EyeVectorModelSpace, gl_MultiTexCoord2.xyz);
80 EyeVector.z = dot(EyeVectorModelSpace, gl_MultiTexCoord3.xyz);
82 #ifdef MODE_LIGHTDIRECTIONMAP_MODELSPACE
83 VectorS = gl_MultiTexCoord1.xyz;
84 VectorT = gl_MultiTexCoord2.xyz;
85 VectorR = gl_MultiTexCoord3.xyz;
88 // transform vertex to camera space, using ftransform to match non-VS
90 gl_Position = ftransform();
93 #endif // VERTEX_SHADER
98 // fragment shader specific:
99 #ifdef FRAGMENT_SHADER
101 uniform sampler2D Texture_Normal;
102 uniform sampler2D Texture_Color;
103 uniform sampler2D Texture_Gloss;
104 uniform samplerCube Texture_Cube;
105 uniform sampler2D Texture_FogMask;
106 uniform sampler2D Texture_Pants;
107 uniform sampler2D Texture_Shirt;
108 uniform sampler2D Texture_Lightmap;
109 uniform sampler2D Texture_Deluxemap;
110 uniform sampler2D Texture_Glow;
112 uniform myhvec3 LightColor;
113 uniform myhvec3 AmbientColor;
114 uniform myhvec3 DiffuseColor;
115 uniform myhvec3 SpecularColor;
116 uniform myhvec3 Color_Pants;
117 uniform myhvec3 Color_Shirt;
118 uniform myhvec3 FogColor;
120 uniform float OffsetMapping_Scale;
121 uniform float OffsetMapping_Bias;
122 uniform float FogRangeRecip;
124 uniform myhalf AmbientScale;
125 uniform myhalf DiffuseScale;
126 uniform myhalf SpecularScale;
127 uniform myhalf SpecularPower;
131 // apply offsetmapping
132 #ifdef USEOFFSETMAPPING
133 vec2 TexCoordOffset = vec2(TexCoord);
134 #define TexCoord TexCoordOffset
136 vec3 eyedir = vec3(normalize(EyeVector));
137 float depthbias = 1.0 - eyedir.z; // should this be a -?
138 depthbias = 1.0 - depthbias * depthbias;
140 #ifdef USEOFFSETMAPPING_RELIEFMAPPING
141 // 14 sample relief mapping: linear search and then binary search
142 //vec3 OffsetVector = vec3(EyeVector.xy * (1.0 / EyeVector.z) * depthbias * OffsetMapping_Scale * vec2(-0.1, 0.1), -0.1);
143 //vec3 OffsetVector = vec3(normalize(EyeVector.xy) * OffsetMapping_Scale * vec2(-0.1, 0.1), -0.1);
144 vec3 OffsetVector = vec3(eyedir.xy * OffsetMapping_Scale * vec2(-0.1, 0.1), -0.1);
145 vec3 RT = vec3(TexCoord - OffsetVector.xy * 10.0, 1.0) + OffsetVector;
146 if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;
147 if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;
148 if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;
149 if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;
150 if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;
151 if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;
152 if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;
153 if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;
154 if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;OffsetVector *= 0.5;RT -= OffsetVector;
155 if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;OffsetVector *= 0.5;RT -= OffsetVector;
156 if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;OffsetVector *= 0.5;RT -= OffsetVector;
157 if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;OffsetVector *= 0.5;RT -= OffsetVector;
158 if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;OffsetVector *= 0.5;RT -= OffsetVector;
159 if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;OffsetVector *= 0.5;RT -= OffsetVector;
162 // 3 sample offset mapping (only 3 samples because of ATI Radeon 9500-9800/X300 limits)
163 //vec2 OffsetVector = vec2(EyeVector.xy * (1.0 / EyeVector.z) * depthbias) * OffsetMapping_Scale * vec2(-0.333, 0.333);
164 //vec2 OffsetVector = vec2(normalize(EyeVector.xy)) * OffsetMapping_Scale * vec2(-0.333, 0.333);
165 vec2 OffsetVector = vec2(eyedir.xy) * OffsetMapping_Scale * vec2(-0.333, 0.333);
166 //TexCoord += OffsetVector * 3.0;
167 TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;
168 TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;
169 TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;
171 // 10 sample offset mapping
172 //vec2 OffsetVector = vec2(EyeVector.xy * (1.0 / EyeVector.z) * depthbias) * OffsetMapping_Scale * vec2(-0.333, 0.333);
173 //vec2 OffsetVector = vec2(normalize(EyeVector.xy)) * OffsetMapping_Scale * vec2(-0.333, 0.333);
174 vec2 OffsetVector = vec2(eyedir.xy) * OffsetMapping_Scale * vec2(-0.1, 0.1);
175 //TexCoord += OffsetVector * 3.0;
176 TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;
177 TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;
178 TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;
179 TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;
180 TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;
181 TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;
182 TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;
183 TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;
184 TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;
185 TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;
187 // parallax mapping as described in the paper
188 // "Parallax Mapping with Offset Limiting: A Per-Pixel Approximation of Uneven Surfaces" by Terry Welsh
189 // The paper provides code in the ARB fragment program assembly language
190 // I translated it to GLSL but may have done something wrong - SavageX
191 // LordHavoc: removed bias and simplified to one line
192 // LordHavoc: this is just a single sample offsetmapping...
193 TexCoordOffset += vec2(eyedir.x, -1.0 * eyedir.y) * OffsetMapping_Scale * texture2D(Texture_Normal, TexCoord).a;
195 // parallax mapping as described in the paper
196 // "Parallax Mapping with Offset Limiting: A Per-Pixel Approximation of Uneven Surfaces" by Terry Welsh
197 // The paper provides code in the ARB fragment program assembly language
198 // I translated it to GLSL but may have done something wrong - SavageX
199 float height = texture2D(Texture_Normal, TexCoord).a;
200 height = (height - 0.5) * OffsetMapping_Scale; // bias and scale
201 TexCoordOffset += height * vec2(eyedir.x, -1.0 * eyedir.y);
205 // combine the diffuse textures (base, pants, shirt)
206 vec4 color = vec4(texture2D(Texture_Color, TexCoord));
207 #ifdef USECOLORMAPPING
208 color.rgb += vec3(myhvec3(texture2D(Texture_Pants, TexCoord)) * myhvec3(Color_Pants) + myhvec3(texture2D(Texture_Shirt, TexCoord)) * myhvec3(Color_Shirt));
214 #ifdef MODE_LIGHTSOURCE
217 // get the surface normal and light normal
218 myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - 0.5);
219 myhvec3 diffusenormal = myhvec3(normalize(LightVector));
221 // calculate directional shading
222 color.rgb *= (AmbientScale + DiffuseScale * max(dot(surfacenormal, diffusenormal), 0.0));
224 myhvec3 specularnormal = myhvec3(normalize(diffusenormal + myhvec3(normalize(EyeVector))));
225 color.rgb += myhvec3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(max(dot(surfacenormal, specularnormal), 0.0), SpecularPower);
229 // apply light cubemap filter
230 //color.rgb *= normalize(CubeVector) * 0.5 + 0.5;//vec3(textureCube(Texture_Cube, CubeVector));
231 color.rgb *= myhvec3(textureCube(Texture_Cube, CubeVector));
235 color.rgb *= LightColor;
239 // the attenuation is (1-(x*x+y*y+z*z)) which gives a large bright
240 // center and sharp falloff at the edge, this is about the most efficient
241 // we can get away with as far as providing illumination.
243 // pow(1-(x*x+y*y+z*z), 4) is far more realistic but needs large lights to
244 // provide significant illumination, large = slow = pain.
245 color.rgb *= max(1.0 - dot(CubeVector, CubeVector), 0.0);
250 #elif defined(MODE_LIGHTDIRECTION)
251 // directional model lighting
253 // get the surface normal and light normal
254 myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhalf(0.5));
255 myhvec3 diffusenormal = myhvec3(normalize(LightVector));
257 // calculate directional shading
258 color.rgb *= vec3(myhvec3(AmbientColor) + myhvec3(DiffuseColor) * myhalf(max(dot(vec3(surfacenormal), vec3(diffusenormal)), 0.0)));
261 myhvec3 specularnormal = myhvec3(normalize(diffusenormal + myhvec3(normalize(EyeVector))));
262 color.rgb += myhvec3(texture2D(Texture_Gloss, TexCoord)) * SpecularColor * pow(max(dot(surfacenormal, specularnormal), 0.0), SpecularPower);
268 #elif defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_LIGHTDIRECTIONMAP_TANGENTSPACE)
269 // deluxemap lightmapping using light vectors in modelspace (evil q3map2)
271 // get the surface normal and light normal
272 myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - 0.5);
274 #ifdef MODE_LIGHTDIRECTIONMAP_MODELSPACE
275 myhvec3 diffusenormal_modelspace = myhvec3(texture2D(Texture_Deluxemap, TexCoordLightmap)) - 0.5;
276 myhvec3 diffusenormal = normalize(myhvec3(dot(diffusenormal_modelspace, VectorS), dot(diffusenormal_modelspace, VectorT), dot(diffusenormal_modelspace, VectorR)));
278 myhvec3 diffusenormal = normalize(myhvec3(texture2D(Texture_Deluxemap, TexCoordLightmap)) - 0.5);
280 // calculate directional shading
281 myhvec3 tempcolor = color.rgb * (DiffuseScale * max(dot(surfacenormal, diffusenormal), 0.0));
283 myhvec3 specularnormal = myhvec3(normalize(diffusenormal + myhvec3(normalize(EyeVector))));
284 tempcolor += myhvec3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(max(dot(surfacenormal, specularnormal), 0.0), SpecularPower);
287 // apply lightmap color
288 color.rgb = tempcolor * myhvec3(texture2D(Texture_Lightmap, TexCoordLightmap)) + color.rgb * myhvec3(AmbientScale);
291 #else // MODE none (lightmap)
292 // apply lightmap color
293 color.rgb *= myhvec3(texture2D(Texture_Lightmap, TexCoordLightmap)) * DiffuseScale + myhvec3(AmbientScale);
299 color.rgb += texture2D(Texture_Glow, TexCoord).rgb;
304 myhalf fog = texture2D(Texture_FogMask, myhvec2(length(EyeVectorModelSpace)*FogRangeRecip, 0.0)).x;
305 color.rgb = color.rgb * fog + FogColor * (1.0 - fog);
308 color.rgb *= SceneBrightness;
310 gl_FragColor = color;
313 #endif // FRAGMENT_SHADER