#version 330 core out vec4 FragColor; const int MAX_POINT_LIGHTS = 10; in vec3 FragPosition; in vec3 Normal; in vec3 Color; struct BaseLight { vec3 color; float ambientIntensity; float diffuseIntensity; }; struct Attenuation { float constant; float linear; float exponential; }; struct PointLight { BaseLight base; Attenuation atten; vec3 position; float farPlane; samplerCube depthMap; }; struct Material { vec3 ambientColor; vec3 diffuseColor; vec3 specularColor; float shininess; }; uniform int numOfPointLights; uniform PointLight pointLights[MAX_POINT_LIGHTS]; uniform Material material; //uniform sampler2D diffuseTexture; uniform vec3 viewPosition; //uniform float farPlane; //uniform bool shadows; vec3 gridSamplingDisk[20] = vec3[] ( vec3(1, 1, 1), vec3( 1, -1, 1), vec3(-1, -1, 1), vec3(-1, 1, 1), vec3(1, 1, -1), vec3( 1, -1, -1), vec3(-1, -1, -1), vec3(-1, 1, -1), vec3(1, 1, 0), vec3( 1, -1, 0), vec3(-1, -1, 0), vec3(-1, 1, 0), vec3(1, 0, 1), vec3(-1, 0, 1), vec3( 1, 0, -1), vec3(-1, 0, -1), vec3(0, 1, 1), vec3( 0, -1, 1), vec3( 0, -1, -1), vec3( 0, 1, -1) ); int bayer[64] = int[64]( 0, 32, 8, 40, 2, 34, 10, 42, 48, 16, 56, 24, 50, 18, 58, 26, 12, 44, 4, 36, 14, 46, 6, 38, 60, 28, 52, 20, 62, 30, 54, 22, 3, 35, 11, 43, 1, 33, 9, 41, 51, 19, 59, 27, 49, 17, 57, 25, 15, 47, 7, 39, 13, 45, 5, 37, 63, 31, 55, 23, 61, 29, 53, 21 ); float ShadowCalculation(PointLight light, vec3 normal) { // get vector between fragment position and light position vec3 fragToLight = FragPosition - light.position; float currentDepth = length(fragToLight); vec3 lightDir = normalize(light.position - FragPosition); float shadow = 0.0; float bias = max(0.05 * (1.0 - dot(normal, lightDir)), 0.005); //float bias = 0.15; int samples = 20; float viewDistance = length(viewPosition - FragPosition); float diskRadius = (1.0 + (viewDistance / light.farPlane)) / 25.0; for(int i = 0; i < samples; ++i) { float closestDepth = texture(light.depthMap, fragToLight + gridSamplingDisk[i] * diskRadius).r; //FragColor = vec4(vec3(closestDepth / farPlane), 1.0); closestDepth *= light.farPlane; // undo mapping [0;1] if(currentDepth - bias > closestDepth) shadow += 1.0; } shadow /= float(samples); //shadow = dither(shadow); // display closestDepth as debug (to visualize depth cubemap) // FragColor = vec4(vec3(closestDepth / farPlane), 1.0); return shadow; } vec4 dither(vec4 color) { float downsampleFactor = 2; float ditherSize = 0.05; float colorSize = 8.0; float _x = (gl_FragCoord.x/downsampleFactor); float _y = (gl_FragCoord.y/downsampleFactor); _x = mod(_x, 8); _y = mod(_y, 8); int _M = bayer[8*int(_y) + int(_x)]; float _z = float(_M) * (1.0 / pow(8, 2.0)); _z -= 0.5; color.x += _z * ditherSize; color.y += _z * ditherSize; color.z += _z * ditherSize; //color = greyscale; color = floor(color * (colorSize - 1) + 0.5) / (colorSize - 1); vec3 greyscale = vec3(0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b); return color; } /*vec3 diffuse(vec3 _lightColor, vec3 _lightPosition) { // diffuse vec3 lightDir = normalize(_lightPosition - FragPosition); vec3 lightDist = _lightPosition - FragPosition; float diff = max(dot(lightDir, Normal), 0.0); float linear = 0.2; float exponential = 0.2; // Apply attenuation: light fades over distance float attenuation = 1.0 / (1.0 + (linear * length(lightDist)) + (exponential * pow(length(lightDist), 2.0))); vec3 diffuse = diff * lightColor; return diffuse; }*/ /*vec3 specular(vec3 _lightPosition) { // specular vec3 lightDir = normalize(_lightPosition - FragPosition); vec3 viewDir = normalize(viewPosition - FragPosition); vec3 reflectDir = reflect(-lightDir, Normal); float spec = 0.0; vec3 halfwayDir = normalize(lightDir + viewDir); spec = pow(max(dot(Normal, halfwayDir), 0.0), 64.0); vec3 specular = spec * lightColor; return specular; }*/ vec4 calculateAmbient(BaseLight light) { vec4 ambientColor = vec4(light.color, 1.0) * light.ambientIntensity * vec4(material.ambientColor, 1.0); return ambientColor; } vec4 calculateDiffuse(BaseLight light, vec3 lightDirection, vec3 normal) { vec4 diffuseColor = vec4(0.0); float diffuseFactor = dot(normal, -lightDirection); if (diffuseFactor > 0.0) { diffuseColor = vec4(light.color, 1.0) * light.diffuseIntensity * vec4(material.diffuseColor, 1.0) * diffuseFactor; } return diffuseColor; } vec4 calculateSpecular(BaseLight light, vec3 lightDirection, vec3 normal) { vec4 specularColor = vec4(0.0); vec3 pixelToCamera = normalize(viewPosition - FragPosition); vec3 lightReflect = normalize(reflect(lightDirection, normal)); float specularFactor = dot(pixelToCamera, lightReflect); if (specularFactor > 0.0) { specularColor = vec4(light.color, 1.0) * light.diffuseIntensity * vec4(material.specularColor, 1.0) * specularFactor; } return specularColor * material.shininess; } vec4 caclulatePointLight(int index, vec3 normal) { vec3 lightDirection = FragPosition - pointLights[index].position; float lightDistance = length(lightDirection); lightDirection = normalize(lightDirection); float shadow = 1.0 - ShadowCalculation(pointLights[index], normal); vec4 color = calculateAmbient(pointLights[index].base) + shadow * (calculateDiffuse(pointLights[index].base, lightDirection, normal) + calculateSpecular(pointLights[index].base, lightDirection, normal)); // color = vec4(Color, 1.0); float attenuation = pointLights[index].atten.constant + pointLights[index].atten.linear * lightDistance + pointLights[index].atten.exponential * (lightDistance * lightDistance); return color / attenuation; } void main() { vec3 normal = normalize(Normal); vec4 totalLight = vec4(0.0, 0.0, 0.0, 0.0); for (int i = 0; i < numOfPointLights; i++) { totalLight += caclulatePointLight(i, normal); } //totalLight = dither(totalLight); FragColor = totalLight; }