diff options
Diffstat (limited to 'data/shaders/phong-frag.glsl')
-rw-r--r-- | data/shaders/phong-frag.glsl | 174 |
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 } |