diff options
author | Sean Harmer <sean.harmer@kdab.com> | 2014-09-21 12:17:21 +0100 |
---|---|---|
committer | Sean Harmer <sean.harmer@kdab.com> | 2014-09-21 16:59:33 +0200 |
commit | 6d9febedb5b734541c037521c39f705c0fdbbc95 (patch) | |
tree | ad2a7ee57ed73d21c66a9e38fdec5cbcc1d7a9be | |
parent | bb7d6c2b10b291a93b04dc9a1753a6eec29b68c7 (diff) |
Add an example to exercise tessellation shader support
Also extended Renderer and friends to support setting the number
of vertices per patch with glPathParameteri(GL_PATCH_VERTICES, n).
To support this QMeshData now also stores the vertices per patch.
This demonstrates how to tessellate using quad tessellation mode.
Follow-up commits will add objects to show triangle and isoline
modes.
Change-Id: I68afb31815db430d0b4d8d9cc525efcfb9a216fc
Reviewed-by: Paul Lemire <paul.lemire@kdab.com>
36 files changed, 1369 insertions, 11 deletions
diff --git a/examples/examples.pro b/examples/examples.pro index c6abffcc4..6a1703e48 100644 --- a/examples/examples.pro +++ b/examples/examples.pro @@ -47,6 +47,10 @@ src_wireframe.subdir = $$PWD/wireframe src_wireframe.target = sub-wireframe src_wireframe.depends = src_exampleresources +src_tessellationmodes.subdir = $$PWD/tessellation-modes +src_tessellationmodes.target = sub-tessellationmodes +src_tessellationmodes.depends = src_exampleresources + SUBDIRS += \ src_exampleresources \ src_simpleqml \ @@ -58,7 +62,8 @@ SUBDIRS += \ src_toruscpp \ src_bigmodelqml \ src_deferredrenderer \ - src_wireframe + src_wireframe \ + src_tessellationmodes # TODO Port the old examples to new APIs #SUBDIRS += qt3d diff --git a/examples/tessellation-modes/BasicCamera.qml b/examples/tessellation-modes/BasicCamera.qml new file mode 100644 index 000000000..2f9f8b7b1 --- /dev/null +++ b/examples/tessellation-modes/BasicCamera.qml @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt3D 2.0 +import Qt3D.Render 2.0 + +// For Qt.vector3d() and friends. For some reason this is provided by +// QQuickValueTypeProvider in QtQuick rather than the default value +// type provider in QtQml. So we will need to replicate this in Qt3D +// for the types that we wish to support. Otherwise we'll have to import +// QtQuick 2.1 all over the place. +import QtQuick 2.1 as QQ2 + +Camera { + id: mainCamera + objectName: "mainCamera" + + property alias position: lookAtTransform.position + property alias viewCenter: lookAtTransform.viewCenter + property alias upVector: lookAtTransform.upVector + + lens: CameraLens { + projectionType: CameraLens.PerspectiveProjection + fieldOfView: 22.5 + aspectRatio: _window.width / _window.height + onAspectRatioChanged: console.log( "aspectRatio = " + aspectRatio ) + nearPlane: 0.01 + farPlane: 1000.0 + } + + transform: Transform { + LookAt { + id: lookAtTransform + viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 ) + upVector: Qt.vector3d( 0.0, 1.0, 0.0 ) + } + } +} diff --git a/examples/tessellation-modes/ForwardRenderer.qml b/examples/tessellation-modes/ForwardRenderer.qml new file mode 100644 index 000000000..7a100bf4d --- /dev/null +++ b/examples/tessellation-modes/ForwardRenderer.qml @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt3D 2.0 +import Qt3D.Render 2.0 + +TechniqueFilter { + id: root + objectName : "techniqueFilter" + + // Expose camera to allow user to choose which camera to use for rendering + property alias camera: cameraSelector.camera + + // Select the forward rendering Technique of any used Effect + criteria: [ Criterion { name: "renderingStyle"; value: "forward" } ] + + // Use the whole viewport + Viewport { + id: viewport + objectName : "viewport" + rect: Qt.rect(0.0, 0.0, 1.0, 1.0) + + // Use the specified camera + CameraSelector { + id : cameraSelector + objectName : "cameraSelector" + ClearBuffer { + buffers : ClearBuffer.ColorDepthBuffer + } + } + } +} diff --git a/examples/tessellation-modes/TessellatedQuad.qml b/examples/tessellation-modes/TessellatedQuad.qml new file mode 100644 index 000000000..8842a4539 --- /dev/null +++ b/examples/tessellation-modes/TessellatedQuad.qml @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt3D 2.0 +import Qt3D.Render 2.0 +import Qt3D.Examples 1.0 + +// For Qt.vector3d() and friends. For some reason this is provided by +// QQuickValueTypeProvider in QtQuick rather than the default value +// type provider in QtQml. So we will need to replicate this in Qt3D +// for the types that we wish to support. Otherwise we'll have to import +// QtQuick 2.1 all over the place. +import QtQuick 2.1 as QQ2 + +Entity { + id: root + + property real x: 0.0 + property real y: 0.0 + property real z: 0.0 + property real scale: 1.0 + property real theta: 0.0 + property Material material + + components: [ transform, mesh, root.material ] + + Transform { + id: transform + Translate { dx: root.x; dy: root.y; dz: root.z } + Scale { scale: root.scale } + Rotate{ angle: root.theta; axis: Qt.vector3d(0.0, 1.0, 0.0) } + } + + TessellatedQuadMesh { + id: mesh + } +} diff --git a/examples/tessellation-modes/TessellatedWireframeEffect.qml b/examples/tessellation-modes/TessellatedWireframeEffect.qml new file mode 100644 index 000000000..0449563d1 --- /dev/null +++ b/examples/tessellation-modes/TessellatedWireframeEffect.qml @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt3D 2.0 +import Qt3D.Render 2.0 + +// For Qt.vector3d() and friends. For some reason this is provided by +// QQuickValueTypeProvider in QtQuick rather than the default value +// type provider in QtQml. So we will need to replicate this in Qt3D +// for the types that we wish to support. Otherwise we'll have to import +// QtQuick 2.1 all over the place. +import QtQuick 2.1 + +Effect { + id: root + + // It's expected that users of this will specify the tessellation control and evaluation + // shaders and if necessary suitable replacements for the other stages + property alias vertexShaderSourceFile: program.vertexShaderSourceFile + property alias tessellationControlShaderSourceFile: program.tessellationControlShaderSourceFile + property alias tessellationEvaluationShaderSourceFile: program.tessellationEvaluationShaderSourceFile + property alias geometryShaderSourceFile: program.geometryShaderSourceFile + property alias fragmentShaderSourceFile: program.fragmentShaderSourceFile + + parameters: [ + Parameter { name: "ambient"; value: Qt.vector3d( 0.1, 0.1, 0.1 ) }, + Parameter { name: "diffuse"; value: Qt.vector3d( 0.7, 0.7, 0.7 ) }, + Parameter { name: "specular"; value: Qt.vector3d( 0.95, 0.95, 0.95 ) }, + Parameter { name: "shininess"; value: 150.0 } + ] + + techniques: [ + Technique { + openGLFilter { + api: OpenGLFilter.Desktop + profile: OpenGLFilter.Core + majorVersion: 4 + minorVersion: 0 + } + + criteria: [ Criterion { name: "renderingStyle"; value: "forward" } ] + + parameters: [ + Parameter { name: "light.position"; value: Qt.vector4d(0.0, 0.0, 0.0, 1.0) }, + Parameter { name: "light.intensity"; value: Qt.vector3d(1.0, 1.0, 1.0) }, + Parameter { name: "line.width"; value: 0.8 }, + Parameter { name: "line.color"; value: Qt.vector4d(1.0, 1.0, 1.0, 1.0) } + ] + + renderPasses: [ + RenderPass { + name: "lighting" + + bindings: [ + ParameterMapper { parameterName: "ambient"; shaderVariableName: "ka"; bindingType: ParameterMapper.Uniform }, + ParameterMapper { parameterName: "diffuse"; shaderVariableName: "kd"; bindingType: ParameterMapper.Uniform }, + ParameterMapper { parameterName: "specular"; shaderVariableName: "ks"; bindingType: ParameterMapper.Uniform }, + + // TODO: Support uniform arrays. We want to be able to do (or something similar) and map vectors or lists of values + // through to the uniforms + //ParameterMapper { parameterName: "innerTessLevel"; shaderVariableName: "inner"; bindingType: ParameterMapper.Uniform } + //ParameterMapper { parameterName: "outerTessLevel"; shaderVariableName: "outer"; bindingType: ParameterMapper.Uniform } + ParameterMapper { parameterName: "innerTessLevel0"; shaderVariableName: "inner[0]"; bindingType: ParameterMapper.Uniform }, + ParameterMapper { parameterName: "innerTessLevel1"; shaderVariableName: "inner[1]"; bindingType: ParameterMapper.Uniform }, + ParameterMapper { parameterName: "outerTessLevel0"; shaderVariableName: "outer[0]"; bindingType: ParameterMapper.Uniform }, + ParameterMapper { parameterName: "outerTessLevel1"; shaderVariableName: "outer[1]"; bindingType: ParameterMapper.Uniform }, + ParameterMapper { parameterName: "outerTessLevel2"; shaderVariableName: "outer[2]"; bindingType: ParameterMapper.Uniform }, + ParameterMapper { parameterName: "outerTessLevel3"; shaderVariableName: "outer[3]"; bindingType: ParameterMapper.Uniform } + ] + + shaderProgram: ShaderProgram { + id: program + vertexShaderSourceFile: ":/shaders/passthru.vert" + geometryShaderSourceFile: ":/shaders/robustwireframe.geom" + fragmentShaderSourceFile: ":/shaders/phongwireframe.frag" + } + } + ] + } + ] +} diff --git a/examples/tessellation-modes/TessellatedWireframeMaterial.qml b/examples/tessellation-modes/TessellatedWireframeMaterial.qml new file mode 100644 index 000000000..edd24795c --- /dev/null +++ b/examples/tessellation-modes/TessellatedWireframeMaterial.qml @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt3D 2.0 +import Qt3D.Render 2.0 + +// For Qt.vector3d() and friends. For some reason this is provided by +// QQuickValueTypeProvider in QtQuick rather than the default value +// type provider in QtQml. So we will need to replicate this in Qt3D +// for the types that we wish to support. Otherwise we'll have to import +// QtQuick 2.1 all over the place. +import QtQuick 2.1 as QQ2 + +Material { + id: root + + property color ambient: Qt.rgba( 0.05, 0.05, 0.05, 1.0 ) + property color diffuse: Qt.rgba( 0.7, 0.7, 0.7, 1.0 ) + property color specular: Qt.rgba( 0.95, 0.95, 0.95, 1.0 ) + property real shininess: 150.0 + property real lineWidth: 1.0 + property color lineColor: Qt.rgba( 1.0, 1.0, 1.0, 1.0 ) + property real innerTessLevel0: 1.0 + property real innerTessLevel1: 1.0 + property real outerTessLevel0: 1.0 + property real outerTessLevel1: 1.0 + property real outerTessLevel2: 1.0 + property real outerTessLevel3: 1.0 + + parameters: [ + Parameter { name: "ambient"; value: Qt.vector3d(root.ambient.r, root.ambient.g, root.ambient.b) }, + Parameter { name: "diffuse"; value: Qt.vector3d(root.diffuse.r, root.diffuse.g, root.diffuse.b) }, + Parameter { name: "specular"; value: Qt.vector3d(root.specular.r, root.specular.g, root.specular.b) }, + Parameter { name: "shininess"; value: root.shininess }, + Parameter { name: "line.width"; value: root.lineWidth }, + Parameter { name: "line.color"; value: root.lineColor }, + Parameter { name: "innerTessLevel0"; value: root.innerTessLevel0 }, + Parameter { name: "innerTessLevel1"; value: root.innerTessLevel1 }, + Parameter { name: "outerTessLevel0"; value: root.outerTessLevel0 }, + Parameter { name: "outerTessLevel1"; value: root.outerTessLevel1 }, + Parameter { name: "outerTessLevel2"; value: root.outerTessLevel2 }, + Parameter { name: "outerTessLevel3"; value: root.outerTessLevel3 } + ] +} diff --git a/examples/tessellation-modes/main.cpp b/examples/tessellation-modes/main.cpp new file mode 100644 index 000000000..c543bdbf9 --- /dev/null +++ b/examples/tessellation-modes/main.cpp @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "tessellatedquadmesh.h" + +#include <Qt3DQuick/quickwindow.h> +#include <Qt3DRenderer/rendereraspect.h> + +#include <exampleresources.h> + +#include <QGuiApplication> +#include <QtQml> + +int main(int argc, char* argv[]) +{ + QGuiApplication app(argc, argv); + + initializeAssetResources("../exampleresources/example-assets.qrb"); + + Qt3D::Quick::QuickWindow view; + view.registerAspect(new Qt3D::RendererAspect()); + + // Register our custom types + qmlRegisterType<TessellatedQuadMesh>("Qt3D.Examples", 1, 0, "TessellatedQuadMesh"); + + // Expose the window as a context property so we can set the aspect ratio + view.engine()->rootContext()->setContextProperty("_window", &view); + + // There should be some synchronising mechanism to make sure + // the source is set after all aspects have been completely initialized + // Otherwise we might encounter cases where an Aspect's QML elements have + // not yet been registered + view.setSource(QUrl("qrc:/main.qml")); + view.show(); + + return app.exec(); +} diff --git a/examples/tessellation-modes/main.qml b/examples/tessellation-modes/main.qml new file mode 100644 index 000000000..5ff86361e --- /dev/null +++ b/examples/tessellation-modes/main.qml @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt3D 2.0 +import Qt3D.Render 2.0 + +// For Qt.vector3d() and friends. For some reason this is provided by +// QQuickValueTypeProvider in QtQuick rather than the default value +// type provider in QtQml. So we will need to replicate this in Qt3D +// for the types that we wish to support. Otherwise we'll have to import +// QtQuick 2.1 all over the place. +import QtQuick 2.1 as QQ2 + +Entity { + id: root + objectName: "root" + + // Use the renderer configuration specified in ForwardRenderer.qml + // and render from the mainCamera + components: [ + FrameGraph { + activeFrameGraph: ForwardRenderer { + id: renderer + camera: mainCamera + } + } + ] + + BasicCamera { + id: mainCamera + position: Qt.vector3d( 0.0, 0.0, 10.0 ) + } + + Configuration { + controlledCamera: mainCamera + } + + TessellatedWireframeMaterial { + id: quadMaterial + ambient: Qt.rgba( 0.2, 0.0, 0.0, 1.0 ) + diffuse: Qt.rgba( 0.8, 0.0, 0.0, 1.0 ) + + innerTessLevel0: 1.0 + innerTessLevel1: 1.0 + outerTessLevel0: 1.0 + outerTessLevel1: 1.0 + outerTessLevel2: 1.0 + outerTessLevel3: 1.0 + + effect: TessellatedWireframeEffect { + tessellationControlShaderSourceFile: ":/shaders/quads.tcs" + tessellationEvaluationShaderSourceFile: ":/shaders/quads.tes" + } + + QQ2.SequentialAnimation { + loops: QQ2.Animation.Infinite + running: true + + QQ2.NumberAnimation { + target: quadMaterial; + properties: "innerTessLevel0,innerTessLevel1,outerTessLevel0,outerTessLevel1,outerTessLevel2,outerTessLevel3"; + duration: 1000; + from: 1.0 + to: 20.0 + } + + QQ2.NumberAnimation { + target: quadMaterial; + properties: "innerTessLevel0,innerTessLevel1,outerTessLevel0,outerTessLevel1,outerTessLevel2,outerTessLevel3"; + duration: 1000; + from: 20.0 + to: 1.0 + } + } + } + + TessellatedQuad { + id: quad + material: quadMaterial + } + + // TODO: Add examples for triangle and isoline tessellation modes +} diff --git a/examples/tessellation-modes/shaders/flat.frag b/examples/tessellation-modes/shaders/flat.frag new file mode 100644 index 000000000..6e596d4d6 --- /dev/null +++ b/examples/tessellation-modes/shaders/flat.frag @@ -0,0 +1,12 @@ +#version 400 core + +in Vertex { + vec3 color; +} fs_in; + +out vec4 fragColor; + +void main() +{ + fragColor = vec4( fs_in.color, 1.0 ); +} diff --git a/examples/tessellation-modes/shaders/isolines.tcs b/examples/tessellation-modes/shaders/isolines.tcs new file mode 100644 index 000000000..624af51cc --- /dev/null +++ b/examples/tessellation-modes/shaders/isolines.tcs @@ -0,0 +1,15 @@ +#version 400 core + +layout( vertices = 4 ) out; + +uniform float outer[4] = float[]( 1.0, 1.0, 1.0, 1.0 ); + +void main() +{ + // Pass along the vertex position unmodified + gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position; + + // Set the tessellation levels + gl_TessLevelOuter[0] = outer[0]; // number of isolines + gl_TessLevelOuter[1] = outer[1]; // divisions along isoline +} diff --git a/examples/tessellation-modes/shaders/isolines.tes b/examples/tessellation-modes/shaders/isolines.tes new file mode 100644 index 000000000..f6b984bc8 --- /dev/null +++ b/examples/tessellation-modes/shaders/isolines.tes @@ -0,0 +1,74 @@ +#version 400 core + +layout( isolines, fractional_even_spacing, ccw ) in; + +out Vertex { + vec3 color; +} te_out; + +uniform mat4 modelViewMatrix; +uniform mat3 normalMatrix; +uniform mat4 projectionMatrix; +uniform mat4 mvp; + +// Calculate RGB triplet from HSV +vec3 hsvToRGB( float h, float s, float v ) +{ + if ( s <= 0.0 ) + return vec3( v ); + + h = h * 6.0; + float c = v * s; + float x = ( 1.0 - abs( ( mod( h, 2 ) - 1 ) ) ) * c; + float m = v - c; + float r = 0.0; + float g = 0.0; + float b = 0.0; + + if ( h < 1.0 ) { r = c; g = x; b = 0.0;} + else if ( h < 2.0 ) { r = x; g = c; b = 0.0; } + else if ( h < 3.0 ) { r = 0.0; g = c; b = x; } + else if ( h < 4.0 ) { r = 0.0; g = x; b = c; } + else if ( h < 5.0 ) { r = x; g = 0.0; b = c; } + else { r = c; g = 0.0; b = x; } + + return vec3( r + m, g + m, b + m ); +} + +void main() +{ + float u = gl_TessCoord.x; + float v = gl_TessCoord.y; + + vec4 a = gl_in[0].gl_Position; + vec4 b = gl_in[1].gl_Position; + vec4 c = gl_in[2].gl_Position; + vec4 d = gl_in[3].gl_Position; + + // Use the (u,v) parametric coords to calculate the vertex. + // u is the position along an isoline + // v is isoline number + + // Let's make a sinusoidal curve as a function of u that varies + // in the v direction which we will define as orthogonal to u + + // Interpolate in u along top and bottom edges of the patch + vec4 q0 = mix( a, b, u ); + vec4 q1 = mix( d, c, u ); + + // Interpolate in v between the above positions. This gives the + // nominal position for our vertex + vec4 p = mix( q0, q1, v ); + + // Find "vertical" direction + vec4 vBasis = normalize( q1 - q0 ); + + // Offset vertex in this direction using sinusoid + vec4 pos = p + 0.2 * vBasis * sin( 20.0 * u ); + + // Use a hue value based on v + te_out.color = hsvToRGB( v, 1.0, 1.0 ); + + // Transform to clip-space + gl_Position = mvp * pos; +} diff --git a/examples/tessellation-modes/shaders/passthru.vert b/examples/tessellation-modes/shaders/passthru.vert new file mode 100644 index 000000000..71875a55f --- /dev/null +++ b/examples/tessellation-modes/shaders/passthru.vert @@ -0,0 +1,10 @@ +#version 400 core + +in vec3 vertexPosition; + +void main() +{ + // We do the transformations later in the + // tessellation evaluation shader + gl_Position = vec4( vertexPosition, 1.0 ); +} diff --git a/examples/tessellation-modes/shaders/phongwireframe.frag b/examples/tessellation-modes/shaders/phongwireframe.frag new file mode 100644 index 000000000..4fd62007d --- /dev/null +++ b/examples/tessellation-modes/shaders/phongwireframe.frag @@ -0,0 +1,108 @@ +#version 400 core + +uniform struct LightInfo { + vec4 position; + vec3 intensity; +} light; + +uniform struct LineInfo { + float width; + vec4 color; +} line; + +uniform vec3 ka; // Ambient reflectivity +uniform vec3 kd; // Diffuse reflectivity +uniform vec3 ks; // Specular reflectivity +uniform float shininess; // Specular shininess factor + +in WireframeVertex { + vec3 position; + vec3 normal; + noperspective vec4 edgeA; + noperspective vec4 edgeB; + flat int configuration; +} fs_in; + +out vec4 fragColor; + +vec3 adsModel( const in vec3 pos, const in vec3 n ) +{ + // Calculate the vector from the light to the fragment + vec3 s = normalize( vec3( light.position ) - pos ); + + // Calculate the vector from the fragment to the eye position (the + // origin since this is in "eye" or "camera" space + vec3 v = normalize( -pos ); + + // Refleft the light beam using the normal at this fragment + vec3 r = reflect( -s, n ); + + // Calculate the diffus component + vec3 diffuse = vec3( max( dot( s, n ), 0.0 ) ); + + // Calculate the specular component + vec3 specular = vec3( pow( max( dot( r, v ), 0.0 ), shininess ) ); + + // Combine the ambient, diffuse and specular contributions + return light.intensity * ( ka + kd * diffuse + ks * specular ); +} + +vec4 shadeLine( const in vec4 color ) +{ + // Find the smallest distance between the fragment and a triangle edge + float d; + if ( fs_in.configuration == 0 ) + { + // Common configuration + d = min( fs_in.edgeA.x, fs_in.edgeA.y ); + d = min( d, fs_in.edgeA.z ); + } + else + { + // Handle configuration where screen space projection breaks down + // Compute and compare the squared distances + vec2 AF = gl_FragCoord.xy - fs_in.edgeA.xy; + float sqAF = dot( AF, AF ); + float AFcosA = dot( AF, fs_in.edgeA.zw ); + d = abs( sqAF - AFcosA * AFcosA ); + + vec2 BF = gl_FragCoord.xy - fs_in.edgeB.xy; + float sqBF = dot( BF, BF ); + float BFcosB = dot( BF, fs_in.edgeB.zw ); + d = min( d, abs( sqBF - BFcosB * BFcosB ) ); + + // Only need to care about the 3rd edge for some configurations. + if ( fs_in.configuration == 1 || fs_in.configuration == 2 || fs_in.configuration == 4 ) + { + float AFcosA0 = dot( AF, normalize( fs_in.edgeB.xy - fs_in.edgeA.xy ) ); + d = min( d, abs( sqAF - AFcosA0 * AFcosA0 ) ); + } + + d = sqrt( d ); + } + + // Blend between line color and phong color + float mixVal; + if ( d < line.width - 1.0 ) + { + mixVal = 1.0; + } + else if ( d > line.width + 1.0 ) + { + mixVal = 0.0; + } + else + { + float x = d - ( line.width - 1.0 ); + mixVal = exp2( -2.0 * ( x * x ) ); + } + + return mix( color, line.color, mixVal ); +} + +void main() +{ + // Calculate the color from the phong model + vec4 color = vec4( adsModel( fs_in.position, normalize( fs_in.normal ) ), 1.0 ); + fragColor = shadeLine( color ); +} diff --git a/examples/tessellation-modes/shaders/quads.tcs b/examples/tessellation-modes/shaders/quads.tcs new file mode 100644 index 000000000..367195522 --- /dev/null +++ b/examples/tessellation-modes/shaders/quads.tcs @@ -0,0 +1,21 @@ +#version 400 core + +layout( vertices = 4 ) out; + +uniform float inner[2] = float[]( 10.0, 10.0 ); +uniform float outer[4] = float[]( 1.0, 1.0, 1.0, 1.0 ); + +void main() +{ + // Pass along the vertex position unmodified + gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position; + + // Set the tessellation levels from the uniforms + gl_TessLevelOuter[0] = outer[0]; + gl_TessLevelOuter[1] = outer[1]; + gl_TessLevelOuter[2] = outer[2]; + gl_TessLevelOuter[3] = outer[3]; + + gl_TessLevelInner[0] = inner[0]; + gl_TessLevelInner[1] = inner[1]; +} diff --git a/examples/tessellation-modes/shaders/quads.tes b/examples/tessellation-modes/shaders/quads.tes new file mode 100644 index 000000000..a3fd48441 --- /dev/null +++ b/examples/tessellation-modes/shaders/quads.tes @@ -0,0 +1,40 @@ +#version 400 core + +layout( quads, fractional_even_spacing, ccw ) in; + +out EyeSpaceVertex { + vec3 position; + vec3 normal; +} te_out; + +uniform mat4 modelView; +uniform mat3 modelViewNormal; +uniform mat4 projectionMatrix; +uniform mat4 mvp; + +void main() +{ + float u = gl_TessCoord.x; + float v = gl_TessCoord.y; + + vec4 p00 = gl_in[0].gl_Position; + vec4 p10 = gl_in[1].gl_Position; + vec4 p11 = gl_in[2].gl_Position; + vec4 p01 = gl_in[3].gl_Position; + + // Linearly interpolate to the vertex position using the + // (u,v) barycentric coords + vec4 pos = p00 * ( 1.0 - u ) * ( 1.0 - v ) + + p10 * u * ( 1.0 - v ) + + p01 * v * ( 1.0 - u ) + + p11 * u * v; + + // Transform to eye space (for lighting calcs) + te_out.position = vec3( modelView * pos ); + + // Assume normal points along z + te_out.normal = normalize( modelViewNormal * vec3( 0.0, 0.0, 1.0 ) ); + + // Transform to clip-space + gl_Position = mvp * pos; +} diff --git a/examples/tessellation-modes/shaders/robustwireframe.geom b/examples/tessellation-modes/shaders/robustwireframe.geom new file mode 100644 index 000000000..02eaaf398 --- /dev/null +++ b/examples/tessellation-modes/shaders/robustwireframe.geom @@ -0,0 +1,131 @@ +#version 400 core + +layout( triangles ) in; +layout( triangle_strip, max_vertices = 3 ) out; + +in EyeSpaceVertex { + vec3 position; + vec3 normal; +} gs_in[]; + +out WireframeVertex { + vec3 position; + vec3 normal; + noperspective vec4 edgeA; + noperspective vec4 edgeB; + flat int configuration; +} gs_out; + +uniform mat4 viewportMatrix; + +const int infoA[] = int[]( 0, 0, 0, 0, 1, 1, 2 ); +const int infoB[] = int[]( 1, 1, 2, 0, 2, 1, 2 ); +const int infoAd[] = int[]( 2, 2, 1, 1, 0, 0, 0 ); +const int infoBd[] = int[]( 2, 2, 1, 2, 0, 2, 1 ); + +vec2 transformToViewport( const in vec4 p ) +{ + return vec2( viewportMatrix * ( p / p.w ) ); +} + +void main() +{ + gs_out.configuration = int(gl_in[0].gl_Position.z < 0) * int(4) + + int(gl_in[1].gl_Position.z < 0) * int(2) + + int(gl_in[2].gl_Position.z < 0); + + // If all vertices are behind us, cull the primitive + if (gs_out.configuration == 7) + return; + + // Transform each vertex into viewport space + vec2 p[3]; + p[0] = transformToViewport( gl_in[0].gl_Position ); + p[1] = transformToViewport( gl_in[1].gl_Position ); + p[2] = transformToViewport( gl_in[2].gl_Position ); + + if (gs_out.configuration == 0) + { + // Common configuration where all vertices are within the viewport + gs_out.edgeA = vec4(0.0); + gs_out.edgeB = vec4(0.0); + + // Calculate lengths of 3 edges of triangle + float a = length( p[1] - p[2] ); + float b = length( p[2] - p[0] ); + float c = length( p[1] - p[0] ); + + // Calculate internal angles using the cosine rule + float alpha = acos( ( b * b + c * c - a * a ) / ( 2.0 * b * c ) ); + float beta = acos( ( a * a + c * c - b * b ) / ( 2.0 * a * c ) ); + + // Calculate the perpendicular distance of each vertex from the opposing edge + float ha = abs( c * sin( beta ) ); + float hb = abs( c * sin( alpha ) ); + float hc = abs( b * sin( alpha ) ); + + // Now add this perpendicular distance as a per-vertex property in addition to + // the position and normal calculated in the vertex shader. + + // Vertex 0 (a) + gs_out.edgeA = vec4( ha, 0.0, 0.0, 0.0 ); + gs_out.normal = gs_in[0].normal; + gs_out.position = gs_in[0].position; + gl_Position = gl_in[0].gl_Position; + EmitVertex(); + + // Vertex 1 (b) + gs_out.edgeA = vec4( 0.0, hb, 0.0, 0.0 ); + gs_out.normal = gs_in[1].normal; + gs_out.position = gs_in[1].position; + gl_Position = gl_in[1].gl_Position; + EmitVertex(); + + // Vertex 2 (c) + gs_out.edgeA = vec4( 0.0, 0.0, hc, 0.0 ); + gs_out.normal = gs_in[2].normal; + gs_out.position = gs_in[2].position; + gl_Position = gl_in[2].gl_Position; + EmitVertex(); + + // Finish the primitive off + EndPrimitive(); + } + else + { + // Viewport projection breaks down for one or two vertices. + // Caclulate what we can here and defer rest to fragment shader. + // Since this is coherent for the entire primitive the conditional + // in the fragment shader is still cheap as all concurrent + // fragment shader invocations will take the same code path. + + // Copy across the viewport-space points for the (up to) two vertices + // in the viewport + gs_out.edgeA.xy = p[infoA[gs_out.configuration]]; + gs_out.edgeB.xy = p[infoB[gs_out.configuration]]; + + // Copy across the viewport-space edge vectors for the (up to) two vertices + // in the viewport + gs_out.edgeA.zw = normalize( gs_out.edgeA.xy - p[ infoAd[gs_out.configuration] ] ); + gs_out.edgeB.zw = normalize( gs_out.edgeB.xy - p[ infoBd[gs_out.configuration] ] ); + + // Pass through the other vertex attributes + gs_out.normal = gs_in[0].normal; + gs_out.position = gs_in[0].position; + gl_Position = gl_in[0].gl_Position; + EmitVertex(); + + gs_out.normal = gs_in[1].normal; + gs_out.position = gs_in[1].position; + gl_Position = gl_in[1].gl_Position; + EmitVertex(); + + gs_out.normal = gs_in[2].normal; + gs_out.position = gs_in[2].position; + gl_Position = gl_in[2].gl_Position; + EmitVertex(); + + // Finish the primitive off + EndPrimitive(); + } +} diff --git a/examples/tessellation-modes/shaders/triangles.tcs b/examples/tessellation-modes/shaders/triangles.tcs new file mode 100644 index 000000000..c311796fd --- /dev/null +++ b/examples/tessellation-modes/shaders/triangles.tcs @@ -0,0 +1,19 @@ +#version 400 core + +layout( vertices = 3 ) out; + +uniform float inner[2] = float[]( 1.0, 1.0 ); +uniform float outer[4] = float[]( 1.0, 1.0, 1.0, 1.0 ); + +void main() +{ + // Pass along the vertex position unmodified + gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position; + + // Set the tessellation levels from the uniforms + gl_TessLevelOuter[0] = outer[0]; + gl_TessLevelOuter[1] = outer[1]; + gl_TessLevelOuter[2] = outer[2]; + + gl_TessLevelInner[0] = inner[0]; +} diff --git a/examples/tessellation-modes/shaders/triangles.tes b/examples/tessellation-modes/shaders/triangles.tes new file mode 100644 index 000000000..c833e9587 --- /dev/null +++ b/examples/tessellation-modes/shaders/triangles.tes @@ -0,0 +1,39 @@ +#version 400 core + +layout( triangles, fractional_even_spacing, ccw ) in; + +out EyeSpaceVertex { + vec3 position; + vec3 normal; +} te_out; + +uniform mat4 modelViewMatrix; +uniform mat3 normalMatrix; +uniform mat4 projectionMatrix; +uniform mat4 mvp; + +void main() +{ + float u = gl_TessCoord.x; + float v = gl_TessCoord.y; + float w = gl_TessCoord.z; + + vec4 p0 = gl_in[0].gl_Position; + vec4 p1 = gl_in[1].gl_Position; + vec4 p2 = gl_in[2].gl_Position; + + // Linearly interpolate to the vertex position using the + // (u,v) barycentric coords + vec4 pos = (u * p0) + + (v * p1) + + (w * p2); + + // Transform to eye space (for lighting calcs) + te_out.position = vec3( modelViewMatrix * pos ); + + // Assume normal points along z + te_out.normal = normalize( normalMatrix * vec3( 0.0, 0.0, 1.0 ) ); + + // Transform to clip-space + gl_Position = mvp * pos; +} diff --git a/examples/tessellation-modes/tessellatedquadmesh.cpp b/examples/tessellation-modes/tessellatedquadmesh.cpp new file mode 100644 index 000000000..de524073a --- /dev/null +++ b/examples/tessellation-modes/tessellatedquadmesh.cpp @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "tessellatedquadmesh.h" + +#include <Qt3DRenderer/qattribute.h> +#include <Qt3DRenderer/qbuffer.h> +#include <Qt3DRenderer/qmeshdata.h> + +TessellatedQuadMesh::TessellatedQuadMesh(Qt3D::QNode *parent) + : Qt3D::QAbstractShapeMesh(parent) +{ +} + +TessellatedQuadMesh *TessellatedQuadMesh::doClone(Qt3D::QNode *clonedParent) const +{ + return new TessellatedQuadMesh(clonedParent); +} + +class TessellatedQuadMeshFunctor : public Qt3D::QAbstractMeshFunctor +{ +public: + TessellatedQuadMeshFunctor() {} + + Qt3D::QAbstractMeshDataPtr operator ()() Q_DECL_OVERRIDE + { + const float positionData[] = { + -0.8f, -0.8f, 0.0f, + 0.8f, -0.8f, 0.0f, + 0.8f, 0.8f, 0.0f, + -0.8f, 0.8f, 0.0f + }; + + const int nVerts = 4; + const int size = nVerts * 3 * sizeof(float); + QByteArray positionBytes; + positionBytes.resize(size); + memcpy(positionBytes.data(), positionData, size); + + Qt3D::BufferPtr vertexBuffer(new Qt3D::Buffer(QOpenGLBuffer::VertexBuffer)); + vertexBuffer->setUsage(QOpenGLBuffer::StaticDraw); + vertexBuffer->setData(positionBytes); + + Qt3D::QMeshDataPtr mesh(new Qt3D::QMeshData(GL_PATCHES)); + mesh->addAttribute(Qt3D::QAbstractMeshData::defaultPositionAttributeName(), + Qt3D::AttributePtr(new Qt3D::Attribute(vertexBuffer, GL_FLOAT_VEC3, nVerts))); + mesh->setVerticesPerPatch(4); + return mesh; + } +}; + +Qt3D::QAbstractMeshFunctorPtr TessellatedQuadMesh::meshFunctor() const +{ + return Qt3D::QAbstractMeshFunctorPtr(new TessellatedQuadMeshFunctor); +} diff --git a/examples/tessellation-modes/tessellatedquadmesh.h b/examples/tessellation-modes/tessellatedquadmesh.h new file mode 100644 index 000000000..f2b04fd54 --- /dev/null +++ b/examples/tessellation-modes/tessellatedquadmesh.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TESSELLATEDQUAD_H +#define TESSELLATEDQUAD_H + +#include <Qt3DRenderer/qabstractshapemesh.h> + +class TessellatedQuadMesh : public Qt3D::QAbstractShapeMesh +{ + Q_OBJECT +public: + explicit TessellatedQuadMesh(Qt3D::QNode *parent = 0); + + Qt3D::QAbstractMeshFunctorPtr meshFunctor() const Q_DECL_OVERRIDE; + +protected: + TessellatedQuadMesh *doClone(QNode *clonedParent) const Q_DECL_OVERRIDE; +}; + +#endif // TESSELLATEDQUAD_H diff --git a/examples/tessellation-modes/tessellation-modes.pro b/examples/tessellation-modes/tessellation-modes.pro new file mode 100644 index 000000000..ab4ca80f5 --- /dev/null +++ b/examples/tessellation-modes/tessellation-modes.pro @@ -0,0 +1,24 @@ +TEMPLATE = app + +QT += 3dcore 3drenderer 3dquick qml quick + +include("../exampleresources/exampleresources.pri") + +HEADERS += \ + tessellatedquadmesh.h + +SOURCES += \ + main.cpp \ + tessellatedquadmesh.cpp + +OTHER_FILES += \ + main.qml \ + BasicCamera.qml \ + TessellatedWireframeEffect.qml \ + TessellatedWireframeMaterial.qml \ + TessellatedQuad.qml \ + ForwardRenderer.qml \ + shaders/* + +RESOURCES += \ + tessellation-modes.qrc diff --git a/examples/tessellation-modes/tessellation-modes.qrc b/examples/tessellation-modes/tessellation-modes.qrc new file mode 100644 index 000000000..705616de4 --- /dev/null +++ b/examples/tessellation-modes/tessellation-modes.qrc @@ -0,0 +1,20 @@ +<RCC> + <qresource prefix="/"> + <file>main.qml</file> + <file>ForwardRenderer.qml</file> + <file>BasicCamera.qml</file> + <file>TessellatedWireframeEffect.qml</file> + <file>TessellatedWireframeMaterial.qml</file> + <file>shaders/flat.frag</file> + <file>shaders/isolines.tcs</file> + <file>shaders/isolines.tes</file> + <file>shaders/passthru.vert</file> + <file>shaders/phongwireframe.frag</file> + <file>shaders/quads.tcs</file> + <file>shaders/quads.tes</file> + <file>shaders/triangles.tcs</file> + <file>shaders/triangles.tes</file> + <file>shaders/robustwireframe.geom</file> + <file>TessellatedQuad.qml</file> + </qresource> +</RCC> diff --git a/src/core/io/qabstractmeshdata.cpp b/src/core/io/qabstractmeshdata.cpp index 698350369..0e2804837 100644 --- a/src/core/io/qabstractmeshdata.cpp +++ b/src/core/io/qabstractmeshdata.cpp @@ -50,6 +50,7 @@ namespace Qt3D { QAbstractMeshDataPrivate::QAbstractMeshDataPrivate(QAbstractMeshData *qq) : q_ptr(qq) + , m_verticesPerPatch(0) { } @@ -97,6 +98,18 @@ QAbstractAttributePtr QAbstractMeshData::indexAttribute() const return d->m_indexAttr; } +void QAbstractMeshData::setVerticesPerPatch(int verticesPerPatch) +{ + Q_D(QAbstractMeshData); + d->m_verticesPerPatch = verticesPerPatch; +} + +int QAbstractMeshData::verticesPerPatch() const +{ + Q_D(const QAbstractMeshData); + return d->m_verticesPerPatch; +} + int QAbstractMeshData::primitiveCount() const { Q_D(const QAbstractMeshData); diff --git a/src/core/io/qabstractmeshdata.h b/src/core/io/qabstractmeshdata.h index 811cea698..e4cc5352a 100644 --- a/src/core/io/qabstractmeshdata.h +++ b/src/core/io/qabstractmeshdata.h @@ -79,6 +79,9 @@ public: virtual void setPrimitiveType(int primitiveType) = 0; virtual int primitiveType() const = 0; + void setVerticesPerPatch(int verticesPerPatch); + int verticesPerPatch() const; + int primitiveCount() const; QList<QAbstractBufferPtr> buffers() const; diff --git a/src/core/io/qabstractmeshdata_p.h b/src/core/io/qabstractmeshdata_p.h index 097b53119..cc2f353b0 100644 --- a/src/core/io/qabstractmeshdata_p.h +++ b/src/core/io/qabstractmeshdata_p.h @@ -66,10 +66,10 @@ public: Q_DECLARE_PUBLIC(QAbstractMeshData) QAbstractMeshData *q_ptr; - QMap<QString, QAbstractAttributePtr> m_attributes; QAbstractAttributePtr m_indexAttr; AxisAlignedBoundingBox m_bbox; + int m_verticesPerPatch; }; } // Qt3D diff --git a/src/render/backend/qgraphicscontext.cpp b/src/render/backend/qgraphicscontext.cpp index d6115bcbf..e9ebfa086 100644 --- a/src/render/backend/qgraphicscontext.cpp +++ b/src/render/backend/qgraphicscontext.cpp @@ -480,6 +480,11 @@ void QGraphicsContext::drawArrays(GLenum primitiveType, count); } +void QGraphicsContext::setVerticesPerPatch(GLint verticesPerPatch) +{ + m_glHelper->setVerticesPerPatch(verticesPerPatch); +} + void QGraphicsContext::blendEquation(GLenum mode) { m_glHelper->blendEquation(mode); diff --git a/src/render/backend/qgraphicscontext_p.h b/src/render/backend/qgraphicscontext_p.h index bd91f35b3..edad0ec5f 100644 --- a/src/render/backend/qgraphicscontext_p.h +++ b/src/render/backend/qgraphicscontext_p.h @@ -163,6 +163,7 @@ public: void drawArraysInstanced(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances); void drawElements(GLenum primitiveType, GLsizei primitiveCount, GLint indexType, void * indices); void drawArrays(GLenum primitiveType, GLint first, GLsizei count); + void setVerticesPerPatch(GLint verticesPerPatch); void blendEquation(GLenum mode); void alphaTest(GLenum mode1, GLenum mode2); void depthTest(GLenum mode); diff --git a/src/render/backend/qgraphicshelperes2.cpp b/src/render/backend/qgraphicshelperes2.cpp index e222580ea..36062560b 100644 --- a/src/render/backend/qgraphicshelperes2.cpp +++ b/src/render/backend/qgraphicshelperes2.cpp @@ -116,6 +116,12 @@ void QGraphicsHelperES2::drawArrays(GLenum primitiveType, count); } +void QGraphicsHelperES2::setVerticesPerPatch(GLint verticesPerPatch) +{ + Q_UNUSED(verticesPerPatch); + qWarning() << "Tessellation not supported with OpenGL ES 2"; +} + void QGraphicsHelperES2::useProgram(GLuint programId) { m_funcs->glUseProgram(programId); @@ -254,6 +260,8 @@ bool QGraphicsHelperES2::supportsFeature(QGraphicsHelperInterface::Feature featu switch (feature) { case MRT: return false; + case Tessellation: + return false; default: return false; } diff --git a/src/render/backend/qgraphicshelperes2_p.h b/src/render/backend/qgraphicshelperes2_p.h index 66dfbff68..fe7acc6b3 100644 --- a/src/render/backend/qgraphicshelperes2_p.h +++ b/src/render/backend/qgraphicshelperes2_p.h @@ -66,6 +66,7 @@ public: void drawArraysInstanced(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances) Q_DECL_OVERRIDE; void drawElements(GLenum primitiveType, GLsizei primitiveCount, GLint indexType, void *indices) Q_DECL_OVERRIDE; void drawArrays(GLenum primitiveType, GLint first, GLsizei count) Q_DECL_OVERRIDE; + void setVerticesPerPatch(GLint verticesPerPatch) Q_DECL_OVERRIDE; void useProgram(GLuint programId) Q_DECL_OVERRIDE; QVector<QPair<QString, int> > programUniformsAndLocations(GLuint programId) Q_DECL_OVERRIDE; QVector<QPair<QString, int> > programAttributesAndLocations(GLuint programId) Q_DECL_OVERRIDE; diff --git a/src/render/backend/qgraphicshelpergl2.cpp b/src/render/backend/qgraphicshelpergl2.cpp index b7b30a52c..68be92cf2 100644 --- a/src/render/backend/qgraphicshelpergl2.cpp +++ b/src/render/backend/qgraphicshelpergl2.cpp @@ -120,6 +120,12 @@ void QGraphicsHelperGL2::drawArrays(GLenum primitiveType, count); } +void QGraphicsHelperGL2::setVerticesPerPatch(GLint verticesPerPatch) +{ + Q_UNUSED(verticesPerPatch); + qWarning() << "Tessellation not supported with OpenGL 2"; +} + void QGraphicsHelperGL2::useProgram(GLuint programId) { m_funcs->glUseProgram(programId); @@ -270,6 +276,8 @@ bool QGraphicsHelperGL2::supportsFeature(QGraphicsHelperInterface::Feature featu switch (feature) { case MRT: return (m_fboFuncs != Q_NULLPTR); + case Tessellation: + return false; default: return false; } diff --git a/src/render/backend/qgraphicshelpergl2_p.h b/src/render/backend/qgraphicshelpergl2_p.h index 964df3364..388e034b1 100644 --- a/src/render/backend/qgraphicshelpergl2_p.h +++ b/src/render/backend/qgraphicshelpergl2_p.h @@ -65,6 +65,7 @@ public: void drawArraysInstanced(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances) Q_DECL_OVERRIDE; void drawElements(GLenum primitiveType, GLsizei primitiveCount, GLint indexType, void *indices) Q_DECL_OVERRIDE; void drawArrays(GLenum primitiveType, GLint first, GLsizei count) Q_DECL_OVERRIDE; + void setVerticesPerPatch(GLint verticesPerPatch) Q_DECL_OVERRIDE; void useProgram(GLuint programId) Q_DECL_OVERRIDE; QVector<QPair<QString, int> > programUniformsAndLocations(GLuint programId) Q_DECL_OVERRIDE; QVector<QPair<QString, int> > programAttributesAndLocations(GLuint programId) Q_DECL_OVERRIDE; diff --git a/src/render/backend/qgraphicshelpergl3.cpp b/src/render/backend/qgraphicshelpergl3.cpp index f5b118e50..c67b5c09f 100644 --- a/src/render/backend/qgraphicshelpergl3.cpp +++ b/src/render/backend/qgraphicshelpergl3.cpp @@ -43,6 +43,7 @@ #include "qgraphicshelpergl3_p.h" #include <QOpenGLFunctions_3_2_Core> +#include <QtOpenGLExtensions/qopenglextensions.h> #include "renderlogging.h" #include <private/attachmentpack_p.h> @@ -51,8 +52,9 @@ QT_BEGIN_NAMESPACE namespace Qt3D { namespace Render { -QGraphicsHelperGL3::QGraphicsHelperGL3() : - m_funcs(0) +QGraphicsHelperGL3::QGraphicsHelperGL3() + : m_funcs(Q_NULLPTR) + , m_tessFuncs() { } @@ -64,6 +66,11 @@ void QGraphicsHelperGL3::initializeHelper(QOpenGLContext *context, const bool ok = m_funcs->initializeOpenGLFunctions(); Q_ASSERT(ok); Q_UNUSED(ok); + + if (context->hasExtension(QByteArrayLiteral("GL_ARB_tessellation_shader"))) { + m_tessFuncs.reset(new QOpenGLExtension_ARB_tessellation_shader); + m_tessFuncs->initializeOpenGLFunctions(); + } } void QGraphicsHelperGL3::drawElementsInstanced(GLenum primitiveType, @@ -112,6 +119,16 @@ void QGraphicsHelperGL3::drawArrays(GLenum primitiveType, count); } +void QGraphicsHelperGL3::setVerticesPerPatch(GLint verticesPerPatch) +{ + if (!m_tessFuncs) { + qWarning() << "Tessellation not supported with OpenGL 3 without GL_ARB_tessellation_shader"; + return; + } + + m_tessFuncs->glPatchParameteri(GL_PATCH_VERTICES, verticesPerPatch); +} + void QGraphicsHelperGL3::useProgram(GLuint programId) { m_funcs->glUseProgram(programId); @@ -253,6 +270,8 @@ bool QGraphicsHelperGL3::supportsFeature(QGraphicsHelperInterface::Feature featu switch (feature) { case MRT: return true; + case Tessellation: + return !m_tessFuncs.isNull(); default: return false; } diff --git a/src/render/backend/qgraphicshelpergl3_p.h b/src/render/backend/qgraphicshelpergl3_p.h index 737429bb7..e98399a33 100644 --- a/src/render/backend/qgraphicshelpergl3_p.h +++ b/src/render/backend/qgraphicshelpergl3_p.h @@ -46,9 +46,12 @@ #include <Qt3DRenderer/private/qgraphicshelperinterface_p.h> +#include <QtCore/qscopedpointer.h> + QT_BEGIN_NAMESPACE class QOpenGLFunctions_3_2_Core; +class QOpenGLExtension_ARB_tessellation_shader; namespace Qt3D { namespace Render { @@ -64,6 +67,7 @@ public: void drawArraysInstanced(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances) Q_DECL_OVERRIDE; void drawElements(GLenum primitiveType, GLsizei primitiveCount, GLint indexType, void *indices) Q_DECL_OVERRIDE; void drawArrays(GLenum primitiveType, GLint first, GLsizei count) Q_DECL_OVERRIDE; + void setVerticesPerPatch(GLint verticesPerPatch) Q_DECL_OVERRIDE; void useProgram(GLuint programId) Q_DECL_OVERRIDE; QVector<QPair<QString, int> > programUniformsAndLocations(GLuint programId) Q_DECL_OVERRIDE; QVector<QPair<QString, int> > programAttributesAndLocations(GLuint programId) Q_DECL_OVERRIDE; @@ -86,6 +90,7 @@ public: private: QOpenGLFunctions_3_2_Core *m_funcs; + QScopedPointer<QOpenGLExtension_ARB_tessellation_shader> m_tessFuncs; }; } // Render diff --git a/src/render/backend/qgraphicshelperinterface_p.h b/src/render/backend/qgraphicshelperinterface_p.h index 71afcb18b..e1d28e448 100644 --- a/src/render/backend/qgraphicshelperinterface_p.h +++ b/src/render/backend/qgraphicshelperinterface_p.h @@ -57,9 +57,9 @@ class Attachment; class QGraphicsHelperInterface { public: - enum Feature { - MRT = 0 + MRT = 0, + Tessellation }; virtual ~QGraphicsHelperInterface() {} @@ -68,6 +68,7 @@ public: virtual void drawArraysInstanced(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances) = 0; virtual void drawElements(GLenum primitiveType, GLsizei primitiveCount, GLint indexType, void * indices) = 0; virtual void drawArrays(GLenum primitiveType, GLint first, GLsizei count) = 0; + virtual void setVerticesPerPatch(GLint verticesPerPatch) = 0; virtual void useProgram(GLuint programId) = 0; virtual QVector<QPair<QString, int> > programUniformsAndLocations(GLuint programId) = 0; virtual QVector<QPair<QString, int> > programAttributesAndLocations(GLuint programId) = 0; diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp index 4f5db8d3a..c89adfc81 100644 --- a/src/render/backend/renderer.cpp +++ b/src/render/backend/renderer.cpp @@ -611,13 +611,17 @@ void Renderer::executeCommands(const QVector<RenderCommand *> &commands) GLint primCount = meshData->primitiveCount(); GLint indexType = drawIndexed ? meshData->indexAttribute()->type() : 0; - if (drawIndexed) + if (primType == GL_PATCHES && meshData->verticesPerPatch() != 0) + m_graphicsContext->setVerticesPerPatch(meshData->verticesPerPatch()); + + if (drawIndexed) { m_graphicsContext->drawElements(primType, primCount, indexType, reinterpret_cast<void*>(meshData->indexAttribute()->byteOffset())); - else + } else { m_graphicsContext->drawArrays(primType, 0, primCount); + } int err = glGetError(); if (err) diff --git a/src/render/io/qmeshdata.cpp b/src/render/io/qmeshdata.cpp index 11f625770..00c7c3a05 100644 --- a/src/render/io/qmeshdata.cpp +++ b/src/render/io/qmeshdata.cpp @@ -75,9 +75,10 @@ QMeshData::QMeshData(int primitiveType) void QMeshData::setPrimitiveType(int primitiveType) { Q_D(QMeshData); - Q_ASSERT((d->m_primitiveType == GL_TRIANGLES) || - (d->m_primitiveType == GL_LINES) || - (d->m_primitiveType == GL_POINTS)); + Q_ASSERT((primitiveType == GL_TRIANGLES) || + (primitiveType == GL_LINES) || + (primitiveType == GL_POINTS) || + (primitiveType == GL_PATCHES)); d->m_primitiveType = primitiveType; } |