UFO: Alien Invasion
Loading...
Searching...
No Matches
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 */
16vec3 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
70vec4 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}