Load lights from model
[opengl.git] / pbrfrag.glsl
index 4421b99b6021a9e6a7da4953122bebf30bbf2499..d4c7eceb7e26cbb97e529768c50ce9a1469454ef 100644 (file)
@@ -7,16 +7,24 @@ in vec2 texCoords;
 
 uniform vec3 camPos;
 
-uniform sampler2D albedoMap;
-uniform sampler2D normalMap;
-uniform sampler2D metallicMap;
-uniform sampler2D roughnessMap;
-uniform sampler2D aoMap;
+struct Material {
+       sampler2D albedoMap;
+       sampler2D normalMap;
+       sampler2D metallicRoughnessMap;
+       sampler2D aoMap;
+       bool hasAlbedo, hasNormal, hasMetallicRoughness, hasAo;
+};
+uniform Material mat;
+
+uniform samplerCube irradianceMap;
+uniform samplerCube prefilterMap;
+uniform sampler2D brdfMap;
 
 out vec4 fragColor;
 
-uniform vec3 lightPositions[4];
-uniform vec3 lightColors[4];
+uniform int numLights;
+uniform vec3 lightPositions[8];
+uniform vec3 lightColors[8];
 
 const float PI = 3.14159265359;
 
@@ -24,6 +32,10 @@ vec3 fresnelSchlick(float cosTheta, vec3 F0) {
        return F0 + (1.f - F0) * pow(1.f - cosTheta, 5.f);
 }
 
+vec3 fresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness) {
+       return F0 + (max(vec3(1.f - roughness), F0) - F0) * pow(1.f - cosTheta, 5.f);
+}
+
 float distributionGGX(vec3 N, vec3 H, float roughness) {
        float a = roughness * roughness;
        float NdotH = mdot(N, H);
@@ -45,7 +57,9 @@ float geometrySmith(vec3 N, vec3 V, vec3 L, float roughness) {
 }
 
 vec3 getNormalFromMap() {
-       vec3 tangentNormal = texture(normalMap, texCoords).xyz * 2.f - 1.f;
+       vec3 tangentNormal = vec3(0, 0, 1);
+       if (mat.hasNormal)
+               tangentNormal = texture(mat.normalMap, texCoords).xyz * 2.f - 1.f;
        vec3 Q1 = dFdx(worldPos);
     vec3 Q2 = dFdy(worldPos);
     vec2 st1 = dFdx(texCoords);
@@ -60,20 +74,29 @@ vec3 getNormalFromMap() {
 }
 
 void main() {
-       vec3 albedo = pow(texture(albedoMap, texCoords).rgb, vec3(2.2));
+       vec3 albedo = vec3(1);
+       if (mat.hasAlbedo)
+               albedo = pow(texture(mat.albedoMap, texCoords).rgb, vec3(2.2));
+
        vec3 normal = getNormalFromMap();
-       float metallic = texture(metallicMap, texCoords).r;
-       float roughness = texture(roughnessMap, texCoords).r;
-       float ao = texture(aoMap, texCoords).r;
+
+       float metallic = 0, roughness = 1;
+       if (mat.hasMetallicRoughness) {
+               metallic = texture(mat.metallicRoughnessMap, texCoords).b;
+               roughness = texture(mat.metallicRoughnessMap, texCoords).g;
+       }
+       float ao = mat.hasAo ? texture(mat.aoMap, texCoords).r : 1;
 
        vec3 N = normalize(normal);
        vec3 V = normalize(camPos - worldPos);
 
        vec3 F0 = mix(vec3(0.04), albedo, metallic);
 
+       vec3 R = reflect(-V, N);
+
        // reflectance
        vec3 Lo = vec3(0.f);
-       for (int i = 0; i < lightPositions.length(); i++) {
+       for (int i = 0; i < numLights; i++) {
                vec3 L = normalize(lightPositions[i] - worldPos);
                vec3 H = normalize(V + L);
 
@@ -97,7 +120,20 @@ void main() {
                Lo += (kD * albedo / PI + specular) * radiance * mdot(N, L);
        }
 
-       vec3 ambient = vec3(0.03) * albedo * ao;
+       vec3 F = fresnelSchlickRoughness(mdot(N, V), F0, roughness);
+       
+       vec3 kS = F;
+       vec3 kD = (1.f - kS) * (1.f - metallic);
+
+       vec3 irradiance = texture(irradianceMap, N).rgb;
+       vec3 diffuse = irradiance * albedo;
+
+       const float maxReflectionLoD = 4.f;
+       vec3 prefilteredColor = textureLod(prefilterMap, R, roughness * maxReflectionLoD).rgb;
+       vec2 envBRDF = texture(brdfMap, vec2(mdot(N, V), roughness)).rg;
+       vec3 specular = prefilteredColor * (F * envBRDF.x + envBRDF.y);
+
+       vec3 ambient = (kD * diffuse + specular) * ao;
        vec3 color = ambient + Lo;
 
        color = color / (color + vec3(1.f)); // map to HDR