diff options
Diffstat (limited to 'res/effectlib')
-rw-r--r-- | res/effectlib/customMaterial.glsllib | 3 | ||||
-rw-r--r-- | res/effectlib/defaultMaterialFresnel.glsllib | 6 | ||||
-rw-r--r-- | res/effectlib/distancefieldtext.frag | 4 | ||||
-rw-r--r-- | res/effectlib/distancefieldtext_core.frag | 4 | ||||
-rw-r--r-- | res/effectlib/distancefieldtext_dropshadow.frag | 8 | ||||
-rw-r--r-- | res/effectlib/distancefieldtext_dropshadow_core.frag | 8 | ||||
-rw-r--r-- | res/effectlib/evalBakedShadowMap.glsllib | 2 | ||||
-rw-r--r-- | res/effectlib/funcdiffuseReflectionBSDF.glsllib | 39 | ||||
-rw-r--r-- | res/effectlib/funcsampleAreaGlossyDefault.glsllib | 29 | ||||
-rw-r--r-- | res/effectlib/funcsampleNormalTexture.glsllib | 6 | ||||
-rw-r--r-- | res/effectlib/funcspecularBSDF.glsllib | 40 | ||||
-rw-r--r-- | res/effectlib/gles2/sampleProbe.glsllib | 482 | ||||
-rw-r--r-- | res/effectlib/gles2/sampleProbePre.glsllib | 7 | ||||
-rw-r--r-- | res/effectlib/luminance.glsllib | 28 | ||||
-rw-r--r-- | res/effectlib/sampleProbe.glsllib | 398 | ||||
-rw-r--r-- | res/effectlib/sampleProbePre.glsllib | 5 | ||||
-rw-r--r-- | res/effectlib/specularBSDF.glsllib | 18 | ||||
-rw-r--r-- | res/effectlib/transformCoordinate.glsllib | 9 |
18 files changed, 166 insertions, 930 deletions
diff --git a/res/effectlib/customMaterial.glsllib b/res/effectlib/customMaterial.glsllib index 0a4d88b..d6f392e 100644 --- a/res/effectlib/customMaterial.glsllib +++ b/res/effectlib/customMaterial.glsllib @@ -31,9 +31,6 @@ #ifndef CUSTOM_MATERIAL_GLSLLIB #define CUSTOM_MATERIAL_GLSLLIB 1 -#define SNAPPER_SAMPLER2D(samplerName, samplerNiceName, texFilter, texWrap, showUI )\ -uniform sampler2D samplerName; - // some useful defines #ifndef PI #define PI 3.14159265358979 diff --git a/res/effectlib/defaultMaterialFresnel.glsllib b/res/effectlib/defaultMaterialFresnel.glsllib index e0eff4f..7a363e9 100644 --- a/res/effectlib/defaultMaterialFresnel.glsllib +++ b/res/effectlib/defaultMaterialFresnel.glsllib @@ -31,13 +31,11 @@ #ifndef DEFAULT_MATERIAL_FRESNEL_GLSLLIB #define DEFAULT_MATERIAL_FRESNEL_GLSLLIB -float defaultMaterialSimpleFresnel( in vec3 N, in vec3 viewDir, in float ior, float fresnelPower ) +float defaultMaterialSimpleFresnel(in vec3 N, in vec3 viewDir, in float ior, float fresnelPower) { float F = ((1.0-ior) * (1.0-ior)) / ((1.0+ior) * (1.0+ior)); - float VdotN = dot(viewDir, N); - VdotN = clamp( VdotN, 0.0, 1.0 ); + float VdotN = max(dot(viewDir, N), 0.0); float ratio = F + (1.0 - F) * pow(1.0 - VdotN, fresnelPower); - return ratio; } diff --git a/res/effectlib/distancefieldtext.frag b/res/effectlib/distancefieldtext.frag index 1d83490..2236f9c 100644 --- a/res/effectlib/distancefieldtext.frag +++ b/res/effectlib/distancefieldtext.frag @@ -20,8 +20,8 @@ void main() #ifdef use_fallback highp float alpha = smoothstep(alphas.x, alphas.y, distance); #else - highp float f = fwidth(distance); - highp float alpha = smoothstep(0.5 - f, 0.5, distance); + highp float f = fwidth(distance) * 0.5; + highp float alpha = smoothstep(0.5 - f, 0.5 + f, distance); #endif gl_FragColor = color * alpha; diff --git a/res/effectlib/distancefieldtext_core.frag b/res/effectlib/distancefieldtext_core.frag index f11dcc1..a3a25a2 100644 --- a/res/effectlib/distancefieldtext_core.frag +++ b/res/effectlib/distancefieldtext_core.frag @@ -6,6 +6,6 @@ uniform vec4 color; void main() { float distance = texture(_qt_texture, sampleCoord).r; - float f = fwidth(distance); - fragOutput = color * smoothstep(0.5 - f, 0.5, distance); + float f = fwidth(distance) * 0.5; + fragOutput = color * smoothstep(0.5 - f, 0.5 + f, distance); } diff --git a/res/effectlib/distancefieldtext_dropshadow.frag b/res/effectlib/distancefieldtext_dropshadow.frag index fdb68ba..2f6c9be 100644 --- a/res/effectlib/distancefieldtext_dropshadow.frag +++ b/res/effectlib/distancefieldtext_dropshadow.frag @@ -25,8 +25,8 @@ void main() #ifdef use_fallback highp float shadowAlpha = smoothstep(alphas.x, alphas.y, shadowDistance); #else - highp float shadowDistanceD = fwidth(shadowDistance); - highp float shadowAlpha = smoothstep(0.5 - shadowDistanceD, 0.5, shadowDistance); + highp float shadowDistanceD = fwidth(shadowDistance) * 0.5; + highp float shadowAlpha = smoothstep(0.5 - shadowDistanceD, 0.5 + shadowDistanceD, shadowDistance); #endif highp vec4 shadowPixel = color * shadowColor * shadowAlpha; @@ -38,8 +38,8 @@ void main() #ifdef use_fallback highp float textAlpha = smoothstep(alphas.x, alphas.y, textDistance); #else - highp float textDistanceD = fwidth(textDistance); - highp float textAlpha = smoothstep(0.5 - textDistanceD, 0.5, textDistance); + highp float textDistanceD = fwidth(textDistance) * 0.5; + highp float textAlpha = smoothstep(0.5 - textDistanceD, 0.5 + textDistanceD, textDistance); #endif highp vec4 textPixel = color * textAlpha; diff --git a/res/effectlib/distancefieldtext_dropshadow_core.frag b/res/effectlib/distancefieldtext_dropshadow_core.frag index e13182e..8e8c61d 100644 --- a/res/effectlib/distancefieldtext_dropshadow_core.frag +++ b/res/effectlib/distancefieldtext_dropshadow_core.frag @@ -12,16 +12,16 @@ void main() clamp(shadowSampleCoord, normalizedTextureBounds.xy, normalizedTextureBounds.zw)).r; - float shadowDistanceD = fwidth(shadowDistance); - float shadowAlpha = smoothstep(0.5 - shadowDistanceD, 0.5, shadowDistance); + float shadowDistanceD = fwidth(shadowDistance) * 0.5; + float shadowAlpha = smoothstep(0.5 - shadowDistanceD, 0.5 + shadowDistanceD, shadowDistance); vec4 shadowPixel = color * shadowColor * shadowAlpha; float textDistance = texture(_qt_texture, clamp(sampleCoord, normalizedTextureBounds.xy, normalizedTextureBounds.zw)).r; - float textDistanceD = fwidth(textDistance); - float textAlpha = smoothstep(0.5 - textDistanceD, 0.5, textDistance); + float textDistanceD = fwidth(textDistance) * 0.5; + float textAlpha = smoothstep(0.5 - textDistanceD, 0.5 + textDistanceD, textDistance); vec4 textPixel = color * textAlpha; fragOutput = mix(shadowPixel, textPixel, textPixel.a); diff --git a/res/effectlib/evalBakedShadowMap.glsllib b/res/effectlib/evalBakedShadowMap.glsllib index a283d8a..7ea3887 100644 --- a/res/effectlib/evalBakedShadowMap.glsllib +++ b/res/effectlib/evalBakedShadowMap.glsllib @@ -30,7 +30,7 @@ vec4 evalBakedShadowMap( in vec3 inCoords ) { - vec4 shadowCol = (uShadowMappingEnabled) ? texture( uBakedShadowTexture, inCoords.xy ) : vec4( 1.0, 1.0, 1.0, 1.0 ); + vec4 shadowCol = (uShadowMappingEnabled) ? texture( uBakedShadowTexture, texcoordTransformed_uBakedShadowTexture(inCoords).xy ) : vec4( 1.0, 1.0, 1.0, 1.0 ); return shadowCol; } diff --git a/res/effectlib/funcdiffuseReflectionBSDF.glsllib b/res/effectlib/funcdiffuseReflectionBSDF.glsllib index bda0ea6..05f54a6 100644 --- a/res/effectlib/funcdiffuseReflectionBSDF.glsllib +++ b/res/effectlib/funcdiffuseReflectionBSDF.glsllib @@ -3,41 +3,8 @@ #define PI_SQUARE ( PI * PI ) #endif -vec4 diffuseReflectionBSDF(in vec3 N, in vec3 L, in vec3 viewDir, - in vec3 lightDiffuse, in float roughness) +vec4 diffuseReflectionBSDF(in vec3 N, in vec3 L, in vec3 lightDiffuse) { - float cosThetaI = max( 0.0, dot( N, L ) ); - float factor = cosThetaI; - if ( ( 0.0 < factor ) && ( 0.0 < roughness ) ) - { - // see http://en.wikipedia.org/wiki/Oren%E2%80%93Nayar_reflectance_model - float sigmaSquare = 0.25 * PI_SQUARE * roughness * roughness; - float A = 1.0 - 0.5 * sigmaSquare / ( sigmaSquare + 0.33 ); - float B = 0.45 * sigmaSquare / ( sigmaSquare + 0.09 ); - - // project L and viewDir on surface to get the azimuthal angle between them - // as we don't really need the projections, but the angle between them, - // it's enough to just use the cross instead - vec3 pl = normalize( cross( L, N ) ); - vec3 pv = normalize( cross( viewDir, N ) ); - float cosPhi = max( 0.0, dot( pl, pv ) ); - - float sinAlpha, tanBeta; - float cosThetaO = max( 0.0, dot( N, viewDir ) ); - float sinThetaI = sqrt( max( 0.0, 1.0 - cosThetaI * cosThetaI ) ); - float sinThetaO = sqrt( max( 0.0, 1.0 - cosThetaO * cosThetaO ) ); - if ( cosThetaI < cosThetaO ) - { // -> thetaO < thetaI - sinAlpha = sinThetaI; - tanBeta = sinThetaO / cosThetaO; - } - else - { - sinAlpha = sinThetaO; - tanBeta = sinThetaI / cosThetaI; - } - - factor *= A + B * cosPhi * sinAlpha * tanBeta; - } - return( vec4( factor * lightDiffuse, 1.0 ) ); + float factor = max(0.0, dot(N, L)); + return vec4(factor * lightDiffuse, 1.0); } diff --git a/res/effectlib/funcsampleAreaGlossyDefault.glsllib b/res/effectlib/funcsampleAreaGlossyDefault.glsllib index cb9cba1..586c693 100644 --- a/res/effectlib/funcsampleAreaGlossyDefault.glsllib +++ b/res/effectlib/funcsampleAreaGlossyDefault.glsllib @@ -1,25 +1,26 @@ #include "funccomputeMicroHit.glsllib" -vec3 sampleAreaGlossyDefault( in mat3 tanFrame, in vec3 pos, in mat3 lightFrame, in vec3 lightPos, in float width, in float height, in vec3 viewDir, in float roughU, in float roughV ) +vec3 sampleAreaGlossyDefault(in mat3 tanFrame, in vec3 pos, in mat3 lightFrame, in vec3 lightPos, + in float width, in float height, in vec3 viewDir, in float roughness) { - float sigmaU = clamp( 0.5 * roughU, 0.005, 0.5 ); - float sigmaV = clamp( 0.5 * roughV, 0.005, 0.5 ); + float sigma = clamp(0.5 * roughness, 0.005, 0.5); vec2 UVset[5]; - float thetaI = acos( dot(viewDir, lightFrame[2]) ); - vec2 minMaxThetaH = vec2( (thetaI - 1.5707) * 0.5, - (thetaI + 1.5707) * 0.5 ); - vec4 sinCosThetaH = vec4( abs(sin(minMaxThetaH)), abs(cos(minMaxThetaH)) ); + float thetaI = acos(dot(viewDir, lightFrame[2])); + vec2 minMaxThetaH = vec2((thetaI - 1.5707) * 0.5, (thetaI + 1.5707) * 0.5 ); + vec4 sinCosThetaH = vec4(abs(sin(minMaxThetaH)), abs(cos(minMaxThetaH))); // First thing we do is compute a small-scale version of the ray hit for a very tiny roughness // then we scale that up based on the _actual_ roughness. - float wt = computeMicroHit( pos, tanFrame, lightPos, lightFrame, width, height, viewDir, UVset ); + float wt = computeMicroHit(pos, tanFrame, lightPos, lightFrame, width, height, viewDir, UVset); UVset[0] -= UVset[4]; UVset[1] -= UVset[4]; UVset[2] -= UVset[4]; UVset[3] -= UVset[4]; - UVset[0] *= mix(1.0, sinCosThetaH.y / 0.005, sigmaU); UVset[1] *= mix(1.0, sinCosThetaH.x / 0.005, sigmaU); - UVset[2] *= mix(1.0, sinCosThetaH.y / 0.005, sigmaV); UVset[3] *= mix(1.0, sinCosThetaH.x / 0.005, sigmaV); + UVset[0] *= mix(1.0, sinCosThetaH.y / 0.005, sigma); + UVset[1] *= mix(1.0, sinCosThetaH.x / 0.005, sigma); + UVset[2] *= mix(1.0, sinCosThetaH.y / 0.005, sigma); + UVset[3] *= mix(1.0, sinCosThetaH.x / 0.005, sigma); UVset[0] += UVset[4]; UVset[1] += UVset[4]; UVset[2] += UVset[4]; UVset[3] += UVset[4]; @@ -31,12 +32,12 @@ vec3 sampleAreaGlossyDefault( in mat3 tanFrame, in vec3 pos, in mat3 lightFrame, UVmin = min(UVmin, UVset[2]); UVmax = max(UVmax, UVset[2]); UVmin = min(UVmin, UVset[3]); UVmax = max(UVmax, UVset[3]); - cminUV = clamp( UVmin, vec2(0.0), vec2(1.0) ); - cmaxUV = clamp( UVmax, vec2(0.0), vec2(1.0) ); + cminUV = clamp(UVmin, vec2(0.0), vec2(1.0)); + cmaxUV = clamp(UVmax, vec2(0.0), vec2(1.0)); vec2 hitScale = (cmaxUV - cminUV); vec2 fullScale = (UVmax - UVmin); - float intensity = ( hitScale.x * hitScale.y ) / max( fullScale.x * fullScale.y, 0.0001 ); + float intensity = (hitScale.x * hitScale.y) / max(fullScale.x * fullScale.y, 0.0001); - return vec3( wt * intensity ); + return vec3(wt * intensity); } diff --git a/res/effectlib/funcsampleNormalTexture.glsllib b/res/effectlib/funcsampleNormalTexture.glsllib new file mode 100644 index 0000000..552112a --- /dev/null +++ b/res/effectlib/funcsampleNormalTexture.glsllib @@ -0,0 +1,6 @@ +vec3 sampleNormalTexture(in sampler2D sampler, in float factor, in vec2 texCoord, in vec3 tangent, + in vec3 binormal, in vec3 normal) +{ + vec3 tsNormal = 2.0 * texture(sampler, texCoord).xyz - 1.0; + return mix(normal, normalize(tsNormal.x * tangent - tsNormal.y * binormal + tsNormal.z * normal), factor); +} diff --git a/res/effectlib/funcspecularBSDF.glsllib b/res/effectlib/funcspecularBSDF.glsllib index e9450bf..f774b0b 100644 --- a/res/effectlib/funcspecularBSDF.glsllib +++ b/res/effectlib/funcspecularBSDF.glsllib @@ -6,37 +6,15 @@ #define scatter_reflect_transmit 2 #endif -vec4 specularBSDF(in vec3 N, in vec3 L, in vec3 viewDir, in vec3 lightSpecular, - in float ior, in float shininess, in vec3 tint, int mode) +vec4 specularBSDF(in vec3 N, in vec3 L, in vec3 viewDir, in vec3 lightSpecular, in float shininess) { - vec4 rgba = vec4( 0.0, 0.0, 0.0, 1.0 ); - float cosTheta = dot( N, L ); - if ( 0.0 < cosTheta ) - { - if ( ( mode == scatter_reflect ) || ( mode == scatter_reflect_transmit ) ) - { - vec3 R = reflect( -L, N ); - float cosAlpha = max( 0.0, dot( R, viewDir ) ); - float shine = pow( cosAlpha, shininess ); - rgba.rgb = shine * lightSpecular; - } + vec4 rgba = vec4(0.0, 0.0, 0.0, 1.0); + float cosTheta = dot(N, L); + if (0.0 < cosTheta) { + vec3 R = reflect(-L, N); + float cosAlpha = max(0.0, dot(R, viewDir)); + float shine = pow(cosAlpha, shininess); + rgba.rgb = shine * lightSpecular; } - if ( ( mode == scatter_transmit ) || ( mode == scatter_reflect_transmit ) ) - { - // check against total reflection - vec3 R = refract( -viewDir, N, ior ); - if ( R == vec3( 0.0, 0.0, 0.0 ) ) - { - rgba.a = 1.0; - } - else if ( mode == scatter_transmit ) - { - rgba.a = 0.0; - } - else - { - rgba.a = 1.0 - luminance( tint ); - } - } - return( rgba ); + return rgba; } diff --git a/res/effectlib/gles2/sampleProbe.glsllib b/res/effectlib/gles2/sampleProbe.glsllib deleted file mode 100644 index f785918..0000000 --- a/res/effectlib/gles2/sampleProbe.glsllib +++ /dev/null @@ -1,482 +0,0 @@ -/**************************************************************************** -** -** 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 SAMPLE_PROBE_GLSLLIB -#define SAMPLE_PROBE_GLSLLIB 1 - -#ifndef QT3DS_ENABLE_LIGHT_PROBE_2 -#define QT3DS_ENABLE_LIGHT_PROBE_2 0 -#endif - -#ifndef QT3DS_ENABLE_IBL_FOV -#define QT3DS_ENABLE_IBL_FOV 0 -#endif - -uniform sampler2D light_probe; -uniform vec4 light_probe_props; -uniform vec4 light_probe_rotation; -uniform vec4 light_probe_offset; // light_probe_offset.w = number of mipmaps -uniform vec2 light_probe_size; - -#if QT3DS_ENABLE_LIGHT_PROBE_2 -uniform sampler2D light_probe2; -uniform vec4 light_probe2_props; -uniform vec2 light_probe2_size; -#endif - -#if QT3DS_ENABLE_IBL_FOV -uniform vec4 light_probe_opts; -#endif - -float noise1d(vec2 n) -{ - return 0.5 + 0.5 * fract(sin(dot(n.xy, vec2(12.9898, 78.233)))* 43758.5453); -} - -mat3 orthoNormalize( in mat3 tanFrame ) -{ - mat3 outMat; - outMat[0] = normalize( cross( tanFrame[1], tanFrame[2] ) ); - outMat[1] = normalize( cross( tanFrame[2], outMat[0] ) ); - outMat[2] = tanFrame[2]; - - return outMat; -} - -mat3 tangentFrame( vec3 N, vec3 p ) -{ - // get edge vectors of the pixel triangle - vec3 dp1 = dFdx( p ); - vec3 dp2 = dFdy( p ); - // Using dPdu and dPdv would be nicer, but the nature of our materials - // are not ones with intrinsic UVs, so we can't really go there. -// vec2 duv1 = dFdx( uv ); -// vec2 duv2 = dFdy( uv ); - - // solve the linear system - vec3 dp2perp = cross( dp2, N ); - vec3 dp1perp = cross( N, dp1 ); -// vec3 T = dp2perp * duv1.x + dp1perp * duv2.x; -// vec3 B = dp2perp * duv1.y + dp1perp * duv2.y; - - vec3 T = normalize(dp1perp); - vec3 B = normalize(dp2perp); - return mat3( T , B , N ); -} - -vec2 transformSample( vec2 origUV, vec4 probeRot, vec2 probeOfs ) -{ - vec2 retUV; - retUV.x = dot( vec3(origUV, 1.0), vec3(probeRot.xy, probeOfs.x) ); - retUV.y = dot( vec3(origUV, 1.0), vec3(probeRot.zw, probeOfs.y) ); - return retUV; -} - -// This is broken out into its own routine so that if we get some other -// format image than a lat-long, then we can account for that by changing -// the code here alone. -vec2 getProbeSampleUV( vec3 smpDir, vec4 probeRot, vec2 probeOfs ) -{ - vec2 smpUV; - -#if QT3DS_ENABLE_IBL_FOV - smpUV.x = (2.0 * atan(-smpDir.z, smpDir.x) + 3.14159265358 ) / light_probe_opts.x; - smpUV.y = (2.0 * atan(-smpDir.z, smpDir.y) + 3.14159265358 ) / light_probe_opts.x; -#else - smpUV.x = atan( smpDir.x, -smpDir.z) / 3.14159265359; - smpUV.y = 1.0 - (acos(smpDir.y) / 1.57079632679); -#endif - smpUV = transformSample( smpUV.xy * 0.5, probeRot, probeOfs ) + vec2(0.5, 0.5); - - return smpUV; -} - -vec4 getTopLayerSample( vec3 inDir, float lodShift, vec3 lodOffsets ) -{ -#if QT3DS_ENABLE_LIGHT_PROBE_2 - if ( light_probe2_props.w < 0.5 ) - return vec4(0.0, 0.0, 0.0, 0.0); - - vec2 smpUV = getProbeSampleUV( inDir, vec4(1.0, 0.0, 0.0, 1.0), light_probe_props.xy ); - smpUV.x -= 0.5; - smpUV.x *= light_probe2_props.x; - smpUV.x += light_probe2_props.y; - - vec4 retVal = 0.4 * textureLod( light_probe2, smpUV , lodShift ); - retVal += 0.2 * textureLod( light_probe2, smpUV , lodShift+lodOffsets.x ); - retVal += 0.3 * textureLod( light_probe2, smpUV , lodShift+lodOffsets.y ); - retVal += 0.1 * textureLod( light_probe2, smpUV , lodShift+lodOffsets.z ); - return retVal; -#else - return vec4(0.0, 0.0, 0.0, 0.0); -#endif -} - -vec3 getProbeSample( vec3 smpDir, float lodShift, vec3 normal ) -{ - vec2 smpUV = getProbeSampleUV( smpDir, light_probe_rotation, light_probe_offset.xy ); - return textureLod( light_probe, smpUV , lodShift ).xyz; -} - -vec3 getProbeWeightedSample( vec3 smpDir, float lodShift, float roughness, vec3 normal ) -{ - // This gives us a weighted sum that approximates the total filter support - // of the full-blown convolution. - vec2 smpUV = getProbeSampleUV( smpDir, light_probe_rotation, light_probe_offset.xy ); - float wt = 1.0; - -#if QT3DS_ENABLE_IBL_FOV - wt = min(wt, smoothstep(roughness * -0.25, roughness * 0.25, smpUV.x)); - wt = min(wt, smoothstep(roughness * -0.25, roughness * 0.25, smpUV.y)); - wt = min(wt, 1.0 - smoothstep(1.0 - roughness*0.25, 1.0 + roughness*0.25, smpUV.x)); - wt = min(wt, 1.0 - smoothstep(1.0 - roughness*0.25, 1.0 + roughness*0.25, smpUV.y)); -#endif - - vec3 lodOffsets; - lodOffsets.x = mix(-2.0, -0.70710678, roughness); - lodOffsets.y = min( 2.0 * smoothstep(0.0, 0.1, roughness), 2.0 - 1.29289 * smoothstep(0.1, 1.0, roughness) ); - lodOffsets.z = min( 6.0 * smoothstep(0.0, 0.1, roughness), 6.0 - 4.585786 * smoothstep(0.1, 1.0, roughness) ); - - ivec2 iSize = ivec2(light_probe_size); - vec3 ddx = dFdx( smpDir ) * float(iSize.x); - vec3 ddy = dFdy( smpDir ) * float(iSize.y); -// vec2 ddxUV = dFdx( smpUV ) * float(iSize.x); -// vec2 ddyUV = dFdy( smpUV ) * float(iSize.y); - - vec2 deriv; - deriv.x = max( dot(ddx, ddx), dot(ddy, ddy) ); -// deriv.y = max( dot(ddxUV, ddxUV), dot(ddyUV, ddyUV) ); - deriv = clamp( deriv, vec2(1.0), vec2(iSize.x * iSize.y) ); - vec2 lodBound = 0.5 * log2( deriv ) - vec2(1.0); - -// float minLod = 0.5 * (lodBound.x + lodBound.y); - float minLod = lodBound.x; - float maxLod = log2( max(float(iSize.x), float(iSize.y)) ); - minLod = clamp( minLod / maxLod, 0.0, 1.0 ); - minLod *= minLod * maxLod; - - lodShift = max( lodShift, minLod ); - - vec3 retVal = 0.4 * textureLod( light_probe, smpUV , lodShift ).xyz; - retVal += 0.2 * textureLod( light_probe, smpUV , max(minLod, lodShift+lodOffsets.x) ).xyz; - retVal += 0.3 * textureLod( light_probe, smpUV , lodShift+lodOffsets.y ).xyz; - retVal += 0.1 * textureLod( light_probe, smpUV , lodShift+lodOffsets.z ).xyz; - -#if QT3DS_ENABLE_LIGHT_PROBE_2 - vec4 topSmp = getTopLayerSample( smpDir, lodShift, lodOffsets ); - vec3 tempVal = mix( retVal, topSmp.xyz, topSmp.w ); - retVal = mix( retVal, tempVal, light_probe2_props.z ); -#endif - - if (light_probe_props.z > -1.0) { - float ctr = 0.5 + 0.5 * light_probe_props.z; - float vertWt = smoothstep(ctr-roughness*0.25, ctr+roughness*0.25, smpUV.y); - float wtScaled = mix(1.0, vertWt, light_probe_props.z + 1.0); - retVal *= wtScaled; - } - - return retVal * wt; -} - -vec2 textureSizeLod( vec2 size, int level ) -{ - return size / pow(2.0, float(level)); -} - -vec3 getProbeAnisoSample( vec3 smpDir, float roughU, float roughV, mat3 tanFrame ) -{ - float minRough = min(roughU, roughV); - float maxRough = max(roughU, roughV); - - float lodMin = log2( (minRough*3.0 + maxRough)*0.25 ) + (light_probe_offset.w - 2.0); - - float ratio = clamp( maxRough / minRough, 1.01, 27.0); - vec2 texSize = textureSizeLod( light_probe_size, int(floor( lodMin )) ); - texSize = mix( texSize, texSize * 0.5, fract(lodMin) ); - - // Boundary of 1.0..9.0 is just to keep the number of samples to within a - // reasonable number of samples in the filter. Similarly, with the clamping - // of the ratio to a max of 27.0 is just to prevent the step size in the filter - // to be no bigger than 3 texels (beyond which, there are some artifacts at high - // roughness, aka low texture res). - float stepFig = clamp(floor( ratio ), 1.0, 9.0); - - // numSteps is half the number of samples we need to take, which makes it - // the number of steps to take on each side. - int numSteps = int( floor(stepFig * 0.5) ); - - vec2 smpUV = getProbeSampleUV( smpDir, light_probe_rotation, light_probe_offset.xy ); - vec4 result = vec4(0.0); - - vec3 smpDirOfs = (maxRough == roughU) ? 0.01 * tanFrame[0] : 0.01 * tanFrame[1]; - vec2 stepPos = getProbeSampleUV(normalize(smpDir + smpDirOfs), light_probe_rotation, light_probe_offset.xy); - vec2 stepNeg = getProbeSampleUV(normalize(smpDir - smpDirOfs), light_probe_rotation, light_probe_offset.xy); - stepPos -= smpUV; stepNeg -= smpUV; - stepPos *= texSize; stepNeg *= texSize; - - // This ensures that we step along a size that makes sense even if one of the two - // sammpling directions wraps around the edges of the IBL texture. - smpDirOfs /= min( length(stepPos), length(stepNeg) ); - smpDirOfs *= ratio / stepFig; - - float sigma = mix(0.0, 2.0, ratio / 27.0); - sigma *= sigma; - - float wt = (1.0 / (ratio - 1.0)) + 1.0; - result.xyz += wt * getProbeWeightedSample( smpDir, lodMin, minRough, tanFrame[2] ); - result.w += wt; - for (int i = 0; i < numSteps; ++i) - { - wt = sigma / (sigma + float(i * i)); - vec2 uv0 = getProbeSampleUV(normalize(smpDir + smpDirOfs * float(i)), light_probe_rotation, light_probe_offset.xy); - vec2 uv1 = getProbeSampleUV(normalize(smpDir - smpDirOfs * float(i)), light_probe_rotation, light_probe_offset.xy); - result.xyz += wt * textureLod( light_probe, uv0 , lodMin ).xyz; - result.w += wt; - result.xyz += wt * textureLod( light_probe, uv1 , lodMin ).xyz; - result.w += wt; - } - - result /= result.w; - return result.xyz; -} - -vec4 sampleDiffuse( mat3 tanFrame ) -{ - if ( light_probe_props.w < 0.005 ) - return vec4( 0.0 ); - -// if ( light_probe_offset.w > 0.5 ) -// { - // The LOD offset comes from the assumption that a full diffuse convolution - // has a support of pi/2, which translates into x pixels, and the base 2 log - // gives us this LOD... Technically, "x" pixels depends on what the original - // texture resolution was, which is why we use light_probe_offset.w, which holds - // the number of mip levels the texture has. - - return vec4( light_probe_props.w * getProbeWeightedSample( tanFrame[2], light_probe_offset.w - 2.65149613, 1.0, tanFrame[2] ), 1.0 ); -// } - - /* - // PKC -- the code below is for full-blown IBL, which we'll skip for now - - // Hand-calculated Hammersley points for t = 2, n = 33 - // I exclude the 0,0 first point, hence why n=33 and not 32 - // Nice thing about 2d Hammersley points is that any subset is - // also stratified, so even if I have 1000 points and truncate - // anywhere, I'm fine. Each of these represent the y of an xy - // while x for the kth point is always (k+1)/n. - float kernel[32]; - kernel[0] = 0.5; kernel[1] = 0.25; - kernel[2] = 0.75; kernel[3] = 0.125; - kernel[4] = 0.625; kernel[5] = 0.375; - kernel[6] = 0.875; kernel[7] = 0.0625; - kernel[8] = 0.5625; kernel[9] = 0.3125; - kernel[10] = 0.8125; kernel[11] = 0.1875; - kernel[12] = 0.6875; kernel[13] = 0.4375; - kernel[14] = 0.9375; kernel[15] = 0.03125; - kernel[16] = 0.53125; kernel[17] = 0.28125; - kernel[18] = 0.78125; kernel[19] = 0.15625; - kernel[20] = 0.65625; kernel[21] = 0.40625; - kernel[22] = 0.90625; kernel[23] = 0.09375; - kernel[24] = 0.59375; kernel[25] = 0.34375; - kernel[26] = 0.84375; kernel[27] = 0.28175; - kernel[28] = 0.71875; kernel[29] = 0.46875; - kernel[30] = 0.96875; kernel[31] = 0.015625; - - float phiShift = noise1d(gl_FragCoord.xy) - 0.5; - - vec3 ret = vec3(0, 0, 0); - - int ct = 24; - float step = 25.0; - - // Importance sampling a cosine-weighted distribution. Since this - // matches the BSDF exactly, we are just going to assume that the PDF - // and the BSDF cancel out in sampling, so we just need to accumulate - // texture colors. The noise function puts randomized "twist" into - // the sampled directions. - for( int i = 0; i < ct; ++i ) - { - vec3 localDir; - float phi = 6.28318530718 * (kernel[i] + phiShift); - float cosTheta = sqrt( float(i+1) / step); - localDir.z = sqrt(1.0 - cosTheta*cosTheta); - localDir.x = cos(phi) * cosTheta; - localDir.y = sin(phi) * cosTheta; - vec3 smpDir = tanFrame[0]*localDir.x + tanFrame[1]*localDir.y + tanFrame[2]*localDir.z; - - - float lodShift = light_probe_offset.w - 2 + log2( 3.1415926535 / (localDir.z * step) ); - vec3 smpColor = getProbeSample( smpDir, lodShift, tanFrame[2] ); - - // The assumption here is that the BSDF and the sampling PDF are identical - // so they cancel out and therefore, we don't need to include it here. - ret += smpColor; - } - - ret *= aoFactor / 24.0; - return ret; - */ -} - -vec4 sampleDiffuseCustomMaterial( vec3 normal, vec3 worldPos, float aoFactor ) -{ - - mat3 tanFrame = tangentFrame( normal, worldPos ); - return sampleDiffuse( tanFrame ); -} - -vec4 sampleGlossyAniso( mat3 tanFrame, vec3 viewDir, float roughU, float roughV ) -{ - if ( light_probe_props.w < 0.005 ) - return vec4( 0.0 ); - - // PKC : If we do the full IBL sampling, it's useful to square the roughnesses because - // it makes the effect of roughness feel more linear in the low end. This isn't necessary - // for fast IBL. -// float sigmaU = clamp(roughU*roughU, 0.0001, 1.0); -// float sigmaV = clamp(roughV*roughV, 0.0001, 1.0); - float sigmaU = smoothstep( 0.0, 1.0, clamp(roughU, 0.0001, 1.0) ); - float sigmaV = smoothstep( 0.0, 1.0, clamp(roughV, 0.0001, 1.0) ); - vec3 ret = vec3(0, 0, 0); - -// if ( light_probe_offset.w > 0.5 ) -// { - vec3 smpDir = reflect( -viewDir, tanFrame[2] ); - float sigma = sqrt(sigmaU * sigmaV); - - // Compute the Geometric occlusion/self-shadowing term - float NdotL = clamp( dot( smpDir, tanFrame[2] ), 0.0, 0.999995); - float k = sigma * 0.31830988618; // roughness / pi - float Gl = clamp( (NdotL / (NdotL*(1.0-k) + k) + (1.0 - k*k)) * 0.5, 0.0, 1.0 ); - - vec3 outColor; - - outColor = getProbeAnisoSample( smpDir, sigmaU, sigmaV, tanFrame ); - - return vec4( light_probe_props.w * Gl * outColor, 1.0 ); -// } - - // PKC -- the code below is for full-blown IBL, which we'll skip for now - -/* - float step = clamp( ceil(32.0 * sqrt(max(sigmaU, sigmaV))), 4.0, 32.0 ); - int actualCt = int(step); - float phiShift = noise1d(gl_FragCoord.xy) - 0.5; - - // Hand-calculated Hammersley points for t = 2, n = 33 - // I exclude the 0,0 first point, hence why n=33 and not 32 - // Nice thing about 2d Hammersley points is that any subset is - // also stratified, so even if I have 1000 points and truncate - // anywhere, I'm fine. Each of these represent the y of an xy - // while x for the kth point is always (k+1)/n. - float kernel[32]; - kernel[0] = 0.5; kernel[1] = 0.25; - kernel[2] = 0.75; kernel[3] = 0.125; - kernel[4] = 0.625; kernel[5] = 0.375; - kernel[6] = 0.875; kernel[7] = 0.0625; - kernel[8] = 0.5625; kernel[9] = 0.3125; - kernel[10] = 0.8125; kernel[11] = 0.1875; - kernel[12] = 0.6875; kernel[13] = 0.4375; - kernel[14] = 0.9375; kernel[15] = 0.03125; - kernel[16] = 0.53125; kernel[17] = 0.28125; - kernel[18] = 0.78125; kernel[19] = 0.15625; - kernel[20] = 0.65625; kernel[21] = 0.40625; - kernel[22] = 0.90625; kernel[23] = 0.09375; - kernel[24] = 0.59375; kernel[25] = 0.34375; - kernel[26] = 0.84375; kernel[27] = 0.28175; - kernel[28] = 0.71875; kernel[29] = 0.46875; - kernel[30] = 0.96875; kernel[31] = 0.015625; - - float thetaI = acos( dot(viewDir, tanFrame[2]) ); - - // NOTE : The model I'm using here is actually based on the KGGX model used in - // physGlossyBSDF. This is my own variation on the original GGX which uses something - // closer to a pure Cauchy distribution in tangent space, but also supports anisotropy. - for (int i = 0; i < actualCt; ++i) - { - vec3 localDir; - - float phi = 6.28318530718 * (kernel[i] + phiShift); - float u = float(i + 1) / (step + 1.0); - float rU = cos(phi) * sigmaU; - float rV = sin(phi) * sigmaV; - float sigma = sqrt(rU * rU + rV * rV); - - float boundA = atan( ((thetaI - 1.57079632679) * 0.5) / sigma ); - float boundB = atan( ((thetaI + 1.57079632679) * 0.5) / sigma ); - float t = (1.0 - u) * boundA + u * boundB; - float thetaH = tan( t ) * sigma; - - float cosThetaH = cos( thetaH ); - float sinThetaH = sin( thetaH ); - localDir.z = cosThetaH; - localDir.y = sin(phi) * sinThetaH; - localDir.x = cos(phi) * sinThetaH; - - vec3 halfDir = tanFrame[0]*localDir.x + tanFrame[1]*localDir.y + tanFrame[2]*localDir.z; - halfDir = normalize(halfDir); - vec3 smpDir = reflect( -viewDir, halfDir ); - - vec2 scaledXY = localDir.xy / vec2(sigmaU, sigmaV); - float PDF = (sigmaU*sigmaV) / (sigmaU*sigmaV + dot(scaledXY, scaledXY)); - vec3 Haf = smpDir + viewDir; // We need the unnormalized half vecter as well as the normalized one - float HdotL = dot(halfDir, smpDir); - // normalize the PDF to compute the filter support - // This gives us the ideal miplevel at which to sample the texture map. - PDF *= dot(Haf, Haf) / (4.0 * dot(Haf, smpDir) * HdotL * sigmaU*sigmaV * (boundB-boundA)*(boundB-boundA)); - - // Again assuming that the pdf and BSDF are equivalent -- that's not generally valid, - // but it saves a lot of ALU cycles. - float lodShift = log2( 512.0 * sigma / PDF ); - - float k = sigma * 0.31830988618; // roughness / pi - float Gl = clamp( (HdotL / (HdotL*(1.0-k) + k) + (1.0 - k*k)) * 0.5, 0.0, 1.0 ); - - vec3 smpColor = Gl * getProbeSample( smpDir, lodShift, tanFrame[2] ); - ret += smpColor; - } - ret /= float(actualCt); - return vec4(ret, 1.0); -*/ -} - -vec4 sampleGlossy( mat3 tanFrame, vec3 viewDir, float roughness ) -{ - return sampleGlossyAniso( tanFrame, viewDir, roughness, roughness ); -} - -vec4 sampleGlossyCustomMaterial( vec3 normal, vec3 worldPos, vec3 viewDir, float roughness ) -{ - mat3 tanFrame = tangentFrame( normal, worldPos ); - return sampleGlossy( tanFrame, viewDir, roughness ); -} - -#endif diff --git a/res/effectlib/gles2/sampleProbePre.glsllib b/res/effectlib/gles2/sampleProbePre.glsllib new file mode 100644 index 0000000..6127566 --- /dev/null +++ b/res/effectlib/gles2/sampleProbePre.glsllib @@ -0,0 +1,7 @@ + +uniform vec4 light_probe_size; + +ivec2 lightProbeSize(sampler2D lightProbe, int lodLevel) +{ + return ivec2(light_probe_size / pow(2.0, float(lodLevel))); +} diff --git a/res/effectlib/luminance.glsllib b/res/effectlib/luminance.glsllib index 067dc18..e4ce386 100644 --- a/res/effectlib/luminance.glsllib +++ b/res/effectlib/luminance.glsllib @@ -32,31 +32,11 @@ #define LUMINANCE_GLSLLIB // Luma coefficients according to ITU-R Recommendation BT.709 (http://en.wikipedia.org/wiki/Rec._709) -const vec3 yCoeff_709 = vec3( 0.2126, 0.7152, 0.0722 ); +const vec3 yCoeff_709 = vec3(0.2126, 0.7152, 0.0722); -float luminance( in vec3 v ) +float luminance(in vec3 v) { - return dot( v, yCoeff_709 ); + return dot(v, yCoeff_709); } -vec3 RGBToYPbPr( in vec3 v ) -{ - vec3 ypp; - ypp.x = luminance( v ); - ypp.y = 0.5 * (v.b - ypp.x) / (1.0 - yCoeff_709.b); - ypp.z = 0.5 * (v.r - ypp.x) / (1.0 - yCoeff_709.r); - - return ypp; -} - -vec3 YPbPrToRGB( in vec3 v ) -{ - vec3 outRGB; - outRGB.x = dot(vec3(1.0, 0.0, 1.575), v); - outRGB.y = dot(vec3(1.0, -0.187, -0.468), v); - outRGB.z = dot(vec3(1.0, 1.856, 0.0), v); - - return outRGB; -} - -#endif
\ No newline at end of file +#endif diff --git a/res/effectlib/sampleProbe.glsllib b/res/effectlib/sampleProbe.glsllib index 6556e51..4846ee3 100644 --- a/res/effectlib/sampleProbe.glsllib +++ b/res/effectlib/sampleProbe.glsllib @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2014 NVIDIA Corporation. -** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt 3D Studio. @@ -31,6 +31,10 @@ #ifndef SAMPLE_PROBE_GLSLLIB #define SAMPLE_PROBE_GLSLLIB 1 +#include "sampleProbePre.glsllib" + +#define USE_RGBE + uniform sampler2D light_probe; uniform vec4 light_probe_props; uniform vec4 light_probe_rotation; @@ -47,52 +51,54 @@ uniform vec4 light_probe_opts; float noise1d(vec2 n) { - return 0.5 + 0.5 * fract(sin(dot(n.xy, vec2(12.9898, 78.233)))* 43758.5453); + return 0.5 + 0.5 * fract(sin(dot(n.xy, vec2(12.9898, 78.233))) * 43758.5453); } -mat3 orthoNormalize( in mat3 tanFrame ) +mat3 orthoNormalize(in mat3 tanFrame) { mat3 outMat; - outMat[0] = normalize( cross( tanFrame[1], tanFrame[2] ) ); - outMat[1] = normalize( cross( tanFrame[2], outMat[0] ) ); + outMat[0] = normalize(cross(tanFrame[1], tanFrame[2])); + outMat[1] = normalize(cross(tanFrame[2], outMat[0])); outMat[2] = tanFrame[2]; return outMat; } -mat3 tangentFrame( vec3 N, vec3 p ) +mat3 tangentFrame(vec3 N, vec3 p) { // get edge vectors of the pixel triangle - vec3 dp1 = dFdx( p ); - vec3 dp2 = dFdy( p ); - // Using dPdu and dPdv would be nicer, but the nature of our materials - // are not ones with intrinsic UVs, so we can't really go there. -// vec2 duv1 = dFdx( uv ); -// vec2 duv2 = dFdy( uv ); - + vec3 dp1 = dFdx(p); + vec3 dp2 = dFdy(p); // solve the linear system - vec3 dp2perp = cross( dp2, N ); - vec3 dp1perp = cross( N, dp1 ); -// vec3 T = dp2perp * duv1.x + dp1perp * duv2.x; -// vec3 B = dp2perp * duv1.y + dp1perp * duv2.y; - + vec3 dp2perp = cross(dp2, N); + vec3 dp1perp = cross(N, dp1); vec3 T = normalize(dp1perp); vec3 B = normalize(dp2perp); - return mat3( T , B , N ); + return mat3(T, B, N); } -vec2 transformSample( vec2 origUV, vec4 probeRot, vec2 probeOfs ) +vec2 transformSample(vec2 origUV, vec4 probeRot, vec2 probeOfs) { vec2 retUV; - retUV.x = dot( vec3(origUV, 1.0), vec3(probeRot.xy, probeOfs.x) ); - retUV.y = dot( vec3(origUV, 1.0), vec3(probeRot.zw, probeOfs.y) ); + retUV.x = dot(vec3(origUV, 1.0), vec3(probeRot.xy, probeOfs.x)); + retUV.y = dot(vec3(origUV, 1.0), vec3(probeRot.zw, probeOfs.y)); return retUV; } +vec3 textureProbe(sampler2D lightProbe, vec2 coord, float lod) +{ +#ifdef USE_RGBE + vec4 ret = textureLod(lightProbe, coord, lod); + return ret.rgb * pow(2.0, ret.a * 255.0 - 128.0); +#else + return textureLod(lightProbe, coord, lod).rgb; +#endif +} + // This is broken out into its own routine so that if we get some other // format image than a lat-long, then we can account for that by changing // the code here alone. -vec2 getProbeSampleUV( vec3 smpDir, vec4 probeRot, vec2 probeOfs ) +vec2 getProbeSampleUV(vec3 smpDir, vec4 probeRot, vec2 probeOfs) { vec2 smpUV; @@ -114,86 +120,83 @@ vec2 getProbeSampleUV( vec3 smpDir, vec4 probeRot, vec2 probeOfs ) return smpUV; } -vec4 getTopLayerSample( vec3 inDir, float lodShift, vec3 lodOffsets ) +vec4 getTopLayerSample(vec3 inDir, float lodShift, vec3 lodOffsets) { #if QT3DS_ENABLE_LIGHT_PROBE_2 - if ( light_probe2_props.w < 0.5 ) + if (light_probe2_props.w < 0.5) return vec4(0.0, 0.0, 0.0, 0.0); - vec2 smpUV = getProbeSampleUV( inDir, vec4(1.0, 0.0, 0.0, 1.0), light_probe_props.xy ); + vec2 smpUV = getProbeSampleUV(inDir, vec4(1.0, 0.0, 0.0, 1.0), light_probe_props.xy); smpUV.x -= 0.5; smpUV.x *= light_probe2_props.x; smpUV.x += light_probe2_props.y; - vec4 retVal = 0.4 * textureLod( light_probe2, smpUV , lodShift ); - retVal += 0.2 * textureLod( light_probe2, smpUV , lodShift+lodOffsets.x ); - retVal += 0.3 * textureLod( light_probe2, smpUV , lodShift+lodOffsets.y ); - retVal += 0.1 * textureLod( light_probe2, smpUV , lodShift+lodOffsets.z ); + vec4 retVal = 0.4 * textureLod(light_probe2, smpUV , lodShift); + retVal += 0.2 * textureLod(light_probe2, smpUV, lodShift+lodOffsets.x); + retVal += 0.3 * textureLod(light_probe2, smpUV, lodShift+lodOffsets.y); + retVal += 0.1 * textureLod(light_probe2, smpUV, lodShift+lodOffsets.z); return retVal; #else return vec4(0.0, 0.0, 0.0, 0.0); #endif } -vec3 getProbeSample( vec3 smpDir, float lodShift, vec3 normal ) +vec3 getProbeSample(vec3 smpDir, float lodShift, vec3 normal) { - vec2 smpUV = getProbeSampleUV( smpDir, light_probe_rotation, light_probe_offset.xy ); - return textureLod( light_probe, smpUV , lodShift ).xyz; + vec2 smpUV = getProbeSampleUV(smpDir, light_probe_rotation, light_probe_offset.xy); + return textureProbe(light_probe, smpUV , lodShift); } -vec3 getProbeWeightedSample( vec3 smpDir, float lodShift, float roughness, vec3 normal ) +vec3 getProbeWeightedSample(vec3 smpDir, float lodShift, float roughness, vec3 normal) { // This gives us a weighted sum that approximates the total filter support // of the full-blown convolution. - vec2 smpUV = getProbeSampleUV( smpDir, light_probe_rotation, light_probe_offset.xy ); + vec2 smpUV = getProbeSampleUV(smpDir, light_probe_rotation, light_probe_offset.xy); float wt = 1.0; #if QT3DS_ENABLE_IBL_FOV wt = min(wt, smoothstep(roughness * -0.25, roughness * 0.25, smpUV.x)); wt = min(wt, smoothstep(roughness * -0.25, roughness * 0.25, smpUV.y)); - wt = min(wt, 1.0 - smoothstep(1.0 - roughness*0.25, 1.0 + roughness*0.25, smpUV.x)); - wt = min(wt, 1.0 - smoothstep(1.0 - roughness*0.25, 1.0 + roughness*0.25, smpUV.y)); + wt = min(wt, 1.0 - smoothstep(1.0 - roughness * 0.25, 1.0 + roughness * 0.25, smpUV.x)); + wt = min(wt, 1.0 - smoothstep(1.0 - roughness * 0.25, 1.0 + roughness * 0.25, smpUV.y)); #endif vec3 lodOffsets; lodOffsets.x = mix(-2.0, -0.70710678, roughness); - lodOffsets.y = min( 2.0 * smoothstep(0.0, 0.1, roughness), 2.0 - 1.29289 * smoothstep(0.1, 1.0, roughness) ); - lodOffsets.z = min( 6.0 * smoothstep(0.0, 0.1, roughness), 6.0 - 4.585786 * smoothstep(0.1, 1.0, roughness) ); + lodOffsets.y = min(2.0 * smoothstep(0.0, 0.1, roughness), 2.0 - 1.29289 * smoothstep(0.1, 1.0, roughness)); + lodOffsets.z = min(6.0 * smoothstep(0.0, 0.1, roughness), 6.0 - 4.585786 * smoothstep(0.1, 1.0, roughness)); - ivec2 iSize = textureSize(light_probe, 0); - vec3 ddx = dFdx( smpDir ) * float(iSize.x); - vec3 ddy = dFdy( smpDir ) * float(iSize.y); -// vec2 ddxUV = dFdx( smpUV ) * float(iSize.x); -// vec2 ddyUV = dFdy( smpUV ) * float(iSize.y); + ivec2 iSize = lightProbeSize(light_probe, 0); + vec3 ddx = dFdx(smpDir) * float(iSize.x); + vec3 ddy = dFdy(smpDir) * float(iSize.y); vec2 deriv; - deriv.x = max( dot(ddx, ddx), dot(ddy, ddy) ); -// deriv.y = max( dot(ddxUV, ddxUV), dot(ddyUV, ddyUV) ); - deriv = clamp( deriv, vec2(1.0), vec2(iSize.x * iSize.y) ); - vec2 lodBound = 0.5 * log2( deriv ) - vec2(1.0); + deriv.x = max(dot(ddx, ddx), dot(ddy, ddy)); + + deriv = clamp(deriv, vec2(1.0), vec2(iSize.x * iSize.y)); + vec2 lodBound = 0.5 * log2(deriv) - vec2(1.0); -// float minLod = 0.5 * (lodBound.x + lodBound.y); float minLod = lodBound.x; - float maxLod = log2( max(float(iSize.x), float(iSize.y)) ); - minLod = clamp( minLod / maxLod, 0.0, 1.0 ); + float maxLod = log2(max(float(iSize.x), float(iSize.y))); + minLod = clamp(minLod / maxLod, 0.0, 1.0); minLod *= minLod * maxLod; - lodShift = max( lodShift, minLod ); + lodShift = max(lodShift, minLod); - vec3 retVal = 0.4 * textureLod( light_probe, smpUV , lodShift ).xyz; - retVal += 0.2 * textureLod( light_probe, smpUV , max(minLod, lodShift+lodOffsets.x) ).xyz; - retVal += 0.3 * textureLod( light_probe, smpUV , lodShift+lodOffsets.y ).xyz; - retVal += 0.1 * textureLod( light_probe, smpUV , lodShift+lodOffsets.z ).xyz; + vec3 retVal = 0.4 * textureProbe(light_probe, smpUV , lodShift); + retVal += 0.2 * textureProbe(light_probe, smpUV , max(minLod, lodShift+lodOffsets.x)); + retVal += 0.3 * textureProbe(light_probe, smpUV , lodShift+lodOffsets.y); + retVal += 0.1 * textureProbe(light_probe, smpUV , lodShift+lodOffsets.z); #if QT3DS_ENABLE_LIGHT_PROBE_2 - vec4 topSmp = getTopLayerSample( smpDir, lodShift, lodOffsets ); - vec3 tempVal = mix( retVal, topSmp.xyz, topSmp.w ); - retVal = mix( retVal, tempVal, light_probe2_props.z ); + vec4 topSmp = getTopLayerSample(smpDir, lodShift, lodOffsets); + vec3 tempVal = mix(retVal, topSmp.xyz, topSmp.w); + retVal = mix(retVal, tempVal, light_probe2_props.z); #endif if (light_probe_props.z > -1.0) { float ctr = 0.5 + 0.5 * light_probe_props.z; - float vertWt = smoothstep(ctr-roughness*0.25, ctr+roughness*0.25, smpUV.y); + float vertWt = smoothstep(ctr-roughness * 0.25, ctr+roughness * 0.25, smpUV.y); float wtScaled = mix(1.0, vertWt, light_probe_props.z + 1.0); retVal *= wtScaled; } @@ -201,273 +204,40 @@ vec3 getProbeWeightedSample( vec3 smpDir, float lodShift, float roughness, vec3 return retVal * wt; } -vec3 getProbeAnisoSample( vec3 smpDir, float roughU, float roughV, mat3 tanFrame ) +vec4 sampleDiffuse(mat3 tanFrame) { - float minRough = min(roughU, roughV); - float maxRough = max(roughU, roughV); - - float lodMin = log2( (minRough*3.0 + maxRough)*0.25 ) + (light_probe_offset.w - 2.0); - - float ratio = clamp( maxRough / minRough, 1.01, 27.0); - vec2 texSize = vec2( textureSize( light_probe, int(floor( lodMin )) ) ); - texSize = mix( texSize, texSize * 0.5, fract(lodMin) ); - - // Boundary of 1.0..9.0 is just to keep the number of samples to within a - // reasonable number of samples in the filter. Similarly, with the clamping - // of the ratio to a max of 27.0 is just to prevent the step size in the filter - // to be no bigger than 3 texels (beyond which, there are some artifacts at high - // roughness, aka low texture res). - float stepFig = clamp(floor( ratio ), 1.0, 9.0); - - // numSteps is half the number of samples we need to take, which makes it - // the number of steps to take on each side. - int numSteps = int( floor(stepFig * 0.5) ); - - vec2 smpUV = getProbeSampleUV( smpDir, light_probe_rotation, light_probe_offset.xy ); - vec4 result = vec4(0.0); - - vec3 smpDirOfs = (maxRough == roughU) ? 0.01 * tanFrame[0] : 0.01 * tanFrame[1]; - vec2 stepPos = getProbeSampleUV(normalize(smpDir + smpDirOfs), light_probe_rotation, light_probe_offset.xy); - vec2 stepNeg = getProbeSampleUV(normalize(smpDir - smpDirOfs), light_probe_rotation, light_probe_offset.xy); - stepPos -= smpUV; stepNeg -= smpUV; - stepPos *= texSize; stepNeg *= texSize; - - // This ensures that we step along a size that makes sense even if one of the two - // sammpling directions wraps around the edges of the IBL texture. - smpDirOfs /= min( length(stepPos), length(stepNeg) ); - smpDirOfs *= ratio / stepFig; - - float sigma = mix(0.0, 2.0, ratio / 27.0); - sigma *= sigma; - - float wt = (1.0 / (ratio - 1.0)) + 1.0; - result.xyz += wt * getProbeWeightedSample( smpDir, lodMin, minRough, tanFrame[2] ); - result.w += wt; - for (int i = 0; i < numSteps; ++i) - { - wt = sigma / (sigma + float(i * i)); - vec2 uv0 = getProbeSampleUV(normalize(smpDir + smpDirOfs * float(i)), light_probe_rotation, light_probe_offset.xy); - vec2 uv1 = getProbeSampleUV(normalize(smpDir - smpDirOfs * float(i)), light_probe_rotation, light_probe_offset.xy); - result.xyz += wt * textureLod( light_probe, uv0 , lodMin ).xyz; - result.w += wt; - result.xyz += wt * textureLod( light_probe, uv1 , lodMin ).xyz; - result.w += wt; - } + if (light_probe_props.w < 0.005) + return vec4(0.0); - result /= result.w; - return result.xyz; + return vec4(light_probe_props.w * getProbeWeightedSample(tanFrame[2], light_probe_offset.w - 2.65149613, 1.0, tanFrame[2]), 1.0 ); } -vec4 sampleDiffuse( mat3 tanFrame ) +vec4 sampleDiffuseCustomMaterial(vec3 normal, vec3 worldPos, float aoFactor) { - if ( light_probe_props.w < 0.005 ) - return vec4( 0.0 ); - -// if ( light_probe_offset.w > 0.5 ) -// { - // The LOD offset comes from the assumption that a full diffuse convolution - // has a support of pi/2, which translates into x pixels, and the base 2 log - // gives us this LOD... Technically, "x" pixels depends on what the original - // texture resolution was, which is why we use light_probe_offset.w, which holds - // the number of mip levels the texture has. - - return vec4( light_probe_props.w * getProbeWeightedSample( tanFrame[2], light_probe_offset.w - 2.65149613, 1.0, tanFrame[2] ), 1.0 ); -// } - - /* - // PKC -- the code below is for full-blown IBL, which we'll skip for now - - // Hand-calculated Hammersley points for t = 2, n = 33 - // I exclude the 0,0 first point, hence why n=33 and not 32 - // Nice thing about 2d Hammersley points is that any subset is - // also stratified, so even if I have 1000 points and truncate - // anywhere, I'm fine. Each of these represent the y of an xy - // while x for the kth point is always (k+1)/n. - float kernel[32]; - kernel[0] = 0.5; kernel[1] = 0.25; - kernel[2] = 0.75; kernel[3] = 0.125; - kernel[4] = 0.625; kernel[5] = 0.375; - kernel[6] = 0.875; kernel[7] = 0.0625; - kernel[8] = 0.5625; kernel[9] = 0.3125; - kernel[10] = 0.8125; kernel[11] = 0.1875; - kernel[12] = 0.6875; kernel[13] = 0.4375; - kernel[14] = 0.9375; kernel[15] = 0.03125; - kernel[16] = 0.53125; kernel[17] = 0.28125; - kernel[18] = 0.78125; kernel[19] = 0.15625; - kernel[20] = 0.65625; kernel[21] = 0.40625; - kernel[22] = 0.90625; kernel[23] = 0.09375; - kernel[24] = 0.59375; kernel[25] = 0.34375; - kernel[26] = 0.84375; kernel[27] = 0.28175; - kernel[28] = 0.71875; kernel[29] = 0.46875; - kernel[30] = 0.96875; kernel[31] = 0.015625; - - float phiShift = noise1d(gl_FragCoord.xy) - 0.5; - - vec3 ret = vec3(0, 0, 0); - - int ct = 24; - float step = 25.0; - - // Importance sampling a cosine-weighted distribution. Since this - // matches the BSDF exactly, we are just going to assume that the PDF - // and the BSDF cancel out in sampling, so we just need to accumulate - // texture colors. The noise function puts randomized "twist" into - // the sampled directions. - for( int i = 0; i < ct; ++i ) - { - vec3 localDir; - float phi = 6.28318530718 * (kernel[i] + phiShift); - float cosTheta = sqrt( float(i+1) / step); - localDir.z = sqrt(1.0 - cosTheta*cosTheta); - localDir.x = cos(phi) * cosTheta; - localDir.y = sin(phi) * cosTheta; - vec3 smpDir = tanFrame[0]*localDir.x + tanFrame[1]*localDir.y + tanFrame[2]*localDir.z; - - - float lodShift = light_probe_offset.w - 2 + log2( 3.1415926535 / (localDir.z * step) ); - vec3 smpColor = getProbeSample( smpDir, lodShift, tanFrame[2] ); - - // The assumption here is that the BSDF and the sampling PDF are identical - // so they cancel out and therefore, we don't need to include it here. - ret += smpColor; - } - - ret *= aoFactor / 24.0; - return ret; - */ + mat3 tanFrame = tangentFrame(normal, worldPos); + return sampleDiffuse(tanFrame); } -vec4 sampleDiffuseCustomMaterial( vec3 normal, vec3 worldPos, float aoFactor ) +vec4 sampleGlossy(mat3 tanFrame, vec3 viewDir, float roughness) { + if (light_probe_props.w < 0.005) + return vec4(0.0); - mat3 tanFrame = tangentFrame( normal, worldPos ); - return sampleDiffuse( tanFrame ); -} - -vec4 sampleGlossyAniso( mat3 tanFrame, vec3 viewDir, float roughU, float roughV ) -{ - if ( light_probe_props.w < 0.005 ) - return vec4( 0.0 ); - - // PKC : If we do the full IBL sampling, it's useful to square the roughnesses because - // it makes the effect of roughness feel more linear in the low end. This isn't necessary - // for fast IBL. -// float sigmaU = clamp(roughU*roughU, 0.0001, 1.0); -// float sigmaV = clamp(roughV*roughV, 0.0001, 1.0); - float sigmaU = smoothstep( 0.0, 1.0, clamp(roughU, 0.0001, 1.0) ); - float sigmaV = smoothstep( 0.0, 1.0, clamp(roughV, 0.0001, 1.0) ); + float sigma = smoothstep(0.0, 1.0, clamp(roughness, 0.0001, 1.0)); vec3 ret = vec3(0, 0, 0); -// if ( light_probe_offset.w > 0.5 ) -// { - vec3 smpDir = reflect( -viewDir, tanFrame[2] ); - float sigma = sqrt(sigmaU * sigmaV); - - // Compute the Geometric occlusion/self-shadowing term - float NdotL = clamp( dot( smpDir, tanFrame[2] ), 0.0, 0.999995); - float k = sigma * 0.31830988618; // roughness / pi - float Gl = clamp( (NdotL / (NdotL*(1.0-k) + k) + (1.0 - k*k)) * 0.5, 0.0, 1.0 ); - - vec3 outColor; - - outColor = getProbeAnisoSample( smpDir, sigmaU, sigmaV, tanFrame ); - - return vec4( light_probe_props.w * Gl * outColor, 1.0 ); -// } - - // PKC -- the code below is for full-blown IBL, which we'll skip for now - -/* - float step = clamp( ceil(32.0 * sqrt(max(sigmaU, sigmaV))), 4.0, 32.0 ); - int actualCt = int(step); - float phiShift = noise1d(gl_FragCoord.xy) - 0.5; - - // Hand-calculated Hammersley points for t = 2, n = 33 - // I exclude the 0,0 first point, hence why n=33 and not 32 - // Nice thing about 2d Hammersley points is that any subset is - // also stratified, so even if I have 1000 points and truncate - // anywhere, I'm fine. Each of these represent the y of an xy - // while x for the kth point is always (k+1)/n. - float kernel[32]; - kernel[0] = 0.5; kernel[1] = 0.25; - kernel[2] = 0.75; kernel[3] = 0.125; - kernel[4] = 0.625; kernel[5] = 0.375; - kernel[6] = 0.875; kernel[7] = 0.0625; - kernel[8] = 0.5625; kernel[9] = 0.3125; - kernel[10] = 0.8125; kernel[11] = 0.1875; - kernel[12] = 0.6875; kernel[13] = 0.4375; - kernel[14] = 0.9375; kernel[15] = 0.03125; - kernel[16] = 0.53125; kernel[17] = 0.28125; - kernel[18] = 0.78125; kernel[19] = 0.15625; - kernel[20] = 0.65625; kernel[21] = 0.40625; - kernel[22] = 0.90625; kernel[23] = 0.09375; - kernel[24] = 0.59375; kernel[25] = 0.34375; - kernel[26] = 0.84375; kernel[27] = 0.28175; - kernel[28] = 0.71875; kernel[29] = 0.46875; - kernel[30] = 0.96875; kernel[31] = 0.015625; - - float thetaI = acos( dot(viewDir, tanFrame[2]) ); - - // NOTE : The model I'm using here is actually based on the KGGX model used in - // physGlossyBSDF. This is my own variation on the original GGX which uses something - // closer to a pure Cauchy distribution in tangent space, but also supports anisotropy. - for (int i = 0; i < actualCt; ++i) - { - vec3 localDir; - - float phi = 6.28318530718 * (kernel[i] + phiShift); - float u = float(i + 1) / (step + 1.0); - float rU = cos(phi) * sigmaU; - float rV = sin(phi) * sigmaV; - float sigma = sqrt(rU * rU + rV * rV); - - float boundA = atan( ((thetaI - 1.57079632679) * 0.5) / sigma ); - float boundB = atan( ((thetaI + 1.57079632679) * 0.5) / sigma ); - float t = (1.0 - u) * boundA + u * boundB; - float thetaH = tan( t ) * sigma; - - float cosThetaH = cos( thetaH ); - float sinThetaH = sin( thetaH ); - localDir.z = cosThetaH; - localDir.y = sin(phi) * sinThetaH; - localDir.x = cos(phi) * sinThetaH; - - vec3 halfDir = tanFrame[0]*localDir.x + tanFrame[1]*localDir.y + tanFrame[2]*localDir.z; - halfDir = normalize(halfDir); - vec3 smpDir = reflect( -viewDir, halfDir ); - - vec2 scaledXY = localDir.xy / vec2(sigmaU, sigmaV); - float PDF = (sigmaU*sigmaV) / (sigmaU*sigmaV + dot(scaledXY, scaledXY)); - vec3 Haf = smpDir + viewDir; // We need the unnormalized half vecter as well as the normalized one - float HdotL = dot(halfDir, smpDir); - // normalize the PDF to compute the filter support - // This gives us the ideal miplevel at which to sample the texture map. - PDF *= dot(Haf, Haf) / (4.0 * dot(Haf, smpDir) * HdotL * sigmaU*sigmaV * (boundB-boundA)*(boundB-boundA)); - - // Again assuming that the pdf and BSDF are equivalent -- that's not generally valid, - // but it saves a lot of ALU cycles. - float lodShift = log2( 512.0 * sigma / PDF ); - - float k = sigma * 0.31830988618; // roughness / pi - float Gl = clamp( (HdotL / (HdotL*(1.0-k) + k) + (1.0 - k*k)) * 0.5, 0.0, 1.0 ); - - vec3 smpColor = Gl * getProbeSample( smpDir, lodShift, tanFrame[2] ); - ret += smpColor; - } - ret /= float(actualCt); - return vec4(ret, 1.0); -*/ -} + vec3 smpDir = reflect(-viewDir, tanFrame[2]); -vec4 sampleGlossy( mat3 tanFrame, vec3 viewDir, float roughness ) -{ - return sampleGlossyAniso( tanFrame, viewDir, roughness, roughness ); -} + // Compute the Geometric occlusion/self-shadowing term + float NdotL = clamp(dot(smpDir, tanFrame[2]), 0.0, 0.999995); + float k = sigma * 0.31830988618; // roughness / pi + float Gl = clamp((NdotL / (NdotL*(1.0-k) + k) + (1.0 - k*k)) * 0.5, 0.0, 1.0 ); -vec4 sampleGlossyCustomMaterial( vec3 normal, vec3 worldPos, vec3 viewDir, float roughness ) -{ - mat3 tanFrame = tangentFrame( normal, worldPos ); - return sampleGlossy( tanFrame, viewDir, roughness ); + vec3 outColor; + + outColor = getProbeSample(smpDir, sigma, tanFrame[2]); + + return vec4(light_probe_props.w * Gl * outColor, 1.0); } #endif diff --git a/res/effectlib/sampleProbePre.glsllib b/res/effectlib/sampleProbePre.glsllib new file mode 100644 index 0000000..5fd42c9 --- /dev/null +++ b/res/effectlib/sampleProbePre.glsllib @@ -0,0 +1,5 @@ + +ivec2 lightProbeSize(sampler2D lightProbe, int lodLevel) +{ + return ivec2(textureSize(lightProbe, lodLevel)); +} diff --git a/res/effectlib/specularBSDF.glsllib b/res/effectlib/specularBSDF.glsllib index 78e541a..028e6fb 100644 --- a/res/effectlib/specularBSDF.glsllib +++ b/res/effectlib/specularBSDF.glsllib @@ -32,16 +32,16 @@ #ifndef DEFAULT_MATERIAL_LIGHTING -vec4 specularBSDFEnvironment( in vec3 N, in vec3 viewDir, in vec3 tint, int mode ) +vec4 specularBSDFEnvironment(in vec3 N, in vec3 viewDir, in vec3 tint, int mode) { - vec3 rgb = vec3( 0.0, 0.0, 0.0 ); - if ( uEnvironmentMappingEnabled ) - { - vec3 R = reflect( -viewDir, N ); - rgb = evalEnvironmentMap( R, 0.0 ); - rgb = specularBSDF( N, R, viewDir, rgb, 1.0, 256.0, tint, scatter_reflect ).rgb; - } - return( vec4( rgb, 1.0 ) ); + vec3 rgb = vec3( 0.0, 0.0, 0.0 ); + if ( uEnvironmentMappingEnabled ) + { + vec3 R = reflect(-viewDir, N); + rgb = evalEnvironmentMap(R, 0.0); + rgb = specularBSDF(N, R, viewDir, rgb, 256.0).rgb; + } + return vec4(rgb, 1.0); } #endif diff --git a/res/effectlib/transformCoordinate.glsllib b/res/effectlib/transformCoordinate.glsllib index ccdf7d0..cbe20e7 100644 --- a/res/effectlib/transformCoordinate.glsllib +++ b/res/effectlib/transformCoordinate.glsllib @@ -40,4 +40,13 @@ texture_coordinate_info transformCoordinate( in mat4 transform, in texture_coord return( tci ); } +texture_coordinate_info scaleCoordinate(in vec3 scale, in texture_coordinate_info coordinate) +{ + texture_coordinate_info tci; + tci.position = scale * coordinate.position; + tci.tangent_u = scale * coordinate.tangent_u; + tci.tangent_v = scale * coordinate.tangent_v; + return tci; +} + #endif |