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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
|
#version 330 core
/*
@note: an explanation of why the light direction vector is taken from fragment to the
light source.
Basic LA really, we need to calculate the angle between the direction of the 2 vectors:
a. The direction at which light incidents with the fragment
b. The normal vector
The reason the light direction is taken from the fragment to the light source, is precisely so we can calculate
the angle between the normal and the direction at which light would hit. This if taken as starting from the light
source would actually be incorrect, since we would be calculating the angle between the light source in the direction
of the fragment and the normal. Consider what happens when it is directly above. The angle becomes 180, not 0. This
is because the normal moves in the direction opposite to the lights direction if taken this way, which is not what
we expect or want.
Reversing this, allows us to consider the angle at the point in which light hits the fragment, and the normal vector
of the fragment.
*/
struct Material {
sampler2D diffuse;
sampler2D specular;
float shininess;
};
struct Light {
vec3 ambient;
vec3 diffuse;
vec3 specular;
vec3 position;
};
struct DirectionalLight {
vec3 direction;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
struct PointLight {
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
// attentuation factors
float kC;
float kL;
float kQ;
};
struct SpotLight {
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
// attenuation factors
float kC;
float kL;
float kQ;
// vector for the direction directly in front of the spotlight
vec3 front;
// spot radius
float radius_inner;
float radius_outer; // to smooth out the light
};
// this is the result of a light creation. This contains the multipliers for each kind of a light we want
// to have.
struct LightFactor {
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
in vec2 texCoords;
in vec3 fragNormal;
in vec3 worldPosition;
uniform Material material;
uniform Light light;
uniform DirectionalLight dirLight;
uniform PointLight pointLight;
uniform PointLight multiPointLight[4];
uniform SpotLight spotLight;
uniform vec3 cameraPosition;
uniform vec3 lightColor;
out vec4 FragColor;
LightFactor make_directional_light(DirectionalLight light, vec3 CONST_viewDir) {
LightFactor res;
vec3 DL_lightDir = normalize(-light.direction);
res.ambient = light.ambient;
float DL_diffuseStrength = max(dot(DL_lightDir, fragNormal), 0.0);
res.diffuse = light.diffuse * DL_diffuseStrength;
vec3 DL_reflectDir = reflect(-DL_lightDir, fragNormal);
float DL_specularity = max(dot(CONST_viewDir, DL_reflectDir), 0.0);
float DL_shinePower = pow(DL_specularity, material.shininess);
res.specular = light.specular * DL_shinePower;
return res;
};
LightFactor make_point_light(PointLight light, vec3 CONST_viewDir) {
LightFactor res;
float PL_lightDistance = length(light.position - worldPosition);
float PL_attenuationFactor = 1.0 /
(light.kC + (light.kL * PL_lightDistance) + (light.kQ * PL_lightDistance * PL_lightDistance));
res.ambient = PL_attenuationFactor * light.ambient;
vec3 PL_lightDir = normalize(light.position - worldPosition);
float PL_diffuseStrength = max(dot(PL_lightDir, fragNormal), 0.0);
res.diffuse = PL_attenuationFactor * light.diffuse * PL_diffuseStrength;
vec3 PL_reflectDir = reflect(-PL_lightDir, fragNormal);
float PL_specularity = max(dot(CONST_viewDir, PL_reflectDir), 0.0);
float PL_shinePower = pow(PL_specularity, material.shininess);
res.specular = PL_attenuationFactor * PL_shinePower * light.specular;
return res;
}
LightFactor make_spot_light(SpotLight light, vec3 CONST_viewDir) {
LightFactor res;
float SL_lightDistance = length(light.position - worldPosition);
float SL_attenuationFactor = 1.0 /
(light.kC + (light.kL * SL_lightDistance) + (light.kQ * SL_lightDistance * SL_lightDistance));
vec3 SL_lightDir = normalize(light.position - worldPosition);
res.ambient = SL_attenuationFactor * light.ambient;
float SL_diffAmount = dot(SL_lightDir, normalize(-light.front));
float SL_spotLightFadeFactor = clamp((SL_diffAmount - light.radius_outer)/(light.radius_inner - light.radius_outer), 0.0f, 1.0f);
float SL_diffuseStrength = max(dot(SL_lightDir, fragNormal), 0.0);
res.diffuse = SL_spotLightFadeFactor * SL_attenuationFactor * light.diffuse * SL_diffuseStrength;
vec3 SL_reflectDir = reflect(-SL_lightDir, fragNormal);
float SL_specularity = max(dot(CONST_viewDir, SL_reflectDir), 0.0);
float SL_shinePower = pow(SL_specularity, material.shininess);
res.specular = SL_spotLightFadeFactor * SL_attenuationFactor * SL_shinePower * light.specular;
return res;
}
void main() {
vec3 CONST_viewDir = normalize(cameraPosition - worldPosition);
vec3 combinedAmbience = vec3(0.0);
vec3 combinedDiffuse = vec3(0.0);
vec3 combinedSpecular = vec3(0.0);
// directional light calculations and stuff
//LightFactor DL_factors = make_directional_light(dirLight, CONST_viewDir);
//combinedAmbience += DL_factors.ambient;
//combinedDiffuse += DL_factors.diffuse;
//combinedSpecular += DL_factors.specular;
// pointlight calculations and stuff
//LightFactor PL_factors = make_point_light(pointLight, CONST_viewDir);
//combinedAmbience += PL_factors.ambient;
//combinedDiffuse += PL_factors.diffuse;
//combinedSpecular += PL_factors.specular;
// multiple point lights
for (int i=0; i<4; i++)
{
PointLight pl = multiPointLight[i];
LightFactor MPL_factors = make_point_light(pl, CONST_viewDir);
combinedAmbience += MPL_factors.ambient;
combinedDiffuse += MPL_factors.diffuse;
combinedSpecular += MPL_factors.specular;
}
// spotlight calculations
LightFactor SL_factors = make_spot_light(spotLight, CONST_viewDir);
combinedAmbience += SL_factors.ambient;
combinedDiffuse += SL_factors.diffuse;
combinedSpecular += SL_factors.specular;
vec3 ambientLight = combinedAmbience * vec3(texture(material.diffuse, texCoords));
vec3 diffuseLight = combinedDiffuse * vec3(texture(material.diffuse, texCoords));
vec3 specularLight = combinedSpecular * vec3(texture(material.specular, texCoords));
vec3 color = ambientLight + diffuseLight + specularLight;
FragColor = vec4(color, 1.0);
}
|