From fae589cf651fc7083e30b294bb292458396aae54 Mon Sep 17 00:00:00 2001 From: saschawillems Date: Tue, 18 Apr 2017 21:26:32 +0200 Subject: [PATCH] Added shaders for PBR IBL BRDF LUT generation --- data/shaders/pbribl/genbrdflut.frag | 90 ++++++++++++++++++++++++ data/shaders/pbribl/genbrdflut.frag.spv | Bin 0 -> 8032 bytes data/shaders/pbribl/genbrdflut.vert | 9 +++ data/shaders/pbribl/genbrdflut.vert.spv | Bin 0 -> 1160 bytes 4 files changed, 99 insertions(+) create mode 100644 data/shaders/pbribl/genbrdflut.frag create mode 100644 data/shaders/pbribl/genbrdflut.frag.spv create mode 100644 data/shaders/pbribl/genbrdflut.vert create mode 100644 data/shaders/pbribl/genbrdflut.vert.spv diff --git a/data/shaders/pbribl/genbrdflut.frag b/data/shaders/pbribl/genbrdflut.frag new file mode 100644 index 00000000..b6290dd0 --- /dev/null +++ b/data/shaders/pbribl/genbrdflut.frag @@ -0,0 +1,90 @@ +#version 450 + +layout (location = 0) in vec2 inUV; +layout (location = 0) out vec4 outColor; +layout (constant_id = 0) const uint NUM_SAMPLES = 1024u; + +const float PI = 3.1415926536; + +// Based omn http://byteblacksmith.com/improvements-to-the-canonical-one-liner-glsl-rand-for-opengl-es-2-0/ +float random(vec2 co) +{ + float a = 12.9898; + float b = 78.233; + float c = 43758.5453; + float dt= dot(co.xy ,vec2(a,b)); + float sn= mod(dt,3.14); + return fract(sin(sn) * c); +} + +vec2 hammersley2d(uint i, uint N) +{ + // Radical inverse based on http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html + uint bits = (i << 16u) | (i >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + float rdi = float(bits) * 2.3283064365386963e-10; + return vec2(float(i) /float(N), rdi); +} + +// Based on http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_slides.pdf +vec3 importanceSample_GGX(vec2 Xi, float roughness, vec3 normal) +{ + // Maps a 2D point to a hemisphere with spread based on roughness + float alpha = roughness * roughness; + float phi = 2.0 * PI * Xi.x + random(normal.xz) * 0.1; + float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (alpha*alpha - 1.0) * Xi.y)); + float sinTheta = sqrt(1.0 - cosTheta * cosTheta); + vec3 H = vec3(sinTheta * cos(phi), sinTheta * sin(phi), cosTheta); + + // Tangent space + vec3 up = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); + vec3 tangentX = normalize(cross(up, normal)); + vec3 tangentY = normalize(cross(normal, tangentX)); + + // Convert to world Space + return normalize(tangentX * H.x + tangentY * H.y + normal * H.z); +} + +// Geometric Shadowing function +float G_SchlicksmithGGX(float dotNL, float dotNV, float roughness) +{ + float k = (roughness * roughness) / 2.0; + float GL = dotNL / (dotNL * (1.0 - k) + k); + float GV = dotNV / (dotNV * (1.0 - k) + k); + return GL * GV; +} + +vec2 BRDF(float NoV, float roughness) +{ + // Normal always points along z-axis for the 2D lookup + const vec3 N = vec3(0.0, 0.0, 1.0); + vec3 V = vec3(sqrt(1.0 - NoV*NoV), 0.0, NoV); + + vec2 LUT = vec2(0.0); + for(uint i = 0u; i < NUM_SAMPLES; i++) { + vec2 Xi = hammersley2d(i, NUM_SAMPLES); + vec3 H = importanceSample_GGX(Xi, roughness, N); + vec3 L = 2.0 * dot(V, H) * H - V; + + float dotNL = max(dot(N, L), 0.0); + float dotNV = max(dot(N, V), 0.0); + float dotVH = max(dot(V, H), 0.0); + float dotNH = max(dot(H, N), 0.0); + + if (dotNL > 0.0) { + float G = G_SchlicksmithGGX(dotNL, dotNV, roughness); + float G_Vis = (G * dotVH) / (dotNH * dotNV); + float Fc = pow(1.0 - dotVH, 5.0); + LUT += vec2((1.0 - Fc) * G_Vis, Fc * G_Vis); + } + } + return LUT / float(NUM_SAMPLES); +} + +void main() +{ + outColor = vec4(BRDF(inUV.s, 1.0-inUV.t), 0.0, 1.0); +} \ No newline at end of file diff --git a/data/shaders/pbribl/genbrdflut.frag.spv b/data/shaders/pbribl/genbrdflut.frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..fa7ff160430992bcb515ccc2ca4f0e22a1c92dd1 GIT binary patch literal 8032 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 G=h#2raz-Zr literal 0 HcmV?d00001