#version 330 core const int MAX_LIGHTS = 32; const float PI = 3.14159265359; const float SPECULAR_POWER = 10; in vec4 outPos; in vec3 outNormal; in vec3 outTangent; in vec3 outBitangent; in vec2 outTextCoords; out vec4 fragColor; struct Attenuation { float constant; float linear; float exponent; }; struct Light { vec3 position; int lightType; float intensity; vec3 color; vec3 conedir; float cutoff; Attenuation attenuation; }; struct Material { vec4 diffuse; int hasTexture; int hasNormalMap; int hasRoughMap; float roughnessFactor; float metallicFactor; }; uniform sampler2D textureSampler; uniform sampler2D normalSampler; uniform sampler2D roughnessSampler; uniform Light lights[MAX_LIGHTS]; struct SceneInfo { vec3 camPos; float ambientLightIntensity; vec3 ambientLightColor; int LightCount; }; uniform Material material; uniform SceneInfo sceneInfo; vec4 calcAmbient(Light ambientLight, vec4 ambient) { return vec4(ambientLight.intensity * ambientLight.color, 1) * ambient; } vec4 calcLightColor(vec4 diffuse, vec4 specular, vec3 lightColor, float light_intensity, vec3 position, vec3 to_light_dir, vec3 normal, float Metallic) { vec4 diffuseColor = vec4(0, 0, 0, 1); vec4 specColor = vec4(0, 0, 0, 1); float diffuseFactor = max(dot(normal, to_light_dir), 0.0); diffuseColor = diffuse * vec4(lightColor, 1.0) * light_intensity * diffuseFactor; vec3 camera_direction = normalize(-position); vec3 from_light_dir = -to_light_dir; vec3 reflected_light = normalize(reflect(from_light_dir, normal)); float specularFactor = max(dot(camera_direction, reflected_light), 0.0); specularFactor = pow(specularFactor, SPECULAR_POWER); specColor = specular * light_intensity * specularFactor * Metallic * vec4(lightColor, 1.0); return (diffuseColor + specColor); } vec4 calcPointLight(vec4 diffuse, vec4 specular, Light light, vec3 position, vec3 normal, float Metallic) { vec3 light_direction = light.position - position; vec3 to_light_dir = normalize(light_direction); vec4 light_color = calcLightColor(diffuse, specular, light.color, light.intensity, position, to_light_dir, normal,Metallic); float distance = length(light_direction); float attenuationInv = light.attenuation.constant + light.attenuation.linear * distance + light.attenuation.exponent * distance * distance; return light_color / attenuationInv; } vec4 calcSpotLight(vec4 diffuse, vec4 specular, Light light, vec3 position, vec3 normal,float Metallic) { vec3 light_direction = light.position - position; vec3 to_light_dir = normalize(light_direction); vec3 from_light_dir = -to_light_dir; float spot_alfa = dot(from_light_dir, normalize(light.conedir)); vec4 color = vec4(0, 0, 0, 0); if (spot_alfa > light.cutoff) { color = calcPointLight(diffuse, specular, light, position, normal,Metallic); color *= (1.0 - (1.0 - spot_alfa)/(1.0 - light.cutoff)); } return color; } vec4 calcDirLight(vec4 diffuse, vec4 specular, Light light, vec3 position, vec3 normal,float Metallic) { return calcLightColor(diffuse, specular, light.color, light.intensity, position, normalize(light.position), normal,Metallic); } vec3 calcNormal(Material material, vec3 normal, vec2 textCoords, mat3 TBN) { vec3 newNormal = normal; if (material.hasNormalMap > 0) { newNormal = texture(normalSampler, textCoords).rgb; newNormal = normalize(newNormal * 2.0 - 1.0); newNormal = normalize(TBN * newNormal); } return newNormal; } float distributionGGX(vec3 N, vec3 H, float roughness) { float a = roughness * roughness; float a2 = a * a; float NdotH = max(dot(N, H), 0.0); float NdotH2 = NdotH * NdotH; float nom = a2; float denom = (NdotH2 * (a2 - 1.0) + 1.0); denom = PI * denom * denom; return nom / denom; } float geometrySchlickGGX(float NdotV, float roughness) { float r = (roughness + 1.0); float k = (r * r) / 8.0; float nom = NdotV; float denom = NdotV * (1.0 - k) + k; return nom / denom; } float geometrySmith(vec3 N, vec3 V, vec3 L, float roughness) { float NdotV = max(dot(N, V), 0.0); float NdotL = max(dot(N, L), 0.0); float ggx2 = geometrySchlickGGX(NdotV, roughness); float ggx1 = geometrySchlickGGX(NdotL, roughness); return ggx1 * ggx2; } vec3 fresnelSchlick(float cosTheta, vec3 F0) { return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0); } vec3 calculatePointLight(Light light, vec3 worldPos, vec3 V, vec3 N, vec3 F0, vec3 albedo, float metallic, float roughness) { vec3 tmpSub = light.position - worldPos; vec3 L = normalize(tmpSub); vec3 H = normalize(V + L); // Calculate distance and attenuation float distance = length(tmpSub); float attenuation = 1.0 / (distance * distance); float intensity = 10.0f; vec3 radiance = light.color * light.intensity * attenuation; // Cook-Torrance BRDF float NDF = distributionGGX(N, H, roughness); float G = geometrySmith(N, V, L, roughness); vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0); vec3 numerator = NDF * G * F; float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0) + 0.0001; vec3 specular = numerator / denominator; vec3 kS = F; vec3 kD = vec3(1.0) - kS; kD *= 1.0 - metallic; float NdotL = max(dot(N, L), 0.0); return (kD * albedo / PI + specular) * radiance * NdotL; } vec3 calculateDirectionalLight(Light light, vec3 V, vec3 N, vec3 F0, vec3 albedo, float metallic, float roughness) { vec3 L = normalize(-light.position); vec3 H = normalize(V + L); vec3 radiance = light.color * light.intensity; // Cook-Torrance BRDF float NDF = distributionGGX(N, H, roughness); float G = geometrySmith(N, V, L, roughness); vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0); vec3 numerator = NDF * G * F; float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0) + 0.0001; vec3 specular = numerator / denominator; vec3 kS = F; vec3 kD = vec3(1.0) - kS; kD *= 1.0 - metallic; float NdotL = max(dot(N, L), 0.0); return (kD * albedo / PI + specular) * radiance * NdotL; } void main() { vec4 text_color = texture(textureSampler, outTextCoords); if(text_color.a < 0.5) discard; vec4 diffuse = text_color; mat3 TBN = mat3(outTangent, outBitangent, outNormal); vec3 newNormal = calcNormal(material, outNormal, outTextCoords, TBN); float ao = 0.5; float roughnessFactor = 0.0; float metallicFactor = 0.0; if (material.hasRoughMap > 0) { vec4 metRoughValue = texture(roughnessSampler, outTextCoords); roughnessFactor = metRoughValue.g; metallicFactor = metRoughValue.b; } else { roughnessFactor = material.roughnessFactor; metallicFactor = material.metallicFactor; } vec4 specular = text_color + metallicFactor - roughnessFactor; vec4 pbr = vec4(ao, roughnessFactor, metallicFactor, text_color.a); float roughness = pbr.g; float metallic = pbr.b; vec3 N = normalize(newNormal); vec3 V = normalize(sceneInfo.camPos - outPos.rgb); vec3 F0 = vec3(0.04); F0 = mix(F0, text_color.rgb, metallic); vec3 Lo = vec3(0.0); for (int i = 0; i < sceneInfo.LightCount; i++) { Light light = lights[i]; vec3 Pos = vec3(outPos.rgb); if (light.lightType == 1) { //Lo += calculateDirectionalLight(light, V, N, F0, text_color.rgb, metallic, roughness); Lo += calcDirLight(diffuse, specular, light, Pos, outNormal,metallic).rgb; } else { // Lo += calculatePointLight(light, outPos.rgb, V, N, F0, text_color.rgb, metallic, roughness); Lo += calcPointLight(diffuse, specular, light, Pos, outNormal,metallic).rgb; } } vec3 ambient = sceneInfo.ambientLightColor * text_color.rgb * sceneInfo.ambientLightIntensity; vec3 color = ambient + Lo; fragColor = vec4(color, 1.0f); }