summaryrefslogtreecommitdiff
path: root/data/shaders/phong-frag.glsl
diff options
context:
space:
mode:
Diffstat (limited to 'data/shaders/phong-frag.glsl')
-rw-r--r--data/shaders/phong-frag.glsl174
1 files changed, 134 insertions, 40 deletions
diff --git a/data/shaders/phong-frag.glsl b/data/shaders/phong-frag.glsl
index ad324b3..84e9feb 100644
--- a/data/shaders/phong-frag.glsl
+++ b/data/shaders/phong-frag.glsl
@@ -15,17 +15,23 @@ struct Material {
bool useBumpMap;
};
-struct DirectionalLight {
+struct Light {
+ bool enabled;
+ int type;
+ vec3 position;
vec3 direction;
- vec3 ambient;
- vec3 diffuse;
- vec3 specular;
+ vec4 color;
+ float cutOff;
};
+#define MAX_LIGHTS 4
+
#ifdef GLSL120
+varying vec3 fragWorldPos;
varying vec3 fragNorm;
varying vec2 fragTex;
#else
+in vec3 fragWorldPos;
in vec3 fragNorm;
in vec2 fragTex;
#endif
@@ -35,55 +41,143 @@ out vec4 fragColor;
#endif
uniform Material material;
-uniform DirectionalLight directionalLight;
+uniform Light lights[MAX_LIGHTS];
+uniform vec3 cameraPosition;
+uniform vec4 ambientLightColor;
-void main() {
- vec3 baseAmbientColor;
- vec3 baseDiffuseColor;
- vec3 baseSpecularColor;
- if(material.useAmbientMap) {
-#ifdef GLSL330
- baseAmbientColor = texture(material.ambientMap, fragTex).xyz;
-#else
- baseAmbientColor = texture2D(material.ambientMap, fragTex).xyz;
+const float GAMMA = 2.2;
+
+#ifndef GLSL330
+// Compatibility shim for older GLSL versions.
+vec2 texture(sampler2D tex, vec2 coord) {
+ return texture2D(tex, coord);
+}
#endif
+
+float posDot(vec3 v1, vec3 v2) {
+ return max(dot(v1, v2), 0.0);
+}
+
+vec3 gammaCorrect(vec3 color) {
+ return pow(color, vec3(1.0 / GAMMA));
+}
+
+vec3 toneMap(vec3 color) {
+ return color / (color + vec3(1.0));
+}
+
+vec3 lightDirection(Light light) {
+ if(light.type == 0 || light.type == 2) { // point and spot lights
+ return normalize(light.position - fragWorldPos);
+ } else if(light.type == 1) { // directional light
+ return normalize(-light.direction);
+ }
+
+ return vec3(0.0); // should never be reached.
+}
+
+vec3 lightAttenuate(Light light) {
+ float distance = length(light.position - fragWorldPos);
+ float attenuation = 1.0 / (distance * distance);
+ return light.color.rgb * attenuation;
+}
+
+vec3 lightRadiance(Light light, vec3 direction) {
+ if(light.type == 0) { // point light
+ return lightAttenuate(light);
+ } else if(light.type == 1) { // directional light
+ return light.color.rgb;
+ } else if(light.type == 2) { // spot light
+ float theta = dot(direction, normalize(-light.direction));
+ // Spot lights only shine light in a specific conical area.
+ // They have no effect outside of that area.
+ if(theta > light.cutOff) {
+ // Feather out the light as it approaches the edge of its cone.
+ float intensity = (theta - light.cutOff) / (1.0 - light.cutOff);
+ return lightAttenuate(light) * intensity;
+ } else {
+ return vec3(0.0);
+ }
+ }
+
+ return vec3(0.0); // should never be reached.
+}
+
+vec3 materialAmbient() {
+ if(material.useAmbientMap) {
+ return texture(material.ambientMap, fragTex).rgb * material.ambient;
} else {
- baseAmbientColor = vec3(1.0, 1.0, 1.0);
+ return material.ambient;
}
+}
+
+vec3 materialDiffuse() {
if(material.useDiffuseMap) {
- // discard transparent fragments.
-#ifdef GLSL330
vec4 color = texture(material.diffuseMap, fragTex);
-#else
- vec4 color = texture2D(material.diffuseMap, fragTex);
-#endif
- if(color.a == 0.0) { discard; }
- baseDiffuseColor = color.xyz;
+ // discard transparent fragments.
+ if(color.a == 0.0) {
+ discard;
+ }
+ return color.rgb * material.diffuse;
} else {
- baseDiffuseColor = vec3(1.0, 1.0, 1.0);
+ return material.diffuse;
}
+}
+
+vec3 materialSpecular() {
if(material.useSpecularMap) {
-#ifdef GLSL330
- baseSpecularColor = texture(material.specularMap, fragTex).xyz;
-#else
- baseSpecularColor = texture2D(material.specularMap, fragTex).xyz;
-#endif
+ return texture(material.specularMap, fragTex).rgb * material.specular;
} else {
- baseSpecularColor = vec3(1.0, 1.0, 1.0);
+ return material.specular;
}
- vec3 ambientColor = material.ambient * baseAmbientColor * baseDiffuseColor;
- vec3 lightDir = normalize(-directionalLight.direction);
- float diffuseFactor = max(dot(lightDir, fragNorm), 0.0);
- vec3 diffuseColor = diffuseFactor * baseDiffuseColor * material.diffuse;
- vec3 reflectDir = reflect(-lightDir, fragNorm);
- float specularFactor = 0;
- if(material.shininess > 0) {
- specularFactor = pow(max(dot(lightDir, reflectDir), 0.0), material.shininess);
+}
+
+vec3 materialNormal() {
+ if(material.useBumpMap) {
+ return normalize(texture(material.bumpMap, fragTex).xyz * 2.0 - 1.0);
+ } else {
+ return fragNorm;
}
- vec3 specularColor = specularFactor * baseSpecularColor * material.specular;
+}
+
+void main() {
+ vec3 ambientOcclusion = materialAmbient();
+ vec3 baseDiffuseColor = materialDiffuse();
+ vec3 baseSpecularColor = materialSpecular();
+ vec3 normal = materialNormal();
+ vec3 color = vec3(0.0);
+
+ // Apply direct lighting.
+ for(int i = 0; i < MAX_LIGHTS; ++i) {
+ Light light = lights[i];
+
+ if(!light.enabled) {
+ continue;
+ }
+
+ vec3 lightDir = lightDirection(light);
+ vec3 radiance = lightRadiance(light, lightDir);
+ float diffuseFactor = posDot(lightDir, normal);
+ vec3 reflectDir = reflect(-lightDir, normal);
+ vec3 diffuseColor = baseDiffuseColor * diffuseFactor;
+ float specularFactor = 0;
+ if(material.shininess > 0) {
+ specularFactor = pow(posDot(lightDir, reflectDir), material.shininess);
+ }
+ vec3 specularColor = baseSpecularColor * specularFactor;
+ color += (diffuseColor + specularColor) * radiance;
+ }
+
+ // Apply ambient lighting.
+ vec3 ambientColor = baseDiffuseColor * ambientOcclusion * ambientLightColor.rgb;
+ color += ambientColor;
+
+ // Apply gamma correction and HDR tone mapping to get the final
+ // color.
+ vec4 finalColor = vec4(toneMap(gammaCorrect(color)), 1.0);
#ifdef GLSL330
- fragColor = vec4(ambientColor + diffuseColor + specularColor, 1.0);
+ fragColor = finalColor;
#else
- gl_FragColor = vec4(ambientColor + diffuseColor + specularColor, 1.0);
+ gl_FragColor = finalColor;
#endif
}