summaryrefslogtreecommitdiffstats
path: root/res/effectlib/physGlossyBSDF.glsllib
diff options
context:
space:
mode:
Diffstat (limited to 'res/effectlib/physGlossyBSDF.glsllib')
-rw-r--r--res/effectlib/physGlossyBSDF.glsllib159
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