diff options
Diffstat (limited to 'res/effectlib/physGlossyBSDF.glsllib')
-rw-r--r-- | res/effectlib/physGlossyBSDF.glsllib | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/res/effectlib/physGlossyBSDF.glsllib b/res/effectlib/physGlossyBSDF.glsllib new file mode 100644 index 0000000..ece836b --- /dev/null +++ b/res/effectlib/physGlossyBSDF.glsllib @@ -0,0 +1,159 @@ +/**************************************************************************** +** +** Copyright (C) 2014 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PHYS_GLOSSY_BSDF_GLSLLIB +#define PHYS_GLOSSY_BSDF_GLSLLIB 1 + +float sqr(float v) +{ + return v*v; +} + +float Gterm( float cosTheta, float roughness ) +{ + float k = roughness * 0.31830988618; // roughness / pi + return clamp( ( cosTheta / (cosTheta*(1.0-k) + k) + (1.0 - k*k) ) * 0.5, 0.0, 1.0 ); +} + + +// PKC -- I came up with an anisotropic microfacet BSDF that has some superficial similarity to GGX in +// its appearance, but is far simpler and more compact in its implementation. It uses a Cauchy-like lobe +// shape and because it has an analytic solution to its antiderivative, we can compute the integral given +// the support boundaries. It's also possible to importance sample at perfect efficiency. +// This is generally a good choice for any material which has a polish coating to it. +// TODO : The way roughness scales with this BSDF is roughly equivalent to roughness^2 would affect Ward. +// It's debatable whether we want that to be done as a sqrt here or as square in Ward. +vec4 kggxGlossyBSDF( in mat3 tanFrame, in vec3 L, in vec3 V, in vec3 lightSpecular, float ior, + in float roughnessU, in float roughnessV, int mode ) +{ + vec4 rgba = vec4( 0.0, 0.0, 0.0, 1.0 ); + vec3 H = normalize(L + V); + + // NOTE : This BSDF allows roughness up to 2.0 which allows it + // to trend partially into Oren-Nayar diffuse territory, but we should + // assume that anything that falls under "glossy" should still be + // in the range of 0..1 + float ax = clamp(roughnessU, 0.0001, 2.0); + float ay = clamp(roughnessV, 0.0001, 2.0); + + float NdotL = dot(tanFrame[2], L); + float HdotL = clamp(dot(H, L), 0.0, 1.0); + + // if (0.0 < NdotL) + // { + vec3 Haf = L + V; + + float HdotN = clamp( dot(H, tanFrame[2]), 0.0001, 1.0 ); + float HdotX = clamp( abs(dot(H, tanFrame[0])), 0.0001, 1.0 ); + float HdotY = clamp( abs(dot(H, tanFrame[1])), 0.0001, 1.0 ); + + float sigma = sqrt(ax * ay); + float sigma2 = ax * ay * HdotN; + + float thetaI = acos( dot(V, tanFrame[2]) ); + float maxThetaI = (thetaI + 1.57079632679) * 0.5; + float minThetaI = (thetaI - 1.57079632679) * 0.5; + float range = atan(maxThetaI / sigma) - atan(minThetaI / sigma); + range = max( range, ax*ay ); + + if ( ( mode == scatter_reflect ) || ( mode == scatter_reflect_transmit ) ) + { + float PDF = sigma2 / (sigma2 + sqr(HdotX / ax) + sqr(HdotY / ay)); + PDF *= dot(Haf, Haf) / (4.71238898038 * sqr(dot(Haf, L)) * ax*ay * sigma * sqr(range)); + + rgba.rgb = Gterm(HdotL, sigma) * lightSpecular * PDF * max(NdotL, 0.0); + } + if ( ( mode == scatter_transmit ) || ( mode == scatter_reflect_transmit ) ) + { + rgba.a = pow(1.0 - clamp(HdotL, 0.0, 1.0), 5.0); + } +// } + return rgba; +} + +vec4 kggxGlossyDefaultMtl( in vec3 normal, in vec3 tangent, in vec3 L, in vec3 V, in vec3 lightSpecular, + in vec3 materialSpecular, in float roughU, in float roughV ) +{ + vec3 bitan = normalize(cross(normal, tangent)); + mat3 tanFrame = mat3( normalize(cross( bitan, normal) ), bitan, normal ); + return vec4(materialSpecular, 1.0) * kggxGlossyBSDF( tanFrame, L, V, lightSpecular, 1.5, roughU, roughV, scatter_reflect ); +} + +// To be exact, this is not the Ward lobe as Ward originally described (there are a few flaws in +// the original paper, which had spawned half a dozen corrective measures as papers of their own). +// This is a Ward-Duer variant with Geisler-Moroder's modified normalization factor which serves +// to bound the albedo. +vec4 wardGlossyBSDF( in mat3 tanFrame, in vec3 L, in vec3 V, in vec3 lightSpecular, in float ior, + in float roughnessU, in float roughnessV, int mode ) +{ + vec4 rgba = vec4( 0.0, 0.0, 0.0, 1.0 ); + vec3 H = normalize(L + V); + + // specular + float ax = clamp(roughnessU, 0.0001, 1.0); + float ay = clamp(roughnessV, 0.0001, 1.0); + + float NdotL = dot(tanFrame[2], L); + float HdotL = clamp(dot(H, L), 0.0, 1.0); + +// if (0.0 < NdotL) +// { + vec3 Haf = L + V; + + float HdotN = clamp( dot(H, tanFrame[2]), 0.0001, 1.0 ); + float HdotX = clamp( abs(dot(H, tanFrame[0])), 0.0001, 1.0 ); + float HdotY = clamp( abs(dot(H, tanFrame[1])), 0.0001, 1.0 ); + + if ( ( mode == scatter_reflect ) || ( mode == scatter_reflect_transmit ) ) + { + float exponent = -(sqr(HdotX/ax) + sqr(HdotY/ay)); + exponent /= sqr(HdotN); + float PDF = exp(exponent) / (4.0 * 3.1415926535 * ax * ay); + PDF *= 4.0 * dot(Haf, Haf) / sqr(sqr(dot(Haf,tanFrame[2]))); + + rgba.rgb = Gterm(HdotL, sqrt(ax * ay)) * lightSpecular * PDF * max(NdotL, 0.0); + } + if ( ( mode == scatter_transmit ) || ( mode == scatter_reflect_transmit ) ) + { + rgba.a = pow(1.0 - clamp(HdotL, 0.0, 1.0), 5.0); + } +// } + return rgba; +} + +vec4 wardGlossyDefaultMtl( in vec3 normal, in vec3 tangent, in vec3 L, in vec3 V, in vec3 lightSpecular, + in vec3 materialSpecular, in float roughU, in float roughV ) +{ + vec3 bitan = normalize(cross(normal, tangent)); + mat3 tanFrame = mat3( normalize(cross( bitan, normal) ), bitan, normal ); + return vec4(materialSpecular, 1.0) * wardGlossyBSDF( tanFrame, L, V, lightSpecular, 1.5, roughU, roughV, scatter_reflect ); +} + +#endif |