1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
[require]
GLSL >= 1.10
[fragment shader]
#version 120
#define I965_HACK 1
varying vec3 light_surf;
varying vec3 eye_surf;
varying vec3 tangent_surf;
varying vec4 shadow_coords;
varying vec2 texcoord;
uniform sampler2D normal_sampler;
uniform sampler2D heightmap_sampler;
uniform sampler2DShadow shadow_sampler;
uniform float F0, ni, ward_mm_inv, ward_mn_inv, ward_nn_inv;
float schlick_fresnel(float n_dot_l)
{
return F0 + (1 - F0) * pow(1 - n_dot_l, 5);
}
void main()
{
float shadow = shadow2DProj(shadow_sampler, shadow_coords).x;
const vec4 material_color = vec4(0.7, 0.5, 0.3, 0.0);
vec4 color;
float s = .7;
float d = 1 - s;
float Ii = 0.9; /*intensity of incoming light */
float Iia = .1 * Ii; /*intensity of ambient light */
float Rs = 0;
float D;
float Rd = (1 - F0) * 2;
/* Calculate ambient lighting. */
/* Ambient occlusion factor -- sample the height map we
* used to generate the normal map, and reduce intensity in
* the valleys.
*/
float heightmap = texture2D(heightmap_sampler, texcoord).x;
float Ra = Rd * (.8 + .2 * heightmap);
color = material_color * Iia * Ra;
/* Calculate specular and diffuse lighting */
#if !I965_HACK
if (shadow > 0) {
#endif
vec3 l = normalize(light_surf);
vec3 v = normalize(eye_surf);
vec3 h = normalize(l + v);
vec3 t = normalize(tangent_surf);
vec3 n = texture2D(normal_sampler, texcoord).xyz * 2 - 1;
/* Hack: Reduce the significance of our normal map, which
* otherwise looks incongruous with the straight edges.
*/
n = normalize(n + vec3(0,0,1));
float n_dot_l = dot(n, l);
float n_dot_v = dot(n, v);
float n_dot_h = dot(n, h);
float v_dot_h = dot(v, h);
float cos2_alpha = n_dot_h * n_dot_h;
float tan2_alpha = (1 - cos2_alpha) / cos2_alpha;
/* Aniso BRDF from Ward's "Measuring and Modeling
* Anisotropic Reflection".
*/
/* Make phi be the angle between the projections of
* the tangent and half-angle vectors onto the
* surface plane (z=0). Doing it right would involve
* projecting onto the plane defined by n.
*/
float cos_phi = dot(normalize(t.xy), normalize(h.xy));
float cos2_phi_over_m2 = (cos_phi * cos_phi) * ward_mm_inv;
float sin2_phi_over_n2 = (1 - cos_phi * cos_phi) * ward_nn_inv;
D = exp(-tan2_alpha * (cos2_phi_over_m2 + sin2_phi_over_n2));
Rs = 2 * schlick_fresnel(n_dot_l) * D *
inversesqrt(n_dot_l * n_dot_v) * ward_mn_inv;
Rs *= s;
color += max(0, n_dot_l) * step(0, n_dot_v) *
vec4(material_color.xyz *
((Rd * d + Rs) * Ii * shadow),
material_color.w);
#if !I965_HACK
}
#endif
gl_FragColor = color;
/* Debugging scalars -- Map [0,1] to [0.5,1] to catch negative
* values. Multiply by the step function to catch when
* the scalar won't come into play because Rs == 0.
*/
#if 0
/* Constant visualization */
gl_FragColor = vec4(vec3(F0 / 2 + .5), 1);
#endif
#if 0
/* Normal visualization */
gl_FragColor = vec4((normal.x + 1) / 2,
(normal.y + 1) / 2,
(normal.z + 1) / 2,
0);
#endif
#if 0
/* Sampler visualization */
gl_FragColor = texture2D(normal_sampler, texcoord);
#endif
}
[vertex shader]
#version 120
uniform vec3 light_eye;
varying vec2 texcoord;
varying vec3 light_surf;
varying vec3 eye_surf;
varying vec3 tangent_surf;
varying vec4 shadow_coords;
uniform mat4 mvp, mv, light_mvp;
void main()
{
mat3 mv3 = mat3(mv);
vec3 t = (mv3 * gl_MultiTexCoord1.xyz);
vec3 n = (mv3 * gl_Normal);
gl_Position = mvp * gl_Vertex;
mat3 tbn = mat3(t,
cross(n, t),
n
);
vec3 vertex_eye = vec3(mv * gl_Vertex);
shadow_coords = light_mvp * gl_Vertex;
texcoord = gl_MultiTexCoord0.xy;
light_surf = normalize((light_eye - vertex_eye) * tbn);
eye_surf = normalize((-vertex_eye) * tbn);
tangent_surf = gl_MultiTexCoord1.xyz * tbn;
}
|