UFO: Alien Invasion
Doxygen documentation generating
cook-torrance_fs.glsl
Go to the documentation of this file.
1 /**
2  * @file
3  * @brief A fragment shader model for light reflection.
4  *
5  * The Cook-Torrance model for light reflection is a physics
6  * based model which uses two "roughness" parameters to describe
7  * the shape and distribution of micro-facets on the surface.
8  * NOTE: portions based on D3D9 source from Jack Hoxley
9  */
10 
11 #define ATTENUATE_THRESH 0.005
12 
13 /**
14  * @todo does not compile on my ati x600 yet
15  */
16 vec3 LightContribution(in vec4 lightParams, in vec3 lightDir, in vec3 N, in vec3 V, float NdotV, float R_2, in vec4 roughness, in vec4 specular, in vec4 diffuse) {
17  /* calculate light attenuation due to distance (do this first so we can return early if possible) */
18  float attenuate = 1.0;
19 
20  float dist = length(lightDir);
21  float attenDiv = lightParams.a * dist * dist;
22  /* If none of the attenuation parameters are set, we keep 1.0.*/
23  if (bool(attenDiv)) {
24  attenuate = 1.0 / attenDiv;
25  }
26 
27  /* if we're out of range, ignore the light; else calculate its contribution */
28  if (attenuate < ATTENUATE_THRESH) {
29  return vec3(0.0);
30  }
31 
32  /* Normalize vectors and cache dot products */
33  vec3 L = normalize(lightDir);
34  float NdotL = clamp(dot(N, L), 0.0, 1.0);
35 
36  /* Compute the final color contribution of the light */
37  vec3 diffuseColor = diffuse.rgb * lightParams.rgb * NdotL;
38  vec3 specularColor = lightParams.rgb;
39 
40  /* Cook-Torrance shading */
41  if (ROUGHMAP > 0) {
42  vec3 H = normalize(-L + V);
43  float NdotH = dot(N, -H);
44  float VdotH = dot(V, H);
45  float NdotH_2 = NdotH * NdotH;
46 
47  /* Compute the geometric term for specularity */
48  float G1 = (2.0 * NdotH * NdotV) / VdotH;
49  float G2 = (2.0 * NdotH * NdotL) / VdotH;
50  float G = clamp(min(G1, G2), 0.0, 1.0);
51 
52  /* Compute the roughness term for specularity */
53  float A = 1.0 / (4.0 * R_2 * NdotH_2 * NdotH_2);
54  float B = exp((NdotH_2 - 1.0) / (R_2 * NdotH_2));
55  float R = A * B;
56 
57  /* Compute the fresnel term for specularity using Schlick's approximation*/
58  float F = roughness.g + (1.0 - roughness.g) * pow(1.0 - VdotH, 5.0);
59 
60  specularColor *= specular.rgb * roughness.b * NdotL * (F * R * G) / (NdotV * NdotL);
61  } else { /* Phong shading */
62  specularColor *= specular.rgb * pow(max(dot(V, reflect(L, N)), 0.0), specular.a);
63  }
64 
65  /* @note We attenuate light here, but attenuation doesn't affect "directional" sources like the sun */
66  return (attenuate * (max(diffuseColor, 0.0) + max(specularColor, 0.0)));
67 }
68 
69 
70 vec4 IlluminateFragment(void) {
71  vec3 totalColor= vec3(0.0);
72 
73  /* sample the relevant textures */
74  vec2 coords = gl_TexCoord[0].st;
75  vec2 offset = vec2(0.0);
76 
77  /* do per-fragment calculations */
78  vec3 V = -normalize(eyedir);
79  vec3 N = vec3(0.0, 0.0, 1.0); /* basic surface normal */
80 
81 #if r_bumpmap
82  if (BUMPMAP > 0) {
83  vec4 normalMap = texture2D(SAMPLER_NORMALMAP, coords);
84  N = normalize(normalMap.xyz * 2.0 - 1.0);
85  N.xy *= BUMP;
86  if (PARALLAX > 0.0) {
87  offset = BumpTexcoord(normalMap.a);
88  coords += offset;
89  }
90  }
91 #endif
92 
93  vec4 diffuse = texture2D(SAMPLER_DIFFUSE, coords);
94  vec4 specular;
95  if (SPECULARMAP > 0) {
96  specular = texture2D(SAMPLER_SPECULAR, coords);
97  } else {
98  specular = vec4(HARDNESS, HARDNESS, HARDNESS, SPECULAR);
99  }
100  specular.a *= 512.0;
101 
102  vec4 roughness;
103  float R_2 = 0.0;
104  float NdotV = 0.0;
105  if (ROUGHMAP > 0) {
106  roughness = texture2D(SAMPLER_ROUGHMAP, coords);
107  /* scale reflectance to a more useful range */
108  roughness.r = clamp(roughness.r, 0.05, 0.95);
109  roughness.g *= 3.0;
110  R_2 = roughness.r * roughness.r;
111  NdotV = dot(N, -V);
112  } else {
113  roughness = vec4(0.0);
114  }
115 
116  /* add ambient light */
117  totalColor += diffuse.rgb * AMBIENT;
118 
119  /* fake light for the sunlight */
120  vec4 sunColor;
121  sunColor.rgb = SUNCOLOR;
122  sunColor.a = 1.0;
123  totalColor += LightContribution(sunColor, sunDir, N, V, NdotV, R_2, roughness, specular, diffuse);
124 
125  /* do per-light calculations */
126 #unroll r_dynamic_lights
127  totalColor += LightContribution(LIGHTPARAMS[$], lightDirs[$], N, V, NdotV, R_2, roughness, specular, diffuse);
128 #endunroll
129 
130  return vec4(totalColor, diffuse.a);
131 }