diff options
author | pryazha <pryadeiniv@mail.ru> | 2025-08-02 13:21:42 +0500 |
---|---|---|
committer | pryazha <pryadeiniv@mail.ru> | 2025-08-02 13:21:42 +0500 |
commit | 2e64d3c5d6eb1eb04168d39d5eb5f2d89af1a8b0 (patch) | |
tree | 85c8a586a1343469cdcdab5dccad023053571ecd /pbr/ibl_specular/prefilter.frag | |
parent | 33d5f67044d104d69cb2d11e78e6a79bc20d4c4e (diff) |
Diffstat (limited to 'pbr/ibl_specular/prefilter.frag')
-rw-r--r-- | pbr/ibl_specular/prefilter.frag | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/pbr/ibl_specular/prefilter.frag b/pbr/ibl_specular/prefilter.frag new file mode 100644 index 0000000..5359c58 --- /dev/null +++ b/pbr/ibl_specular/prefilter.frag @@ -0,0 +1,91 @@ +#version 330 core + +in vert_t { + vec3 position; +} vert; + +out vec4 frag_color; + +uniform samplerCube cubemap; +uniform float roughness; + +const float PI = 3.14159265359; + +float distribution_ggx(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 radical_inverse_vdc(uint bits) +{ + bits = (bits << 16u) | (bits >> 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); + return float(bits) * 2.3283064365386963e-10; // / 0x100000000 +} + +vec2 hammersley(uint i, uint n) +{ + return vec2(float(i) / float(n), radical_inverse_vdc(i)); +} + +vec3 importance_sample_ggx(vec2 xi, vec3 n, float roughness) +{ + float a = roughness * roughness; + + float phi = 2.0 * PI * xi.x; + float cos_theta = sqrt((1.0 - xi.y) / (1.0 + (a * a - 1.0) * xi.y)); + float sin_theta = sqrt(1.0 - cos_theta * cos_theta); + + vec3 h; + h.x = cos(phi) * sin_theta; + h.y = sin(phi) * sin_theta; + h.z = cos_theta; + + vec3 up = abs(n.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); + vec3 tangent = normalize(cross(up, n)); + vec3 bitangent = cross(n, tangent); + + vec3 samplevec = tangent * h.x + bitangent * h.y + n * h.z; + return normalize(samplevec); +} + +void main(void) +{ + vec3 n = normalize(vert.position); + vec3 r = n; + vec3 v = r; + + uint count = 1024u; + float total = 0.0; + vec3 prefiltered = vec3(0.0); + for (uint i = 0u; i < count; i++) { + vec2 xi = hammersley(i, count); + vec3 h = importance_sample_ggx(xi, n, roughness); + vec3 l = normalize(2.0 * dot(v, h) * h - v); + float ndotl = max(dot(n, l), 0.0); + if (ndotl > 0.0) { + float d = distribution_ggx(n, h, roughness); + float ndoth = max(dot(n, h), 0.0); + float hdotv = max(dot(h, v), 0.0); + float pdf = d * ndoth / (4.0 * hdotv) + 0.0001; + float resolution = 512.0; + float sa_texel = 4.0 * PI / (6.0 * resolution * resolution); + float sa_sample = 1.0 / (float(count) * pdf + 0.0001); + float mip_level = roughness == 0.0 ? 0.0 : 0.5 * log2(sa_sample / sa_texel); + prefiltered += textureLod(cubemap, l, mip_level).rgb * ndotl; + total += ndotl; + } + } + prefiltered /= total; + frag_color = vec4(prefiltered, 1.0); +} |