diff options
author | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2018-10-05 13:58:50 +0200 |
---|---|---|
committer | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2018-10-05 13:58:50 +0200 |
commit | 6c77dea4711b6a88e80e30db21d622808e5ef9b6 (patch) | |
tree | 7f03934b19f5782447da135aeceb4269298e3f2a | |
parent | edc88e97721c0a223a2b77cec217f550f08a4135 (diff) | |
parent | d8789d8fd17fd58f06003e9846b3d107ffc8ec52 (diff) |
Merge remote-tracking branch 'origin/5.11' into 5.12
Change-Id: I2a92242b0d6be4f4e7f07f0f020fa6751ada9bc3
30 files changed, 631 insertions, 357 deletions
diff --git a/examples/qt3d/exampleresources/assets/cubemaps/miramar/qt_attribution.json b/examples/qt3d/exampleresources/assets/cubemaps/miramar/qt_attribution.json new file mode 100644 index 000000000..6eccf001c --- /dev/null +++ b/examples/qt3d/exampleresources/assets/cubemaps/miramar/qt_attribution.json @@ -0,0 +1,14 @@ +{ + "Id": "miramar-sky", + "Name": "Miramar Skybox Textures", + "QDocModule": "qt3d", + "QtUsage": "Used in the anaglyph-rendering example and autotests of Qt 3D.", + + "QtParts": [ "examples", "tests" ] , + "Description": "High res environment map (converted to webgl).", + "Homepage": "http://www.zfight.com/misc/files/textures/envmap_miramar.rar", + "DownloadLocation": "https://opengameart.org/sites/default/files/envmap_miramar.zip", + "License": "Modify however you like, just cred me for my work, maybe link to my page.", + "LicenseFile": "README.txt", + "Copyright": "Copyright (c) Jockum Skoglund aka hipshot" +} diff --git a/examples/qt3d/simple-qml/CameraController.qml b/examples/qt3d/simple-qml/CameraController.qml deleted file mode 100644 index 69eff70ed..000000000 --- a/examples/qt3d/simple-qml/CameraController.qml +++ /dev/null @@ -1,297 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 Paul Lemire <paul.lemire350@gmail.com> -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import Qt3D.Core 2.0 -import Qt3D.Render 2.0 -import Qt3D.Input 2.0 -import Qt3D.Logic 2.0 -import QtQml 2.2 - -Entity { - id: root - property Camera camera - property real linearSpeed: 10.0 - property real orbitSpeed: -180.0 - property real lookSpeed: 180.0 - property bool firstPersonMode: true - - QtObject { - id: d - readonly property vector3d firstPersonUp: Qt.vector3d(0, 1, 0) - property bool leftMouseButtonPressed: false - property bool rightMouseButtonPressed: false - property real vx: 0; - property real vy: 0; - property real vz: 0; - property real dx: 0 - property real dy: 0 - property bool fineMotion: false - } - - KeyboardDevice { - id: keyboardSourceDevice - } - - MouseDevice { - id: mouseSourceDevice - sensitivity: d.fineMotion ? 0.01 : 0.1 - } - - LogicalDevice { - id: cameraControlDevice - - actions: [ - Action { - name: "LMB" - inputs: [ - ActionInput { - sourceDevice: mouseSourceDevice - buttons: [MouseEvent.LeftButton] - } - ] - }, - Action { - name: "RMB" - inputs: [ - ActionInput { - sourceDevice: mouseSourceDevice - buttons: [MouseEvent.RightButton] - } - ] - }, - Action { - name: "fineMotion" - inputs: [ - ActionInput { - sourceDevice: keyboardSourceDevice - buttons: [Qt.Key_Shift] - } - ] - } - - ] // actions - - axes: [ - // Rotation - Axis { - name: "RX" - inputs: [ - AnalogAxisInput { - sourceDevice: mouseSourceDevice - axis: MouseDevice.X - } - ] - }, - Axis { - name: "RY" - inputs: [ - AnalogAxisInput { - sourceDevice: mouseSourceDevice - axis: MouseDevice.Y - } - ] - }, - // Translation - Axis { - name: "TX" - inputs: [ - ButtonAxisInput { - sourceDevice: keyboardSourceDevice - buttons: [Qt.Key_Left] - scale: -1.0 - }, - ButtonAxisInput { - sourceDevice: keyboardSourceDevice - buttons: [Qt.Key_Right] - scale: 1.0 - } - ] - }, - Axis { - name: "TZ" - inputs: [ - ButtonAxisInput { - sourceDevice: keyboardSourceDevice - buttons: [Qt.Key_Up] - scale: 1.0 - }, - ButtonAxisInput { - sourceDevice: keyboardSourceDevice - buttons: [Qt.Key_Down] - scale: -1.0 - } - ] - }, - Axis { - name: "TY" - inputs: [ - ButtonAxisInput { - sourceDevice: keyboardSourceDevice - buttons: [Qt.Key_PageUp] - scale: 1.0 - }, - ButtonAxisInput { - sourceDevice: keyboardSourceDevice - buttons: [Qt.Key_PageDown] - scale: -1.0 - } - ] - } - ] // axes - } - - components: [ - AxisActionHandler { - id: handler - logicalDevice: cameraControlDevice - - onAxisValueChanged: { - - switch (name) { - - case "TX": { - d.vx = axisValue * linearSpeed - break; - } - - case "TY": { - d.vy = axisValue * linearSpeed - break; - } - - case "TZ": { - d.vz = axisValue * linearSpeed - break; - } - - case "RX": { - d.dx = axisValue; - break; - } - - case "RY": { - d.dy = axisValue; - break; - } - - } - } - - onActionStarted: { - - switch (name) { - - case "LMB": { - d.leftMouseButtonPressed = true; - break; - } - - case "RMB": { - d.rightMouseButtonPressed = true; - break; - } - - case "fineMotion": { - console.log("fineMotion started") - d.fineMotion = true; - break; - } - - } - - } - - onActionFinished: { - - switch (name) { - - case "LMB": { - d.leftMouseButtonPressed = false; - break; - } - - case "RMB": { - d.rightMouseButtonPressed = false; - break; - } - - case "fineMotion": { - console.log("fineMotion finished") - d.fineMotion = false; - break; - } - - } - } - }, - - FrameAction { - onTriggered: { - // The time difference since the last frame is passed in as the - // argument dt. It is a floating point value in units of seconds. - root.camera.translate(Qt.vector3d(d.vx, d.vy, d.vz).times(dt)) - - if (d.leftMouseButtonPressed) { - if (root.firstPersonMode) - root.camera.pan(root.lookSpeed * d.dx * dt, d.firstPersonUp) - else - root.camera.pan(root.lookSpeed * d.dx * dt) - root.camera.tilt(root.lookSpeed * d.dy * dt) - } else if (d.rightMouseButtonPressed) { - if (root.firstPersonMode) - root.camera.panAboutViewCenter(root.lookSpeed * d.dx * dt, d.firstPersonUp) - else - root.camera.panAboutViewCenter(root.lookSpeed * d.dx * dt) - root.camera.tiltAboutViewCenter(root.orbitSpeed * d.dy * dt) - } - } - } - ] // components -} diff --git a/examples/qt3d/simple-qml/doc/src/simple-qml.qdoc b/examples/qt3d/simple-qml/doc/src/simple-qml.qdoc index 13ca8ff1f..9d4f55c52 100644 --- a/examples/qt3d/simple-qml/doc/src/simple-qml.qdoc +++ b/examples/qt3d/simple-qml/doc/src/simple-qml.qdoc @@ -65,20 +65,4 @@ \skipto InputSettings \printuntil } - - \section1 - - \section1 Specifying Settings and Axes - - In the \e CameraController.qml file, we use the LogicalDevice type to define - a set of actions and axes to use within the application: - - \quotefromfile simple-qml/CameraController.qml - \skipto LogicalDevice { - \printuntil ] - \dots - \skipto axes - \printuntil ] - \dots - \skipto /^\}/ */ diff --git a/examples/qt3d/simple-qml/simple-qml.qrc b/examples/qt3d/simple-qml/simple-qml.qrc index 9d95d9835..5f6483ac3 100644 --- a/examples/qt3d/simple-qml/simple-qml.qrc +++ b/examples/qt3d/simple-qml/simple-qml.qrc @@ -1,6 +1,5 @@ <RCC> <qresource prefix="/"> <file>main.qml</file> - <file>CameraController.qml</file> </qresource> </RCC> diff --git a/src/core/jobs/qthreadpooler.cpp b/src/core/jobs/qthreadpooler.cpp index 6819faca7..ca123ddad 100644 --- a/src/core/jobs/qthreadpooler.cpp +++ b/src/core/jobs/qthreadpooler.cpp @@ -41,6 +41,11 @@ #include <QtCore/QDebug> #if QT_CONFIG(qt3d_profile_jobs) + +#ifdef Q_OS_ANDROID +#include <QtCore/QStandardPaths> +#endif + #include <QtCore/QCoreApplication> #include <QtCore/QFile> #include <QtCore/QThreadStorage> diff --git a/src/core/qchangearbiter.cpp b/src/core/qchangearbiter.cpp index d6c7e05df..2e32d6722 100644 --- a/src/core/qchangearbiter.cpp +++ b/src/core/qchangearbiter.cpp @@ -217,12 +217,15 @@ void QChangeArbiter::registerSceneObserver(QSceneObserverInterface *observer) void QChangeArbiter::unregisterObserver(QObserverInterface *observer, QNodeId nodeId) { QMutexLocker locker(&m_mutex); - if (m_nodeObservations.contains(nodeId)) { - QObserverList &observers = m_nodeObservations[nodeId]; + const auto it = m_nodeObservations.find(nodeId); + if (it != m_nodeObservations.end()) { + QObserverList &observers = it.value(); for (int i = observers.count() - 1; i >= 0; i--) { if (observers[i].second == observer) observers.removeAt(i); } + if (observers.isEmpty()) + m_nodeObservations.erase(it); } } diff --git a/src/doc/src/qmlextramaterials.qdoc b/src/doc/src/qmlextramaterials.qdoc index 10198845f..c54cc948b 100644 --- a/src/doc/src/qmlextramaterials.qdoc +++ b/src/doc/src/qmlextramaterials.qdoc @@ -28,6 +28,8 @@ /*! \qmltype DiffuseMapMaterial \inqmlmodule Qt3D.Extras + \obsolete + \brief The DiffuseMapMaterial provides a default implementation of the phong lighting effect where the diffuse light component is read from a texture map. \since 5.7 @@ -86,6 +88,8 @@ /*! \qmltype DiffuseSpecularMapMaterial \inqmlmodule Qt3D.Extras + \obsolete + \brief The DiffuseSpecularMapMaterial provides a default implementation of the phong lighting effect where the diffuse and specular light components are read from texture maps. \since 5.7 @@ -220,6 +224,8 @@ /*! \qmltype NormalDiffuseMapAlphaMaterial \inqmlmodule Qt3D.Extras + \obsolete + \brief The NormalDiffuseMapAlphaMaterial provides a specialization of NormalDiffuseMapMaterial with alpha coverage and a depth test performed in the rendering pass. \since 5.7 @@ -291,6 +297,8 @@ /*! \qmltype NormalDiffuseMapMaterial \inqmlmodule Qt3D.Extras + \obsolete + \brief The NormalDiffuseMapMaterial provides a default implementation of the phong lighting and bump effect where the diffuse light component is read from a texture map and the normals of the mesh being rendered from a normal texture map. @@ -363,6 +371,8 @@ /*! \qmltype NormalDiffuseSpecularMapMaterial \inqmlmodule Qt3D.Extras + \obsolete + \brief The NormalDiffuseSpecularMapMaterial provides a default implementation of the phong lighting and bump effect where the diffuse and specular light components are read from texture maps and the normals of the mesh being rendered from a normal texture map. @@ -465,6 +475,8 @@ /*! \qmltype PhongAlphaMaterial \inqmlmodule Qt3D.Extras + \obsolete + \brief The PhongAlphaMaterial class provides a default implementation of the phong lighting effect with alpha. \since 5.7 @@ -516,6 +528,8 @@ /*! \qmltype PhongMaterial \inqmlmodule Qt3D.Extras + \obsolete + \brief The PhongMaterial class provides a default implementation of the phong lighting effect. \since 5.7 \inherits Qt3D.Render::Material diff --git a/src/extras/defaults/qmorphphongmaterial.cpp b/src/extras/defaults/qmorphphongmaterial.cpp index ade9f8542..1711a21dd 100644 --- a/src/extras/defaults/qmorphphongmaterial.cpp +++ b/src/extras/defaults/qmorphphongmaterial.cpp @@ -44,6 +44,7 @@ #include <Qt3DRender/qparameter.h> #include <Qt3DRender/qrenderpass.h> #include <Qt3DRender/qgraphicsapifilter.h> +#include <Qt3DRender/qshaderprogrambuilder.h> #include <QUrl> #include <QVector3D> #include <QVector4D> @@ -57,9 +58,9 @@ namespace Qt3DExtras { QMorphPhongMaterialPrivate::QMorphPhongMaterialPrivate() : QMaterialPrivate() , m_phongEffect(new QEffect()) - , m_ambientParameter(new QParameter(QStringLiteral("ka"), QColor::fromRgbF(0.05f, 0.05f, 0.05f, 1.0f))) - , m_diffuseParameter(new QParameter(QStringLiteral("kd"), QColor::fromRgbF(0.7f, 0.7f, 0.7f, 1.0f))) - , m_specularParameter(new QParameter(QStringLiteral("ks"), QColor::fromRgbF(0.01f, 0.01f, 0.01f, 1.0f))) + , m_ambientParameter(new QParameter(QStringLiteral("ka"), QColor::fromRgbF(0.05, 0.05, 0.05, 1.0))) + , m_diffuseParameter(new QParameter(QStringLiteral("kd"), QColor::fromRgbF(0.7, 0.7, 0.7, 1.0))) + , m_specularParameter(new QParameter(QStringLiteral("ks"), QColor::fromRgbF(0.01, 0.01, 0.01, 1.0))) , m_shininessParameter(new QParameter(QStringLiteral("shininess"), 150.0f)) , m_interpolatorParameter(new QParameter(QStringLiteral("interpolator"), 0.0f)) , m_phongGL3Technique(new QTechnique()) @@ -70,12 +71,16 @@ QMorphPhongMaterialPrivate::QMorphPhongMaterialPrivate() , m_phongES2RenderPass(new QRenderPass()) , m_phongGL3Shader(new QShaderProgram()) , m_phongGL2ES2Shader(new QShaderProgram()) + , m_phongGL3ShaderBuilder(new QShaderProgramBuilder()) + , m_phongGL2ES2ShaderBuilder(new QShaderProgramBuilder()) , m_filterKey(new QFilterKey) { } void QMorphPhongMaterialPrivate::init() { + Q_Q(QMorphPhongMaterial); + connect(m_ambientParameter, &Qt3DRender::QParameter::valueChanged, this, &QMorphPhongMaterialPrivate::handleAmbientChanged); connect(m_diffuseParameter, &Qt3DRender::QParameter::valueChanged, @@ -88,9 +93,19 @@ void QMorphPhongMaterialPrivate::init() this, &QMorphPhongMaterialPrivate::handleInterpolatorChanged); m_phongGL3Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/morphphong.vert")))); - m_phongGL3Shader->setFragmentShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/phong.frag")))); + m_phongGL3ShaderBuilder->setParent(q); + m_phongGL3ShaderBuilder->setShaderProgram(m_phongGL3Shader); + m_phongGL3ShaderBuilder->setFragmentShaderGraph(QUrl(QStringLiteral("qrc:/shaders/graphs/phong.frag.json"))); + m_phongGL3ShaderBuilder->setEnabledLayers({QStringLiteral("diffuse"), + QStringLiteral("specular"), + QStringLiteral("normal")}); m_phongGL2ES2Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/es2/morphphong.vert")))); - m_phongGL2ES2Shader->setFragmentShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/es2/phong.frag")))); + m_phongGL2ES2ShaderBuilder->setParent(q); + m_phongGL2ES2ShaderBuilder->setShaderProgram(m_phongGL2ES2Shader); + m_phongGL2ES2ShaderBuilder->setFragmentShaderGraph(QUrl(QStringLiteral("qrc:/shaders/graphs/phong.frag.json"))); + m_phongGL2ES2ShaderBuilder->setEnabledLayers({QStringLiteral("diffuse"), + QStringLiteral("specular"), + QStringLiteral("normal")}); m_phongGL3Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL); m_phongGL3Technique->graphicsApiFilter()->setMajorVersion(3); @@ -115,7 +130,6 @@ void QMorphPhongMaterialPrivate::init() m_phongGL2Technique->addRenderPass(m_phongGL2RenderPass); m_phongES2Technique->addRenderPass(m_phongES2RenderPass); - Q_Q(QMorphPhongMaterial); m_filterKey->setParent(q); m_filterKey->setName(QStringLiteral("renderingStyle")); m_filterKey->setValue(QStringLiteral("forward")); diff --git a/src/extras/defaults/qmorphphongmaterial_p.h b/src/extras/defaults/qmorphphongmaterial_p.h index 25bff9042..28b7750d9 100644 --- a/src/extras/defaults/qmorphphongmaterial_p.h +++ b/src/extras/defaults/qmorphphongmaterial_p.h @@ -60,6 +60,7 @@ class QTechnique; class QParameter; class QShaderProgram; class QRenderPass; +class QShaderProgramBuilder; } // namespace Qt3DRender @@ -94,6 +95,8 @@ public: Qt3DRender::QRenderPass *m_phongES2RenderPass; Qt3DRender::QShaderProgram *m_phongGL3Shader; Qt3DRender::QShaderProgram *m_phongGL2ES2Shader; + Qt3DRender::QShaderProgramBuilder *m_phongGL3ShaderBuilder; + Qt3DRender::QShaderProgramBuilder *m_phongGL2ES2ShaderBuilder; Qt3DRender::QFilterKey *m_filterKey; Q_DECLARE_PUBLIC(QMorphPhongMaterial) diff --git a/src/extras/defaults/qorbitcameracontroller.cpp b/src/extras/defaults/qorbitcameracontroller.cpp index 6d3e83bcb..aff91f6cf 100644 --- a/src/extras/defaults/qorbitcameracontroller.cpp +++ b/src/extras/defaults/qorbitcameracontroller.cpp @@ -186,7 +186,7 @@ void QOrbitCameraController::moveCamera(const QAbstractCameraController::InputSt } else if (state.shiftKeyActive) { if (zoomDistance(camera()->position(), theCamera->viewCenter()) > d->m_zoomInLimit * d->m_zoomInLimit) { // Dolly - theCamera->translate(QVector3D(0, 0, state.tyAxisValue * linearSpeed() * dt), theCamera->DontTranslateViewCenter); + theCamera->translate(QVector3D(0, 0, state.tzAxisValue * linearSpeed() * dt), theCamera->DontTranslateViewCenter); } else { theCamera->translate(QVector3D(0, 0, -0.5), theCamera->DontTranslateViewCenter); } diff --git a/src/extras/extras.qrc b/src/extras/extras.qrc index bfb14f3f9..8bbffd272 100644 --- a/src/extras/extras.qrc +++ b/src/extras/extras.qrc @@ -5,14 +5,17 @@ <file>shaders/gl3/light.inc.frag</file> <file>shaders/es2/light.inc.frag</file> <file>shaders/es2/light.inc.frag100</file> + <file>shaders/es3/light.inc.frag</file> <file>shaders/gl3/phong.inc.frag</file> <file>shaders/es2/phong.inc.frag</file> <file>shaders/es2/phong.inc.frag100</file> <file>shaders/gl3/metalrough.inc.frag</file> + <file>shaders/es3/metalrough.inc.frag</file> <file>shaders/gl3/coordinatesystems.inc</file> <file>shaders/es2/coordinatesystems.inc</file> <file>shaders/gl3/default.vert</file> <file>shaders/es2/default.vert</file> + <file>shaders/es3/default.vert</file> <file>shaders/gl3/pervertexcolor.frag</file> <file>shaders/gl3/pervertexcolor.vert</file> <file>shaders/es2/pervertexcolor.frag</file> diff --git a/src/extras/shaders/es2/morphphong.vert b/src/extras/shaders/es2/morphphong.vert index d091e87c0..89877dca8 100644 --- a/src/extras/shaders/es2/morphphong.vert +++ b/src/extras/shaders/es2/morphphong.vert @@ -25,7 +25,7 @@ void main() morphNormal = normalize(vertexNormal + vertexNormalTarget * abs(interpolator)); } - worldNormal = normalize( modelNormalMatrix * morphPos ); + worldNormal = normalize( modelNormalMatrix * morphNormal ); worldPosition = vec3( modelMatrix * vec4( morphPos, 1.0 ) ); gl_Position = modelViewProjection * vec4( morphPos, 1.0 ); diff --git a/src/extras/shaders/es3/default.vert b/src/extras/shaders/es3/default.vert new file mode 100644 index 000000000..7641882f2 --- /dev/null +++ b/src/extras/shaders/es3/default.vert @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#version 300 es + +in vec3 vertexPosition; +in vec3 vertexNormal; +in vec4 vertexTangent; +in vec2 vertexTexCoord; + +out vec3 worldPosition; +out vec3 worldNormal; +out vec4 worldTangent; +out vec2 texCoord; + +uniform mat4 modelMatrix; +uniform mat3 modelNormalMatrix; +uniform mat4 modelViewProjection; + +uniform float texCoordScale; + +void main() +{ + // Pass through scaled texture coordinates + texCoord = vertexTexCoord * texCoordScale; + + // Transform position, normal, and tangent to world space + worldPosition = vec3(modelMatrix * vec4(vertexPosition, 1.0)); + worldNormal = normalize(modelNormalMatrix * vertexNormal); + worldTangent.xyz = normalize(vec3(modelMatrix * vec4(vertexTangent.xyz, 0.0))); + worldTangent.w = vertexTangent.w; + + // Calculate vertex position in clip coordinates + gl_Position = modelViewProjection * vec4(vertexPosition, 1.0); +} diff --git a/src/extras/shaders/es3/light.inc.frag b/src/extras/shaders/es3/light.inc.frag new file mode 100644 index 000000000..9d03fca54 --- /dev/null +++ b/src/extras/shaders/es3/light.inc.frag @@ -0,0 +1,25 @@ +const int MAX_LIGHTS = 8; +const int TYPE_POINT = 0; +const int TYPE_DIRECTIONAL = 1; +const int TYPE_SPOT = 2; +struct Light { + int type; + vec3 position; + vec3 color; + float intensity; + vec3 direction; + float constantAttenuation; + float linearAttenuation; + float quadraticAttenuation; + float cutOffAngle; +}; +uniform Light lights[MAX_LIGHTS]; +uniform int lightCount; + +// Pre-convolved environment maps +struct EnvironmentLight { + highp samplerCube irradiance; // For diffuse contribution + highp samplerCube specular; // For specular contribution +}; +uniform EnvironmentLight envLight; +uniform int envLightCount; diff --git a/src/extras/shaders/es3/metalrough.inc.frag b/src/extras/shaders/es3/metalrough.inc.frag new file mode 100644 index 000000000..85f392f4c --- /dev/null +++ b/src/extras/shaders/es3/metalrough.inc.frag @@ -0,0 +1,348 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +precision highp float; + +// Exposure correction +uniform float exposure; +// Gamma correction +const float gamma = 2.2; + +#pragma include light.inc.frag + +int mipLevelCount(const in samplerCube cube) +{ + int baseSize = textureSize(cube, 0).x; + int nMips = int(log2(float(baseSize > 0 ? baseSize : 1))) + 1; + return nMips; +} + +float remapRoughness(const in float roughness) +{ + // As per page 14 of + // http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf + // we remap the roughness to give a more perceptually linear response + // of "bluriness" as a function of the roughness specified by the user. + // r = roughness^2 + const float maxSpecPower = 999999.0; + const float minRoughness = sqrt(2.0 / (maxSpecPower + 2.0)); + return max(roughness * roughness, minRoughness); +} + +float alphaToMipLevel(float alpha) +{ + float specPower = 2.0 / (alpha * alpha) - 2.0; + + // We use the mip level calculation from Lys' default power drop, which in + // turn is a slight modification of that used in Marmoset Toolbag. See + // https://docs.knaldtech.com/doku.php?id=specular_lys for details. + // For now we assume a max specular power of 999999 which gives + // maxGlossiness = 1. + const float k0 = 0.00098; + const float k1 = 0.9921; + float glossiness = (pow(2.0, -10.0 / sqrt(specPower)) - k0) / k1; + + // TODO: Optimize by doing this on CPU and set as + // uniform int envLight.specularMipLevels say (if present in shader). + // Lookup the number of mips in the specular envmap + int mipLevels = mipLevelCount(envLight.specular); + + // Offset of smallest miplevel we should use (corresponds to specular + // power of 1). I.e. in the 32x32 sized mip. + const float mipOffset = 5.0; + + // The final factor is really 1 - g / g_max but as mentioned above g_max + // is 1 by definition here so we can avoid the division. If we make the + // max specular power for the spec map configurable, this will need to + // be handled properly. + float mipLevel = (float(mipLevels) - 1.0 - mipOffset) * (1.0 - glossiness); + return mipLevel; +} + +float normalDistribution(const in vec3 n, const in vec3 h, const in float alpha) +{ + // Blinn-Phong approximation - see + // http://graphicrants.blogspot.co.uk/2013/08/specular-brdf-reference.html + float specPower = 2.0 / (alpha * alpha) - 2.0; + return (specPower + 2.0) / (2.0 * 3.14159) * pow(max(dot(n, h), 0.0), specPower); +} + +vec3 fresnelFactor(const in vec3 color, const in float cosineFactor) +{ + // Calculate the Fresnel effect value + vec3 f = color; + vec3 F = f + (1.0 - f) * pow(1.0 - cosineFactor, 5.0); + return clamp(F, f, vec3(1.0)); +} + +float geometricModel(const in float lDotN, + const in float vDotN, + const in vec3 h) +{ + // Implicit geometric model (equal to denominator in specular model). + // This currently assumes that there is no attenuation by geometric shadowing or + // masking according to the microfacet theory. + return lDotN * vDotN; +} + +vec3 specularModel(const in vec3 F0, + const in float sDotH, + const in float sDotN, + const in float vDotN, + const in vec3 n, + const in vec3 h) +{ + // Clamp sDotN and vDotN to small positive value to prevent the + // denominator in the reflection equation going to infinity. Balance this + // by using the clamped values in the geometric factor function to + // avoid ugly seams in the specular lighting. + float sDotNPrime = max(sDotN, 0.001); + float vDotNPrime = max(vDotN, 0.001); + + vec3 F = fresnelFactor(F0, sDotH); + float G = geometricModel(sDotNPrime, vDotNPrime, h); + + vec3 cSpec = F * G / (4.0 * sDotNPrime * vDotNPrime); + return clamp(cSpec, vec3(0.0), vec3(1.0)); +} + +vec3 pbrModel(const in int lightIndex, + const in vec3 wPosition, + const in vec3 wNormal, + const in vec3 wView, + const in vec3 baseColor, + const in float metalness, + const in float alpha, + const in float ambientOcclusion) +{ + // Calculate some useful quantities + vec3 n = wNormal; + vec3 s = vec3(0.0); + vec3 v = wView; + vec3 h = vec3(0.0); + + float vDotN = dot(v, n); + float sDotN = 0.0; + float sDotH = 0.0; + float att = 1.0; + + if (lights[lightIndex].type != TYPE_DIRECTIONAL) { + // Point and Spot lights + vec3 sUnnormalized = vec3(lights[lightIndex].position) - wPosition; + s = normalize(sUnnormalized); + + // Calculate the attenuation factor + sDotN = dot(s, n); + if (sDotN > 0.0) { + if (lights[lightIndex].constantAttenuation != 0.0 + || lights[lightIndex].linearAttenuation != 0.0 + || lights[lightIndex].quadraticAttenuation != 0.0) { + float dist = length(sUnnormalized); + att = 1.0 / (lights[lightIndex].constantAttenuation + + lights[lightIndex].linearAttenuation * dist + + lights[lightIndex].quadraticAttenuation * dist * dist); + } + + // The light direction is in world space already + if (lights[lightIndex].type == TYPE_SPOT) { + // Check if fragment is inside or outside of the spot light cone + if (degrees(acos(dot(-s, lights[lightIndex].direction))) > lights[lightIndex].cutOffAngle) + sDotN = 0.0; + } + } + } else { + // Directional lights + // The light direction is in world space already + s = normalize(-lights[lightIndex].direction); + sDotN = dot(s, n); + } + + h = normalize(s + v); + sDotH = dot(s, h); + + // Calculate diffuse component + vec3 diffuseColor = (1.0 - metalness) * baseColor * lights[lightIndex].color; + vec3 diffuse = diffuseColor * max(sDotN, 0.0) / 3.14159; + + // Calculate specular component + vec3 dielectricColor = vec3(0.04); + vec3 F0 = mix(dielectricColor, baseColor, metalness); + vec3 specularFactor = vec3(0.0); + if (sDotN > 0.0) { + specularFactor = specularModel(F0, sDotH, sDotN, vDotN, n, h); + specularFactor *= normalDistribution(n, h, alpha); + } + vec3 specularColor = lights[lightIndex].color; + vec3 specular = specularColor * specularFactor; + + // Blend between diffuse and specular to conserver energy + vec3 color = att * lights[lightIndex].intensity * (specular + diffuse * (vec3(1.0) - specular)); + + // Reduce by ambient occlusion amount + color *= ambientOcclusion; + + return color; +} + +vec3 pbrIblModel(const in vec3 wNormal, + const in vec3 wView, + const in vec3 baseColor, + const in float metalness, + const in float alpha, + const in float ambientOcclusion) +{ + // Calculate reflection direction of view vector about surface normal + // vector in world space. This is used in the fragment shader to sample + // from the environment textures for a light source. This is equivalent + // to the l vector for punctual light sources. Armed with this, calculate + // the usual factors needed + vec3 n = wNormal; + vec3 l = reflect(-wView, n); + vec3 v = wView; + vec3 h = normalize(l + v); + float vDotN = dot(v, n); + float lDotN = dot(l, n); + float lDotH = dot(l, h); + + // Calculate diffuse component + vec3 diffuseColor = (1.0 - metalness) * baseColor; + vec3 diffuse = diffuseColor * texture(envLight.irradiance, l).rgb; + + // Calculate specular component + vec3 dielectricColor = vec3(0.04); + vec3 F0 = mix(dielectricColor, baseColor, metalness); + vec3 specularFactor = specularModel(F0, lDotH, lDotN, vDotN, n, h); + + float lod = alphaToMipLevel(alpha); +//#define DEBUG_SPECULAR_LODS +#ifdef DEBUG_SPECULAR_LODS + if (lod > 7.0) + return vec3(1.0, 0.0, 0.0); + else if (lod > 6.0) + return vec3(1.0, 0.333, 0.0); + else if (lod > 5.0) + return vec3(1.0, 1.0, 0.0); + else if (lod > 4.0) + return vec3(0.666, 1.0, 0.0); + else if (lod > 3.0) + return vec3(0.0, 1.0, 0.666); + else if (lod > 2.0) + return vec3(0.0, 0.666, 1.0); + else if (lod > 1.0) + return vec3(0.0, 0.0, 1.0); + else if (lod > 0.0) + return vec3(1.0, 0.0, 1.0); +#endif + vec3 specularSkyColor = textureLod(envLight.specular, l, lod).rgb; + vec3 specular = specularSkyColor * specularFactor; + + // Blend between diffuse and specular to conserve energy + vec3 color = specular + diffuse * (vec3(1.0) - specularFactor); + + // Reduce by ambient occlusion amount + color *= ambientOcclusion; + + return color; +} + +vec3 toneMap(const in vec3 c) +{ + return c / (c + vec3(1.0)); +} + +vec3 gammaCorrect(const in vec3 color) +{ + return pow(color, vec3(1.0 / gamma)); +} + +vec4 metalRoughFunction(const in vec4 baseColor, + const in float metalness, + const in float roughness, + const in float ambientOcclusion, + const in vec3 worldPosition, + const in vec3 worldView, + const in vec3 worldNormal) +{ + vec3 cLinear = vec3(0.0); + + // Remap roughness for a perceptually more linear correspondence + float alpha = remapRoughness(roughness); + + for (int i = 0; i < envLightCount; ++i) { + cLinear += pbrIblModel(worldNormal, + worldView, + baseColor.rgb, + metalness, + alpha, + ambientOcclusion); + } + + for (int i = 0; i < lightCount; ++i) { + cLinear += pbrModel(i, + worldPosition, + worldNormal, + worldView, + baseColor.rgb, + metalness, + alpha, + ambientOcclusion); + } + + // Apply exposure correction + cLinear *= pow(2.0, exposure); + + // Apply simple (Reinhard) tonemap transform to get into LDR range [0, 1] + vec3 cToneMapped = toneMap(cLinear); + + // Apply gamma correction prior to display + vec3 cGamma = gammaCorrect(cToneMapped); + + return vec4(cGamma, 1.0); +} diff --git a/src/extras/shaders/gl3/morphphong.vert b/src/extras/shaders/gl3/morphphong.vert index c74fbdcff..7a8bdd097 100644 --- a/src/extras/shaders/gl3/morphphong.vert +++ b/src/extras/shaders/gl3/morphphong.vert @@ -27,7 +27,7 @@ void main() morphNormal = normalize(vertexNormal + vertexNormalTarget * abs(interpolator)); } - worldNormal = normalize( modelNormalMatrix * morphPos ); + worldNormal = normalize( modelNormalMatrix * morphNormal ); worldPosition = vec3( modelMatrix * vec4( morphPos, 1.0 ) ); gl_Position = modelViewProjection * vec4( morphPos, 1.0 ); diff --git a/src/extras/text/qtext2dentity.cpp b/src/extras/text/qtext2dentity.cpp index 10939a1e2..ae25e8ecc 100644 --- a/src/extras/text/qtext2dentity.cpp +++ b/src/extras/text/qtext2dentity.cpp @@ -92,10 +92,17 @@ void QText2DEntityPrivate::setScene(Qt3DCore::QScene *scene) // Unref old glyph cache if it exists if (m_scene != nullptr) { + // Ensure we don't keep reference to glyphs + // if we are changing the cache + if (m_glyphCache != nullptr) + clearCurrentGlyphRuns(); + m_glyphCache = nullptr; + QText2DEntityPrivate::CacheEntry &entry = QText2DEntityPrivate::m_glyphCacheInstances[m_scene]; --entry.count; if (entry.count == 0 && entry.glyphCache != nullptr) { + delete entry.glyphCache; entry.glyphCache = nullptr; } @@ -149,7 +156,6 @@ void QText2DEntityPrivate::setCurrentGlyphRuns(const QVector<QGlyphRun> &runs) // For each distinct texture, we need a separate DistanceFieldTextRenderer, // for which we need vertex and index data QHash<Qt3DRender::QAbstractTexture*, RenderData> renderData; - const float scale = computeActualScale(); // process glyph runs @@ -248,6 +254,13 @@ void QText2DEntityPrivate::setCurrentGlyphRuns(const QVector<QGlyphRun> &runs) m_currentGlyphRuns = runs; } +void QText2DEntityPrivate::clearCurrentGlyphRuns() +{ + for (int i = 0; i < m_currentGlyphRuns.size(); i++) + m_glyphCache->derefGlyphs(m_currentGlyphRuns[i]); + m_currentGlyphRuns.clear(); +} + void QText2DEntityPrivate::update() { if (m_glyphCache == nullptr) diff --git a/src/extras/text/qtext2dentity_p.h b/src/extras/text/qtext2dentity_p.h index 934e2087f..b98c62ce3 100644 --- a/src/extras/text/qtext2dentity_p.h +++ b/src/extras/text/qtext2dentity_p.h @@ -104,6 +104,7 @@ public: float computeActualScale() const; void setCurrentGlyphRuns(const QVector<QGlyphRun> &runs); + void clearCurrentGlyphRuns(); void update(); struct CacheEntry diff --git a/src/quick3d/imports/scene3d/scene3ditem.cpp b/src/quick3d/imports/scene3d/scene3ditem.cpp index 2f791b202..ddb25777c 100644 --- a/src/quick3d/imports/scene3d/scene3ditem.cpp +++ b/src/quick3d/imports/scene3d/scene3ditem.cpp @@ -372,9 +372,6 @@ QSGNode *Scene3DItem::updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNode m_renderer->setCleanerHelper(m_rendererCleaner); } - // The main thread is blocked, it is now time to sync data between the renderer and the item. - m_renderer->synchronize(); - Scene3DSGNode *fboNode = static_cast<Scene3DSGNode *>(node); if (fboNode == nullptr) { fboNode = new Scene3DSGNode(); diff --git a/src/quick3d/imports/scene3d/scene3drenderer.cpp b/src/quick3d/imports/scene3d/scene3drenderer.cpp index b3cac0dcd..b96fc516d 100644 --- a/src/quick3d/imports/scene3d/scene3drenderer.cpp +++ b/src/quick3d/imports/scene3d/scene3drenderer.cpp @@ -138,11 +138,13 @@ Scene3DRenderer::Scene3DRenderer(Scene3DItem *item, Qt3DCore::QAspectEngine *asp , m_lastMultisample(false) , m_needsShutdown(true) , m_blocking(false) + , m_forceRecreate(false) { Q_CHECK_PTR(m_item); Q_CHECK_PTR(m_item->window()); m_window = m_item->window(); + QObject::connect(m_item->window(), &QQuickWindow::afterSynchronizing, this, &Scene3DRenderer::synchronize, Qt::DirectConnection); QObject::connect(m_item->window(), &QQuickWindow::beforeRendering, this, &Scene3DRenderer::render, Qt::DirectConnection); QObject::connect(m_item->window(), &QQuickWindow::sceneGraphInvalidated, this, &Scene3DRenderer::onSceneGraphInvalidated, Qt::DirectConnection); // So that we can schedule the cleanup @@ -247,7 +249,30 @@ void Scene3DRenderer::onWindowChanged(QQuickWindow *w) void Scene3DRenderer::synchronize() { - m_multisample = m_item->multisample(); + if (m_item && m_window) { + m_multisample = m_item->multisample(); + + if (m_aspectEngine->rootEntity() != m_item->entity()) { + scheduleRootEntityChange(); + } + + const QSize boundingRectSize = m_item->boundingRect().size().toSize(); + const QSize currentSize = boundingRectSize * m_window->effectiveDevicePixelRatio(); + const bool sizeHasChanged = currentSize != m_lastSize; + const bool multisampleHasChanged = m_multisample != m_lastMultisample; + m_forceRecreate = sizeHasChanged || multisampleHasChanged; + + if (sizeHasChanged) { + static const QMetaMethod setItemAreaAndDevicePixelRatio = setItemAreaAndDevicePixelRatioMethod(); + setItemAreaAndDevicePixelRatio.invoke(m_item, Qt::QueuedConnection, Q_ARG(QSize, boundingRectSize), + Q_ARG(qreal, m_window->effectiveDevicePixelRatio())); + } + + // Store the current size as a comparison + // point for the next frame + m_lastSize = currentSize; + m_lastMultisample = m_multisample; + } } void Scene3DRenderer::setSGNode(Scene3DSGNode *node) @@ -261,51 +286,30 @@ void Scene3DRenderer::render() { QMutexLocker l(&m_windowMutex); // Lock to ensure the window doesn't change while we are rendering - if (!m_item || !m_window) + if (!m_window) return; - if (m_aspectEngine->rootEntity() != m_item->entity()) - scheduleRootEntityChange(); - ContextSaver saver; // The OpenGL state may be dirty from the previous QtQuick nodes, so reset // it here to give Qt3D the clean state it expects m_window->resetOpenGLState(); - const QSize boundingRectSize = m_item->boundingRect().size().toSize(); - const QSize currentSize = boundingRectSize * m_window->effectiveDevicePixelRatio(); - const bool sizeHasChanged = currentSize != m_lastSize; - const bool multisampleHasChanged = m_multisample != m_lastMultisample; - const bool forceRecreate = sizeHasChanged || multisampleHasChanged; - - if (sizeHasChanged) { - // We are in the QSGRenderThread (doing a direct call would result in a race) - static const QMetaMethod setItemAreaAndDevicePixelRatio = setItemAreaAndDevicePixelRatioMethod(); - setItemAreaAndDevicePixelRatio.invoke(m_item, Qt::QueuedConnection, Q_ARG(QSize, boundingRectSize), - Q_ARG(qreal, m_window->effectiveDevicePixelRatio())); - } - // Rebuild FBO and textures if never created or a resize has occurred - if ((m_multisampledFBO.isNull() || forceRecreate) && m_multisample) { - m_multisampledFBO.reset(createMultisampledFramebufferObject(currentSize)); + if ((m_multisampledFBO.isNull() || m_forceRecreate) && m_multisample) { + m_multisampledFBO.reset(createMultisampledFramebufferObject(m_lastSize)); if (m_multisampledFBO->format().samples() == 0 || !QOpenGLFramebufferObject::hasOpenGLFramebufferBlit()) { m_multisample = false; m_multisampledFBO.reset(nullptr); } } - if (m_finalFBO.isNull() || forceRecreate) { - m_finalFBO.reset(createFramebufferObject(currentSize)); + if (m_finalFBO.isNull() || m_forceRecreate) { + m_finalFBO.reset(createFramebufferObject(m_lastSize)); m_texture.reset(m_window->createTextureFromId(m_finalFBO->texture(), m_finalFBO->size(), QQuickWindow::TextureHasAlphaChannel)); m_node->setTexture(m_texture.data()); } - // Store the current size as a comparison - // point for the next frame - m_lastSize = currentSize; - m_lastMultisample = m_multisample; - // Bind FBO if (m_multisample) //Only try to use MSAA when available m_multisampledFBO->bind(); diff --git a/src/quick3d/imports/scene3d/scene3drenderer_p.h b/src/quick3d/imports/scene3d/scene3drenderer_p.h index eb2b930ef..e28ecbe6e 100644 --- a/src/quick3d/imports/scene3d/scene3drenderer_p.h +++ b/src/quick3d/imports/scene3d/scene3drenderer_p.h @@ -110,6 +110,7 @@ private: bool m_lastMultisample; bool m_needsShutdown; bool m_blocking; + bool m_forceRecreate; friend class Scene3DCleaner; }; diff --git a/src/render/materialsystem/prototypes/default.json b/src/render/materialsystem/prototypes/default.json index 535f144d7..63c39164c 100644 --- a/src/render/materialsystem/prototypes/default.json +++ b/src/render/materialsystem/prototypes/default.json @@ -87,6 +87,15 @@ }, { "format": { + "api": "OpenGLES", + "major": 3, + "minor": 0 + }, + "substitution": "highp vec4 $color = texture($name, $coord);", + "headerSnippets": [ "uniform sampler2D $name;" ] + }, + { + "format": { "api": "OpenGLCoreProfile", "major": 3, "minor": 0 @@ -111,6 +120,15 @@ }, { "format": { + "api": "OpenGLES", + "major": 3, + "minor": 0 + }, + "substitution": "fragColor = $fragColor;", + "headerSnippets": [ "out highp vec4 fragColor;" ] + }, + { + "format": { "api": "OpenGLCoreProfile", "major": 3, "minor": 0 @@ -445,6 +463,15 @@ "rules": [ { "format": { + "api": "OpenGLES", + "major": 3, + "minor": 0 + }, + "substitution": "highp vec4 $outputColor = metalRoughFunction($baseColor, $metalness, $roughness, $ambientOcclusion, $worldPosition, $worldView, $worldNormal);", + "headerSnippets": [ "#pragma include :/shaders/es3/metalrough.inc.frag" ] + }, + { + "format": { "api": "OpenGLCoreProfile", "major": 3, "minor": 1 diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelperes3.cpp b/src/render/renderers/opengl/graphicshelpers/graphicshelperes3.cpp index 29ecf9308..34c1e7448 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelperes3.cpp +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelperes3.cpp @@ -234,6 +234,14 @@ void GraphicsHelperES3::vertexAttributePointer(GLenum shaderDataType, } } +void GraphicsHelperES3::drawArraysInstanced(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances) +{ + m_extraFuncs->glDrawArraysInstanced(primitiveType, + first, + count, + instances); +} + void GraphicsHelperES3::readBuffer(GLenum mode) { m_extraFuncs->glReadBuffer(mode); diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_2.cpp b/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_2.cpp index 9dce08e4f..56da249f2 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_2.cpp +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_2.cpp @@ -117,6 +117,19 @@ void GraphicsHelperES3_2::setVerticesPerPatch(GLint verticesPerPatch) m_extraFuncs->glPatchParameteri(GL_PATCH_VERTICES, verticesPerPatch); } +void GraphicsHelperES3_2::drawElementsInstancedBaseVertexBaseInstance(GLenum primitiveType, GLsizei primitiveCount, GLint indexType, void *indices, GLsizei instances, GLint baseVertex, GLint baseInstance) +{ + if (baseInstance != 0) + qWarning() << "glDrawElementsInstancedBaseVertexBaseInstance is not supported with OpenGL ES 2"; + + m_extraFuncs->glDrawElementsInstancedBaseVertex(primitiveType, + primitiveCount, + indexType, + indices, + instances, + baseVertex); +} + } // namespace Render } // namespace Qt3DRender diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_2_p.h b/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_2_p.h index ed71b1e3e..259864379 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_2_p.h +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_2_p.h @@ -70,6 +70,7 @@ public: void bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment) override; bool frameBufferNeedsRenderBuffer(const Attachment &attachment) override; void setVerticesPerPatch(GLint verticesPerPatch) override; + void drawElementsInstancedBaseVertexBaseInstance(GLenum primitiveType, GLsizei primitiveCount, GLint indexType, void *indices, GLsizei instances, GLint baseVertex = 0, GLint baseInstance = 0) override; }; } // namespace Render diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_p.h b/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_p.h index 142b7cadd..d4467cf7f 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_p.h +++ b/src/render/renderers/opengl/graphicshelpers/graphicshelperes3_p.h @@ -74,6 +74,7 @@ public: void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) override; void buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer) override; void drawBuffers(GLsizei n, const int *bufs) override; + void drawArraysInstanced(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances) override; void drawElementsInstancedBaseVertexBaseInstance(GLenum primitiveType, GLsizei primitiveCount, GLint indexType, void *indices, GLsizei instances, GLint baseVertex = 0, GLint baseInstance = 0) override; void readBuffer(GLenum mode) override; void drawBuffer(GLenum mode) override; diff --git a/src/render/renderers/opengl/renderer/openglvertexarrayobject.cpp b/src/render/renderers/opengl/renderer/openglvertexarrayobject.cpp index 0c4fd8c9d..f5d0a64f5 100644 --- a/src/render/renderers/opengl/renderer/openglvertexarrayobject.cpp +++ b/src/render/renderers/opengl/renderer/openglvertexarrayobject.cpp @@ -108,6 +108,11 @@ void OpenGLVertexArrayObject::create(SubmissionContext *ctx, const VAOIdentifier m_owners = key; } +VAOIdentifier OpenGLVertexArrayObject::key() const +{ + return m_owners; +} + // called from Render thread void OpenGLVertexArrayObject::destroy() { diff --git a/src/render/renderers/opengl/renderer/openglvertexarrayobject_p.h b/src/render/renderers/opengl/renderer/openglvertexarrayobject_p.h index eee837221..4896df9bf 100644 --- a/src/render/renderers/opengl/renderer/openglvertexarrayobject_p.h +++ b/src/render/renderers/opengl/renderer/openglvertexarrayobject_p.h @@ -73,6 +73,7 @@ public: void release(); void create(SubmissionContext *ctx, const VAOIdentifier &key); + VAOIdentifier key() const; void destroy(); void cleanup(); diff --git a/src/render/renderers/opengl/renderer/renderer.cpp b/src/render/renderers/opengl/renderer/renderer.cpp index c9ba6409d..5d12729f2 100644 --- a/src/render/renderers/opengl/renderer/renderer.cpp +++ b/src/render/renderers/opengl/renderer/renderer.cpp @@ -2140,7 +2140,8 @@ void Renderer::cleanGraphicsResources() OpenGLVertexArrayObject *vao = m_nodesManager->vaoManager()->data(vaoHandle); if (vao) { vao->destroy(); - m_nodesManager->vaoManager()->release(vaoHandle); + // We remove VAO from manager using its VAOIdentifier + m_nodesManager->vaoManager()->releaseResource(vao->key()); } } } diff --git a/src/render/renderers/opengl/textures/gltexture.cpp b/src/render/renderers/opengl/textures/gltexture.cpp index b61d06a80..e98f3965d 100644 --- a/src/render/renderers/opengl/textures/gltexture.cpp +++ b/src/render/renderers/opengl/textures/gltexture.cpp @@ -212,6 +212,10 @@ GLTexture::TextureUpdateInfo GLTexture::createOrUpdateGLTexture() delete m_gl; m_gl = nullptr; textureInfo.wasUpdated = true; + // If we are destroyed because of some property change but still our content data + // make sure we are marked for upload + if (m_textureData || !m_imageData.empty()) + needUpload = true; } |