X-Git-Url: http://git.lukelau.me/?p=opengl.git;a=blobdiff_plain;f=pbrfrag.glsl;h=d4c7eceb7e26cbb97e529768c50ce9a1469454ef;hp=4421b99b6021a9e6a7da4953122bebf30bbf2499;hb=5e2b8438a1600a790dc105d25b7d5cd2278864aa;hpb=a03f2bc751bbd7f91cbc2f52d2f0f6e753d6f776 diff --git a/pbrfrag.glsl b/pbrfrag.glsl index 4421b99..d4c7ece 100644 --- a/pbrfrag.glsl +++ b/pbrfrag.glsl @@ -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