diff --git a/data/shaders/pbribl/prefilterenvmap.frag b/data/shaders/pbribl/prefilterenvmap.frag index dada35f0..ae1212ed 100644 --- a/data/shaders/pbribl/prefilterenvmap.frag +++ b/data/shaders/pbribl/prefilterenvmap.frag @@ -8,7 +8,7 @@ layout (binding = 0) uniform samplerCube samplerEnv; layout(push_constant) uniform PushConsts { layout (offset = 64) float roughness; layout (offset = 68) uint numSamples; -} pushConsts; +} consts; const float PI = 3.1415926536; @@ -69,14 +69,29 @@ vec3 prefilterEnvMap(vec3 R, float roughness) vec3 V = R; vec3 color = vec3(0.0); float totalWeight = 0.0; - for(uint i = 0u; i < pushConsts.numSamples; i++) { - vec2 Xi = hammersley2d(i, pushConsts.numSamples); + float envMapDim = float(textureSize(samplerEnv, 0).s); + for(uint i = 0u; i < consts.numSamples; i++) { + vec2 Xi = hammersley2d(i, consts.numSamples); vec3 H = importanceSample_GGX(Xi, roughness, N); vec3 L = 2.0 * dot(V, H) * H - V; float dotNL = clamp(dot(N, L), 0.0, 1.0); if(dotNL > 0.0) { - color += texture(samplerEnv, L).rgb * dotNL; + // Filtering based on https://placeholderart.wordpress.com/2015/07/28/implementation-notes-runtime-environment-map-filtering-for-image-based-lighting/ + + float dotNH = clamp(dot(N, H), 0.0, 1.0); + float dotVH = clamp(dot(V, H), 0.0, 1.0); + + // Probability Distribution Function + float pdf = D_GGX(dotNH, roughness) * dotNH / (4.0 * dotVH) + 0.0001; + // Slid angle of current smple + float omegaS = 1.0 / (float(consts.numSamples) * pdf); + // Solid angle of 1 pixel across all cube faces + float omegaP = 4.0 * PI / (6.0 * envMapDim * envMapDim); + // Biased (+1.0) mip level for better result + float mipLevel = roughness == 0.0 ? 0.0 : max(0.5 * log2(omegaS / omegaP) + 1.0, 0.0f); + color += textureLod(samplerEnv, L, mipLevel).rgb * dotNL; totalWeight += dotNL; + } } return (color / totalWeight); @@ -86,5 +101,5 @@ vec3 prefilterEnvMap(vec3 R, float roughness) void main() { vec3 N = normalize(inPos); - outColor = vec4(prefilterEnvMap(N, pushConsts.roughness), 1.0); + outColor = vec4(prefilterEnvMap(N, consts.roughness), 1.0); } diff --git a/data/shaders/pbribl/prefilterenvmap.frag.spv b/data/shaders/pbribl/prefilterenvmap.frag.spv index 0cdcde25..269e5d55 100644 Binary files a/data/shaders/pbribl/prefilterenvmap.frag.spv and b/data/shaders/pbribl/prefilterenvmap.frag.spv differ diff --git a/pbribl/pbribl.cpp b/pbribl/pbribl.cpp index 0bf5ef39..8f37014f 100644 --- a/pbribl/pbribl.cpp +++ b/pbribl/pbribl.cpp @@ -260,8 +260,6 @@ public: models.objects.push_back(model); } textures.environmentCube.loadFromFile(ASSET_PATH "textures/hdr/pisa_cube.ktx", VK_FORMAT_R16G16B16A16_SFLOAT, vulkanDevice, queue); - // Irradiance map generated offline with https://github.com/dariomanesku/cmft - // textures.irradianceCube.loadFromFile(ASSET_PATH "textures/hdr/pisa_cube_irradiance.ktx", VK_FORMAT_R16G16B16A16_SFLOAT, vulkanDevice, queue); } void setupDescriptors() @@ -1199,7 +1197,7 @@ public: struct PushBlock { glm::mat4 mvp; float roughness; - uint32_t numSamples = 1024u; + uint32_t numSamples = 32u; } pushBlock; VkPipelineLayout pipelinelayout; @@ -1439,7 +1437,7 @@ public: // 3D object uboMatrices.projection = camera.matrices.perspective; uboMatrices.view = camera.matrices.view; - uboMatrices.model = glm::rotate(glm::mat4(), glm::radians(-90.0f + (models.objectIndex == 1 ? 45.0f : 0.0f)), glm::vec3(0.0f, 1.0f, 0.0f)); + uboMatrices.model = glm::rotate(glm::mat4(), glm::radians(90.0f + (models.objectIndex == 1 ? -45.0f : 0.0f)), glm::vec3(0.0f, 1.0f, 0.0f)); uboMatrices.camPos = camera.position * -1.0f; memcpy(uniformBuffers.object.mapped, &uboMatrices, sizeof(uboMatrices));