1/****************************************************************************
2**
3** Copyright (C) 2014 NVIDIA Corporation.
4** Copyright (C) 2019 The Qt Company Ltd.
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of Qt 3D Studio.
8**
9** $QT_BEGIN_LICENSE:GPL$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU
20** General Public License version 3 or (at your option) any later version
21** approved by the KDE Free Qt Foundation. The licenses are as published by
22** the Free Software Foundation and appearing in the file LICENSE.GPL3
23** included in the packaging of this file. Please review the following
24** information to ensure the GNU General Public License requirements will
25** be met: https://www.gnu.org/licenses/gpl-3.0.html.
26**
27** $QT_END_LICENSE$
28**
29****************************************************************************/
30
31#ifndef SCREEN_SPACE_DO_GLSLLIB
32#define SCREEN_SPACE_DO_GLSLLIB 1
33
34#include "depthpass.glsllib"
35
36vec3 getViewSpacePos( sampler2D depthSampler, vec2 camProps, vec2 UV, vec4 UvToEye )
37{
38    float sampleDepth = getDepthValue( texture(depthSampler, UV), camProps );
39    sampleDepth = depthValueToLinearDistance( sampleDepth, camProps );
40
41    vec2 scaledUV = (UV * UvToEye.xy) + UvToEye.zw;
42    return vec3(scaledUV * sampleDepth, sampleDepth);
43}
44
45float shadowOcclusion(sampler2D depthSampler, vec3 lightDir, vec3 worldPos, mat4 viewMat, mat4 viewProj, vec4 shadowParams, vec2 camProps, vec4 aoScreen, vec4 UvToEye)
46{
47    vec3 viewPos = getViewSpacePos( depthSampler, camProps, ( gl_FragCoord.xy * aoScreen.zw ), UvToEye );
48    float depth = viewPos.z;
49
50    // Get the screen-space UV
51    vec2 centerUV = gl_FragCoord.xy * aoScreen.zw;
52
53    float screenDist = shadowParams.y * 3.1415926535 * aoScreen.y / viewPos.z;
54    if (screenDist < 1.0) { return 1.0; }
55
56    vec3 viewL = normalize( (viewMat * vec4(lightDir, 0)).xyz );
57
58    float steps = min( screenDist, 20.0 );
59    int maxCt = int(steps);
60    float step = 3.1415926535 * shadowParams.y / float(maxCt);
61    float ret = float(maxCt);
62
63    for( int i = 0; i < maxCt; ++i )
64    {
65        vec3 ray = lightDir * step * float(i);
66        vec3 samplePos = worldPos - ray;
67
68        vec4 smpUV = viewProj * vec4(samplePos, 1.0);
69        smpUV /= smpUV.w;
70        smpUV.xy = (smpUV.xy + 1.0) * 0.5;
71
72        vec3 testPos = getViewSpacePos( depthSampler, camProps, smpUV.xy, UvToEye );
73        testPos.z += shadowParams.w;
74        vec3 testVec = normalize(viewPos - testPos);
75        testVec -= viewL;
76        float isBehind = clamp( testVec.z, 0.0, 1.0 );
77    float diff = (testPos.z - depth) / shadowParams.y;
78        ret -= isBehind * (1.0 / (1.0 + diff * diff));
79    }
80
81    ret /= float(maxCt);    // divide by number of samples;
82    // Blend between soft and hard based on softness param
83    // NOTE : the 0.72974 is actually an gamma-inverted 0.5 (assuming gamma 2.2)
84    // Would not need this if we linearized color instead.
85    float hardCut = (ret <= 0.72974) ? 0.0 : 1.0;
86    ret = shadowParams.z * ret + (1.0 - shadowParams.z) * hardCut;
87
88    // Blend between full and no occlusion based on strength param
89    ret = shadowParams.x * ret + (1.0 - shadowParams.x);
90
91    return ret;
92}
93
94// For reference
95/*
96float glossyOcclusionBasis(sampler2D depthSampler, mat3 tanFrame, vec3 worldPos, mat4 viewProj, vec3 viewDir, vec4 shadowParams, vec2 camProps, float roughness)
97{
98    float ret = 16.0;
99
100    float kernel[16];
101    kernel[0] = 0.5; kernel[1] = 0.25;
102    kernel[2] = 0.75; kernel[3] = 0.125;
103    kernel[4] = 0.625; kernel[5] = 0.375;
104    kernel[6] = 0.875; kernel[7] = 0.0625;
105    kernel[8] = 0.5625; kernel[9] = 0.3125;
106    kernel[10] = 0.8125; kernel[11] = 0.1875;
107    kernel[12] = 0.6875; kernel[13] = 0.4375;
108    kernel[14] = 0.9375; kernel[15] = 0.03125;
109
110    float rough = clamp(roughness, 0.0001, 1.0);
111    float normFac = 1.0 / (rough);
112
113    float phiShift = hashRot( gl_FragCoord.xy );
114    ivec2 iCoords = ivec2( gl_FragCoord.xy );
115    float depth = getDepthValue( texelFetch(depthSampler, iCoords, 0) );
116    depth = depthValueToLinearDistance( depth, camProps );
117
118    for( int i = 0; i < 16; ++i )
119    {
120        vec3 localDir;
121        float phi = 6.28318530718 * (kernel[i] + phiShift);
122        float cosTheta = sqrt( float(i+1) / 33.0);
123        localDir.z = sqrt(1.0 - cosTheta*cosTheta) * normFac;
124        localDir.x = cos(phi) * cosTheta;
125        localDir.y = sin(phi) * cosTheta;
126
127        localDir = normalize(localDir);
128
129        vec3 halfDir = tanFrame[0]*localDir.x + tanFrame[1]*localDir.y + tanFrame[2]*localDir.z;
130        vec3 ray = reflect( -viewDir, halfDir ) * shadowParams.x;
131
132        vec4 samplePos = vec4( worldPos + ray, 1.0 );
133
134        vec4 sampleProj = viewProj * samplePos;
135        sampleProj /= sampleProj.w;
136        sampleProj.xy = (sampleProj.xy + 1.0) * 0.5;
137        float sampleDepth = getDepthValue( texture(depthSampler, sampleProj.xy) );
138
139        sampleDepth = depthValueToLinearDistance( sampleDepth, camProps );
140
141        // Occlusion is applied based on a Cauchy distribution filter
142        // But with a "dead zone" for the very close samples. By subtracting it from 16,
143        // which represents no occlusion (16/16 = 1), we let nearby occluders have a
144        // lot of effect, but far away occluders do not.  Furthermore, the "dead zone"
145        // in the filter means that the extremely near (which we assume to be part of the
146        // same surface) are also excluded to try and limit self-occlusion.
147        float occlDist = 4.0 * max(depth - sampleDepth - shadowParams.y, 0.0) / shadowParams.x;
148        float occlFactor = 1.0 / ( 1.0 + occlDist*occlDist*0.04 );
149        occlFactor -= 1.0 / ( 1.0 + occlDist*occlDist*4.0 );
150    ret -= min(2.0 * occlFactor, 1.0);
151    }
152
153    ret /= 16.0;        // divide by number of samples;
154    return ret;
155}
156*/
157
158#endif
159