scg3  0.6
blinn_phong_lighting.glsl
Go to the documentation of this file.
1 /**
2  * \file blinn_phong_lighting.glsl
3  * \brief Blinn Phong 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 = max(0., dot(s, n));
102  diffuse += lights[idx].diffuse * sDotN;
103 
104  // specular
105  float hDotN = dot(lights[idx].halfVector.xyz, n);
106  if (hDotN > 0.) {
107  specular += lights[idx].specular * pow(hDotN, material.shininess);
108  }
109 }
110 
111 
112 void pointLight(const in int idx, const in vec3 ecVertex, const in vec3 v, const in vec3 n,
113  inout vec4 ambient, inout vec4 diffuse, inout vec4 specular) {
114 
115  // normalized light source direction and half vector
116  vec3 s = normalize(lights[idx].position.xyz - ecVertex);
117  vec3 h = normalize(v + s);
118 
119  // ambient
120  ambient += lights[idx].ambient;
121 
122  // diffuse
123  float sDotN = max(0., dot(s, n));
124  diffuse += lights[idx].diffuse * sDotN;
125 
126  // specular
127  float hDotN = dot(h, n);
128  if (hDotN > 0.) {
129  specular += lights[idx].specular * pow(hDotN, material.shininess);
130  }
131 }
132 
133 
134 void spotLight(const in int idx, const in vec3 ecVertex, const in vec3 v, const in vec3 n,
135  inout vec4 ambient, inout vec4 diffuse, inout vec4 specular) {
136 
137  // normalized light source direction and half vector
138  vec3 s = normalize(lights[idx].position.xyz - ecVertex);
139  vec3 h = normalize(v + s);
140 
141  // check if surface point is inside spotlight cone
142  float dirDotS = dot(lights[idx].spotDirection.xyz, -s);
143  if (dirDotS >= lights[idx].spotCosCutoff) {
144 
145  // spot attenuation from center to edges
146  float attenuation = pow(dirDotS, lights[idx].spotExponent);
147 
148  // ambient
149  ambient += attenuation * lights[idx].ambient;
150 
151  // diffuse
152  float sDotN = max(0., dot(s, n));
153  diffuse += attenuation * lights[idx].diffuse * sDotN;
154 
155  // specular
156  float hDotN = dot(h, n);
157  if (hDotN > 0.) {
158  specular += attenuation * lights[idx].specular * pow(hDotN, material.shininess);
159  }
160  }
161 }