scg3  0.6
toon_lighting.glsl
Go to the documentation of this file.
1 /**
2  * \file toon_lighting.glsl
3  * \brief Toon lighting shader, provides external function applyLighting()
4  * to vertex or fragment shader.
5  */
6 
7 #version 150
8 
9 const int MAX_NUMBER_OF_LIGHTS = 10;
10 
11 struct Light {
12  vec4 position;
13  vec4 ambient;
14  vec4 diffuse;
15  vec4 specular;
16  vec4 halfVector; // used as vec3, expected as normalized
17  vec4 spotDirection; // used as vec3, expected as normalized
18  float spotCosCutoff;
19  float spotExponent;
20 };
21 
22 layout(std140) uniform LightBlock {
23  Light lights[MAX_NUMBER_OF_LIGHTS];
24 };
25 
26 struct Material {
27  vec4 emission;
28  vec4 ambient;
29  vec4 diffuse;
30  vec4 specular;
31  float shininess;
32 };
33 
34 layout(std140) uniform MaterialBlock {
35  Material material;
36 };
37 
38 uniform int nLights;
39 uniform vec4 globalAmbientLight;
40 
41 
42 // --- declarations ---
43 
44 
45 void directionalLight(const in int idx, const in vec3 v, const in vec3 n,
46  inout vec4 ambient, inout vec4 diffuse, inout vec4 specular);
47 
48 void pointLight(const in int idx, const in vec3 ecVertex, const in vec3 v, const in vec3 n,
49  inout vec4 ambient, inout vec4 diffuse, inout vec4 specular);
50 
51 void spotLight(const in int idx, const in vec3 ecVertex, const in vec3 v, const in vec3 n,
52  inout vec4 ambient, inout vec4 diffuse, inout vec4 specular);
53 
54 
55 // --- implementations ---
56 
57 
58 void applyLighting(const in vec3 ecVertex, const in vec3 ecNormal,
59  out vec4 emissionAmbientDiffuse, out vec4 specular) {
60 
61  // normalized view direction and surface normal
62  vec3 v = normalize(-ecVertex);
63  vec3 n = normalize(ecNormal);
64 
65  // add contributions of light sources
66  vec4 ambient = vec4(0., 0., 0., 0.);
67  vec4 diffuse = vec4(0., 0., 0., 0.);
68  specular = vec4(0., 0., 0., 0.);
69  for (int i = 0; i < nLights; ++i) {
70  if (lights[i].position.w < 0.001) {
71  directionalLight(i, v, n, ambient, diffuse, specular);
72  }
73  else {
74  if (lights[i].spotCosCutoff < 0.001) {
75  pointLight(i, ecVertex, v, n, ambient, diffuse, specular);
76  }
77  else {
78  spotLight(i, ecVertex, v, n, ambient, diffuse, specular);
79  }
80  }
81  }
82 
83  // multiply with material parameters, add emission and global ambient light
84  emissionAmbientDiffuse = material.emission
85  + material.ambient * (globalAmbientLight + ambient)
86  + material.diffuse * diffuse;
87  specular *= material.specular;
88 }
89 
90 
91 void directionalLight(const in int idx, const in vec3 v, const in vec3 n,
92  inout vec4 ambient, inout vec4 diffuse, inout vec4 specular) {
93 
94  // normalized light source direction (half vector is provided by application)
95  vec3 s = normalize(lights[idx].position.xyz);
96 
97  // ambient
98  ambient += lights[idx].ambient;
99 
100  // diffuse
101  float sDotN = dot(s, n);
102  if (sDotN > 0.0) {
103  if (sDotN > 0.9) {
104  diffuse += lights[idx].diffuse;
105  }
106  else if (sDotN > 0.6) {
107  diffuse += lights[idx].diffuse * 0.75;
108  }
109  else if (sDotN > 0.3) {
110  diffuse += lights[idx].diffuse * 0.5;
111  }
112  else {
113  diffuse += lights[idx].diffuse * 0.25;
114  }
115  }
116 
117  // specular
118  float hDotN = dot(lights[idx].halfVector.xyz, n);
119  if (hDotN > 0.99) {
120  specular += lights[idx].specular;
121  }
122 }
123 
124 
125 void pointLight(const in int idx, const in vec3 ecVertex, const in vec3 v, const in vec3 n,
126  inout vec4 ambient, inout vec4 diffuse, inout vec4 specular) {
127 
128  // normalized light source direction and half vector
129  vec3 s = normalize(lights[idx].position.xyz - ecVertex);
130  vec3 h = normalize(v + s);
131 
132  // ambient
133  ambient += lights[idx].ambient;
134 
135  // diffuse
136  float sDotN = dot(s, n);
137  if (sDotN > 0.0) {
138  if (sDotN > 0.9) {
139  diffuse += lights[idx].diffuse;
140  }
141  else if (sDotN > 0.6) {
142  diffuse += lights[idx].diffuse * 0.75;
143  }
144  else if (sDotN > 0.3) {
145  diffuse += lights[idx].diffuse * 0.5;
146  }
147  else {
148  diffuse += lights[idx].diffuse * 0.25;
149  }
150  }
151 
152  // specular
153  float hDotN = dot(h, n);
154  if (hDotN > 0.99) {
155  specular += lights[idx].specular;
156  }
157 }
158 
159 
160 void spotLight(const in int idx, const in vec3 ecVertex, const in vec3 v, const in vec3 n,
161  inout vec4 ambient, inout vec4 diffuse, inout vec4 specular) {
162 
163  // normalized light source direction and half vector
164  vec3 s = normalize(lights[idx].position.xyz - ecVertex);
165  vec3 h = normalize(v + s);
166 
167  // check if surface point is inside spotlight cone
168  float dirDotS = dot(lights[idx].spotDirection.xyz, -s);
169  if (dirDotS >= lights[idx].spotCosCutoff) {
170 
171  // spot attenuation from center to edges
172  float attenuation = pow(dirDotS, lights[idx].spotExponent);
173 
174  // ambient
175  ambient += attenuation * lights[idx].ambient;
176 
177  // diffuse
178  float sDotN = dot(s, n);
179  if (sDotN > 0.0) {
180  if (sDotN > 0.9) {
181  diffuse += lights[idx].diffuse;
182  }
183  else if (sDotN > 0.6) {
184  diffuse += lights[idx].diffuse * 0.75;
185  }
186  else if (sDotN > 0.3) {
187  diffuse += lights[idx].diffuse * 0.5;
188  }
189  else {
190  diffuse += lights[idx].diffuse * 0.25;
191  }
192  }
193 
194  // specular
195  float hDotN = dot(h, n);
196  if (hDotN > 0.99) {
197  specular += lights[idx].specular;
198  }
199  }
200 }