From e5e17f55abca52bf6b93592fb68da88f0ddb3305 Mon Sep 17 00:00:00 2001
From: Tomi Korpipaa <tomi.korpipaa@qt.io>
Date: Fri, 28 Feb 2020 09:04:26 +0200
Subject: [PATCH] Add tilt shift effect
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Change-Id: I74ec0be689b6e51fb289e2c99c8da66da70296f2
Reviewed-by: Antti Määttä <antti.maatta@qt.io>
Reviewed-by: Christian Strømme <christian.stromme@qt.io>
---
 src/imports/effectlib/TiltShift.qml           | 93 +++++++++++++++++++
 src/imports/effectlib/plugin.pro              |  3 +-
 src/imports/effectlib/qmldir                  |  1 +
 src/imports/effectlib/qteffectlibrary.qrc     |  3 +
 .../shaders/downsampletiltshift.frag          | 38 ++++++++
 .../shaders/poissonblurtiltshift.frag         | 50 ++++++++++
 .../shaders/poissonblurtiltshift.vert         |  6 ++
 7 files changed, 193 insertions(+), 1 deletion(-)
 create mode 100644 src/imports/effectlib/TiltShift.qml
 create mode 100644 src/imports/effectlib/shaders/downsampletiltshift.frag
 create mode 100644 src/imports/effectlib/shaders/poissonblurtiltshift.frag
 create mode 100644 src/imports/effectlib/shaders/poissonblurtiltshift.vert

diff --git a/src/imports/effectlib/TiltShift.qml b/src/imports/effectlib/TiltShift.qml
new file mode 100644
index 000000000..1d3892ef1
--- /dev/null
+++ b/src/imports/effectlib/TiltShift.qml
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Quick 3D.
+**
+** $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$
+**
+****************************************************************************/
+
+import QtQuick 2.15
+import QtQuick3D 1.15
+import QtQuick3D.Effects 1.15
+
+Effect {
+    property TextureInput sourceSampler: TextureInput {
+        texture: Texture {}
+    }
+    property real focusPosition: 0.5    // 0 - 1
+    property real focusWidth: 0.2       // 0 - 1
+    property real blurAmount: 4         // 0 - 10
+    property bool isVertical: false
+    property bool isInverted: false
+
+    Shader {
+        id: downsampleVert
+        stage: Shader.Vertex
+        shader: "shaders/downsample.vert"
+    }
+    Shader {
+        id: downsampleFrag
+        stage: Shader.Fragment
+        shader: "shaders/downsampletiltshift.frag"
+    }
+
+    Shader {
+        id: blurVert
+        stage: Shader.Vertex
+        shader: "shaders/poissonblurtiltshift.vert"
+    }
+    Shader {
+        id: blurFrag
+        stage: Shader.Fragment
+        shader: "shaders/poissonblurtiltshift.frag"
+    }
+
+    Buffer {
+        id: downsampleBuffer
+        name: "downsampleBuffer"
+        format: Buffer.RGBA8
+        textureFilterOperation: Buffer.Linear
+        textureCoordOperation: Buffer.ClampToEdge
+        bufferFlags: Buffer.None
+        sizeMultiplier: 0.5
+    }
+
+    passes: [
+        Pass {
+            shaders: [ downsampleVert, downsampleFrag ]
+            output: downsampleBuffer
+        },
+        Pass {
+            shaders: [ blurVert, blurFrag ]
+            commands: [
+                BufferInput {
+                    buffer: downsampleBuffer
+                },
+                BufferInput {
+                    param: "sourceSampler"
+                }
+            ]
+        }
+    ]
+}
diff --git a/src/imports/effectlib/plugin.pro b/src/imports/effectlib/plugin.pro
index 60673008a..a981fb1e7 100644
--- a/src/imports/effectlib/plugin.pro
+++ b/src/imports/effectlib/plugin.pro
@@ -4,8 +4,9 @@ TARGETPATH = QtQuick3D/Effects
 QT += quick qml quick3d-private
 IMPORT_VERSION = 1.$$QT_MINOR_VERSION
 QML_FILES = \
-    SCurveTonemap.qml \
     Vignette.qml \
+    TiltShift.qml \
+    SCurveTonemap.qml \
     Scatter.qml \
     MotionBlur.qml \
     HDRBloomTonemap.qml \
diff --git a/src/imports/effectlib/qmldir b/src/imports/effectlib/qmldir
index a4e96acee..1af833901 100644
--- a/src/imports/effectlib/qmldir
+++ b/src/imports/effectlib/qmldir
@@ -20,6 +20,7 @@ HDRBloomTonemap 1.0 HDRBloomTonemap.qml
 MotionBlur 1.0 MotionBlur.qml
 Scatter 1.0 Scatter.qml
 SCurveTonemap 1.0 SCurveTonemap.qml
+TiltShift 1.0 TiltShift.qml
 Vignette 1.0 Vignette.qml
 designersupported
 depends QtQuick3D 1.15
diff --git a/src/imports/effectlib/qteffectlibrary.qrc b/src/imports/effectlib/qteffectlibrary.qrc
index d24e8053e..b9eb9ba7e 100644
--- a/src/imports/effectlib/qteffectlibrary.qrc
+++ b/src/imports/effectlib/qteffectlibrary.qrc
@@ -38,5 +38,8 @@
         <file>shaders/motionblurhorizontal.frag</file>
         <file>shaders/motionblurvertical.frag</file>
         <file>shaders/blend.frag</file>
+        <file>shaders/downsampletiltshift.frag</file>
+        <file>shaders/poissonblurtiltshift.vert</file>
+        <file>shaders/poissonblurtiltshift.frag</file>
     </qresource>
 </RCC>
diff --git a/src/imports/effectlib/shaders/downsampletiltshift.frag b/src/imports/effectlib/shaders/downsampletiltshift.frag
new file mode 100644
index 000000000..da81e5076
--- /dev/null
+++ b/src/imports/effectlib/shaders/downsampletiltshift.frag
@@ -0,0 +1,38 @@
+#include "blur.glsllib"
+
+float AdvancedGetTiltShiftMultiplier(vec2 inTexCoord, float inFocusBarHeight, float inFocusWidth,
+                                     bool inVertical, bool inInvert)
+{
+    float texPos = inVertical ? inTexCoord.x : inTexCoord.y;
+    float focusDiff = max(0.0, abs(texPos - inFocusBarHeight) - (inFocusWidth / 2.0))
+            / inFocusWidth;
+    float retval = clamp(focusDiff, 0.0, 1.0);
+    return inInvert ? 1.0 - retval : retval;
+}
+
+vec4 AdvancedBoxTiltShiftBlur(sampler2D inBlurSampler, float inBlurSamplerAlphaFlag,
+                              float inFocusBarHeight, float inFocusWidth,
+                              bool inVertical, bool inInvert)
+{
+    float mult0 = .25 * AdvancedGetTiltShiftMultiplier(TexCoord0, inFocusBarHeight, inFocusWidth,
+                                                       inVertical, inInvert);
+    float mult1 = .25 * AdvancedGetTiltShiftMultiplier(TexCoord1, inFocusBarHeight, inFocusWidth,
+                                                       inVertical, inInvert);
+    float mult2 = .25 * AdvancedGetTiltShiftMultiplier(TexCoord2, inFocusBarHeight, inFocusWidth,
+                                                       inVertical, inInvert);
+    float mult3 = .25 * AdvancedGetTiltShiftMultiplier(TexCoord3, inFocusBarHeight, inFocusWidth,
+                                                       inVertical, inInvert);
+    float multTotal = mult0 + mult1 + mult2 + mult3;
+    float totalDivisor = multTotal != 0.0 ? 1.0 / multTotal : 0.0;
+    vec4 outCol = GetTextureValuePreMult(inBlurSampler, TexCoord0) * mult0;
+    outCol += GetTextureValuePreMult(inBlurSampler, TexCoord1) * mult1;
+    outCol += GetTextureValuePreMult(inBlurSampler, TexCoord2) * mult2;
+    outCol += GetTextureValuePreMult(inBlurSampler, TexCoord3) * mult3;
+    return outCol * totalDivisor;
+}
+
+void frag()
+{
+    gl_FragColor = AdvancedBoxTiltShiftBlur(Texture0, Texture0Info.z, focusPosition, focusWidth,
+                                            isVertical, isInverted);
+}
diff --git a/src/imports/effectlib/shaders/poissonblurtiltshift.frag b/src/imports/effectlib/shaders/poissonblurtiltshift.frag
new file mode 100644
index 000000000..6c9bf82bf
--- /dev/null
+++ b/src/imports/effectlib/shaders/poissonblurtiltshift.frag
@@ -0,0 +1,50 @@
+#include "blur.glsllib"
+
+float AdvancedGetTiltShiftMultiplier(vec2 inTexCoord, float inFocusBarHeight, float inFocusWidth,
+                                     bool inVertical, bool inInvert)
+{
+    float texPos = inVertical ? inTexCoord.x : inTexCoord.y;
+    float focusDiff = max(0.0, abs(texPos - inFocusBarHeight) - (inFocusWidth / 2.0))
+            / inFocusWidth;
+    float retval = clamp(focusDiff, 0.0, 1.0);
+    return inInvert ? 1.0 - retval : retval;
+}
+
+vec4 AdvancedPoissonTiltShiftBlur(sampler2D inSampler, float inAlphaFlag, float inBarHeight,
+                                  float inFocusWidth, bool inVertical, bool inInvert)
+{
+    float mult0 = (1.0 - poisson0.z) * AdvancedGetTiltShiftMultiplier(TexCoord0, inBarHeight,
+                                                                      inFocusWidth, inVertical,
+                                                                      inInvert);
+    float mult1 = (1.0 - poisson1.z) * AdvancedGetTiltShiftMultiplier(TexCoord1, inBarHeight,
+                                                                      inFocusWidth, inVertical,
+                                                                      inInvert);
+    float mult2 = (1.0 - poisson2.z) * AdvancedGetTiltShiftMultiplier(TexCoord2, inBarHeight,
+                                                                      inFocusWidth, inVertical,
+                                                                      inInvert);
+    float mult3 = (1.0 - poisson3.z) * AdvancedGetTiltShiftMultiplier(TexCoord3, inBarHeight,
+                                                                      inFocusWidth, inVertical,
+                                                                      inInvert);
+    float mult4 = (1.0 - poisson4.z) * AdvancedGetTiltShiftMultiplier(TexCoord4, inBarHeight,
+                                                                      inFocusWidth, inVertical,
+                                                                      inInvert);
+
+    float multTotal = mult0 + mult1 + mult2 + mult3 + mult4;
+    float multMultiplier = multTotal > 0.0 ? 1.0 / multTotal : 0.0;
+
+    vec4 outColor = GetTextureValuePreMult(inSampler, TexCoord0) * (mult0 * multMultiplier);
+    outColor += GetTextureValuePreMult(inSampler, TexCoord1) * (mult1 * multMultiplier);
+    outColor += GetTextureValuePreMult(inSampler, TexCoord2) * (mult2 * multMultiplier);
+    outColor += GetTextureValuePreMult(inSampler, TexCoord3) * (mult3 * multMultiplier);
+    outColor += GetTextureValuePreMult(inSampler, TexCoord4) * (mult4 * multMultiplier);
+    return outColor;
+}
+
+void frag()
+{
+    float centerMultiplier = AdvancedGetTiltShiftMultiplier(TexCoord, focusPosition, focusWidth,
+                                                             isVertical, isInverted);
+    vec4 blurColor = AdvancedPoissonTiltShiftBlur(Texture0, Texture0Info.z, focusPosition,
+                                                  focusWidth, isVertical, isInverted);
+    gl_FragColor = mix(texture2D_sourceSampler(TexCoord), blurColor, centerMultiplier);
+}
diff --git a/src/imports/effectlib/shaders/poissonblurtiltshift.vert b/src/imports/effectlib/shaders/poissonblurtiltshift.vert
new file mode 100644
index 000000000..43f45d7a4
--- /dev/null
+++ b/src/imports/effectlib/shaders/poissonblurtiltshift.vert
@@ -0,0 +1,6 @@
+#include "blur.glsllib"
+
+void vert()
+{
+    SetupPoissonBlurCoords(blurAmount, DestSize.xy);
+}
-- 
GitLab