From 4a44b6520ff8add3dd65be6224fd7410e5405939 Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Tue, 8 Dec 2015 09:01:15 +0100 Subject: Add a compute shader example Change-Id: I956b647e2218ad3e604bd9e8260b3ea0a90dc84e Reviewed-by: Sean Harmer --- .../qt3d/compute-particles/ComputeFrameGraph.qml | 69 +++++++ .../qt3d/compute-particles/ComputeMaterial.qml | 108 ++++++++++ examples/qt3d/compute-particles/ParticlesScene.qml | 230 +++++++++++++++++++++ .../qt3d/compute-particles/compute-particles.pro | 14 ++ .../qt3d/compute-particles/compute-particles.qrc | 11 + examples/qt3d/compute-particles/main.cpp | 52 +++++ examples/qt3d/compute-particles/main.qml | 132 ++++++++++++ examples/qt3d/compute-particles/particles.comp | 41 ++++ examples/qt3d/compute-particles/particles.frag | 33 +++ examples/qt3d/compute-particles/particles.vert | 27 +++ examples/qt3d/qt3d.pro | 3 +- 11 files changed, 719 insertions(+), 1 deletion(-) create mode 100644 examples/qt3d/compute-particles/ComputeFrameGraph.qml create mode 100644 examples/qt3d/compute-particles/ComputeMaterial.qml create mode 100644 examples/qt3d/compute-particles/ParticlesScene.qml create mode 100644 examples/qt3d/compute-particles/compute-particles.pro create mode 100644 examples/qt3d/compute-particles/compute-particles.qrc create mode 100644 examples/qt3d/compute-particles/main.cpp create mode 100644 examples/qt3d/compute-particles/main.qml create mode 100644 examples/qt3d/compute-particles/particles.comp create mode 100644 examples/qt3d/compute-particles/particles.frag create mode 100644 examples/qt3d/compute-particles/particles.vert (limited to 'examples/qt3d') diff --git a/examples/qt3d/compute-particles/ComputeFrameGraph.qml b/examples/qt3d/compute-particles/ComputeFrameGraph.qml new file mode 100644 index 000000000..08782d93f --- /dev/null +++ b/examples/qt3d/compute-particles/ComputeFrameGraph.qml @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2015 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:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt3D.Core 2.0 +import Qt3D.Render 2.0 + +Viewport { + property alias camera: selector.camera + + // Clear Buffer + ClearBuffer { + buffers: ClearBuffer.ColorDepthBuffer + NoDraw {} + } + + // Compute Pass + DispatchCompute { + workGroupX: 1024; workGroupY: 1; workGroupZ: 1 + TechniqueFilter { + requires: [ + Annotation { name: "type"; value: "compute"} + ] + } + } + + // Draw particles from buffer computed in the Compute Pass + CameraSelector { + id: selector + TechniqueFilter { + requires: [ + Annotation { name: "type"; value: "draw"} + ] + } + } +} + diff --git a/examples/qt3d/compute-particles/ComputeMaterial.qml b/examples/qt3d/compute-particles/ComputeMaterial.qml new file mode 100644 index 000000000..d91d15b3c --- /dev/null +++ b/examples/qt3d/compute-particles/ComputeMaterial.qml @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2015 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:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt3D.Core 2.0 +import Qt3D.Render 2.0 + +Material { + property Buffer dataBuffer; + property real particleStep: 0.4 + property real finalCollisionFactor: 0.2 + + parameters: [ + Parameter { name: "particleStep"; value: particleStep }, + Parameter { name: "finalCollisionFactor"; value: finalCollisionFactor } + ] + + ShaderProgram { + id: computeShader + computeShaderCode: loadSource("qrc:/particles.comp") + } + + ShaderProgram { + id: drawShader + vertexShaderCode: loadSource("qrc:/particles.vert") + fragmentShaderCode: loadSource("qrc:/particles.frag") + } + + effect: Effect { + techniques: [ + Technique { + renderPasses: [ + RenderPass { + shaderProgram: computeShader + // We set the buffer as the parameter data + parameters: [ + Parameter { name: "Particles"; value: dataBuffer } + ] + } + ] + annotations: [ + Annotation { name: "type"; value: "compute" } + ] + graphicsApiFilter { + api: GraphicsApiFilter.OpenGL + profile: GraphicsApiFilter.CoreProfile + majorVersion: 4 + minorVersion: 3 + } + }, + Technique { + renderPasses: [ + RenderPass { + shaderProgram: drawShader + // We assume the mesh to be drawn will also receive + // Vertex buffers attributes that will be used to position and color + bindings: [ + ParameterMapping { parameterName: "particlePosition"; shaderVariableName: "particlePosition"; bindingType: ParameterMapping.Attribute }, + ParameterMapping { parameterName: "particleColor"; shaderVariableName: "particleColor"; bindingType: ParameterMapping.Attribute } + ] + } + ] + annotations: [ + Annotation { name: "type"; value: "draw" } + ] + graphicsApiFilter { + api: GraphicsApiFilter.OpenGL + profile: GraphicsApiFilter.CoreProfile + majorVersion: 4 + minorVersion: 3 + } + } + ] // techniques + } +} + diff --git a/examples/qt3d/compute-particles/ParticlesScene.qml b/examples/qt3d/compute-particles/ParticlesScene.qml new file mode 100644 index 000000000..f1472e178 --- /dev/null +++ b/examples/qt3d/compute-particles/ParticlesScene.qml @@ -0,0 +1,230 @@ +/**************************************************************************** +** +** Copyright (C) 2015 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:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt3D.Core 2.0 +import Qt3D.Render 2.0 + +Entity { + property alias particleStep: computeMaterial.particleStep + property alias finalCollisionFactor: computeMaterial.finalCollisionFactor + + readonly property int _SPHERE: 0 + readonly property int _CUBE: 1 + readonly property int _CYLINDER: 2 + readonly property int _TORUS: 3 + + property int particlesShape: _SPHERE + + signal reset() + + components: [ + FrameGraph { + ComputeFrameGraph { + camera: sceneCamera + } + } + ] + + Configuration { + controlledCamera: sceneCamera + } + + Camera { + id: sceneCamera + projectionType: CameraLens.PerspectiveProjection + viewCenter: Qt.vector3d(0, 0, 0) + position: Qt.vector3d(0, 0, -800) + nearPlane: 0.1 + farPlane: 1000 + fieldOfView: 25 + aspectRatio: 1.33 + } + + property int particlesCount: 50 * 1024 + readonly property int floatSize: 4 + + function buildParticlesBuffer() { + var bufferData = new Float32Array(particlesCount * 4 * 3); + var factor = 500.0; + for (var i = 0; i < particlesCount; ++i) { + var positionIdx = i * 12; + var velocityIdx = i * 12 + 4; + var colorIdx = i * 12 + 8; + + for (var j = 0; j < 3; ++j) { + bufferData[positionIdx + j] = (Math.random() - 0.5) * factor; + bufferData[velocityIdx + j] = Math.random() * 2.0; + bufferData[colorIdx + j] = 0.75 + Math.sin(((i / 1024.0) + j * 0.333) * 6.0) * 0.25; + } + + bufferData[positionIdx + 3] = 1.0; + bufferData[velocityIdx + 3] = 0.0; + bufferData[colorIdx + 3] = 1.0; + } + return bufferData + } + + Buffer { + id: particleBuffer + type: Buffer.VertexBuffer + // struct ParticleData + // { + // vec3 position; // Aligned to 4 floats + // vec3 velocity; // Aligned to 4 floats + // vec3 color; // Aligned to 4 floats + // }; + data: buildParticlesBuffer() + } + + onReset : { + particleBuffer.data = buildParticlesBuffer() + } + + Attribute { + id: particlePositionDataAttribute + name: "particlePosition" + attributeType: Attribute.VertexAttribute + dataType: Attribute.Float + dataSize: 3 + divisor: 1 + byteStride: 12 * floatSize + buffer: particleBuffer + } + + Attribute { + id: particleColorDataAttribute + name: "particleColor" + attributeType: Attribute.VertexAttribute + dataType: Attribute.Float + dataSize: 3 + divisor: 1 + byteOffset: 8 * floatSize + byteStride: 12 * floatSize + buffer: particleBuffer + } + + ComputeMaterial { + id: computeMaterial + dataBuffer: particleBuffer + } + + Entity { + id: particleComputeEntity + readonly property ComputeJob particlesComputeJob: ComputeJob {} + components: [ + particlesComputeJob, + computeMaterial + ] + } + + SphereGeometry { + id: sphereGeometry + rings: 10 + slices: 10 + radius: 1 + // Additional Attributes + attributes: [ + particlePositionDataAttribute, + particleColorDataAttribute + ] + } + + CuboidGeometry { + id: cubeGeometry + yzMeshResolution: Qt.size(2, 2) + xzMeshResolution: Qt.size(2, 2) + xyMeshResolution: Qt.size(2, 2) + // Additional Attributes + attributes: [ + particlePositionDataAttribute, + particleColorDataAttribute + ] + } + + CylinderGeometry { + id: cylinderGeometry + rings: 10 + slices: 10 + radius: 1 + length: 1.5 + // Additional Attributes + attributes: [ + particlePositionDataAttribute, + particleColorDataAttribute + ] + } + + TorusGeometry { + id: torusGeometry + rings: 10 + slices: 10 + radius: 1 + minorRadius: 0.5 + // Additional Attributes + attributes: [ + particlePositionDataAttribute, + particleColorDataAttribute + ] + } + + Entity { + id: particleRenderEntity + readonly property GeometryRenderer particlesRenderer: GeometryRenderer { + instanceCount: particlesCount + baseVertex: 0 + baseInstance: 0 + primitiveType: GeometryRenderer.Triangles + geometry: { + switch (particlesShape) { + case _SPHERE: + return sphereGeometry; + case _CUBE: + return cubeGeometry; + case _CYLINDER: + return cylinderGeometry; + case _TORUS: + return torusGeometry; + } + } + } + + components: [ + particlesRenderer, + computeMaterial + ] + } +} + diff --git a/examples/qt3d/compute-particles/compute-particles.pro b/examples/qt3d/compute-particles/compute-particles.pro new file mode 100644 index 000000000..c25cc0c30 --- /dev/null +++ b/examples/qt3d/compute-particles/compute-particles.pro @@ -0,0 +1,14 @@ +!include( ../examples.pri ) { + error( "Couldn't find the examples.pri file!" ) +} + +QT += 3dcore 3drender 3dquick 3dinput quick qml + +HEADERS += \ + + +RESOURCES += \ + compute-particles.qrc + +SOURCES += \ + main.cpp diff --git a/examples/qt3d/compute-particles/compute-particles.qrc b/examples/qt3d/compute-particles/compute-particles.qrc new file mode 100644 index 000000000..0f94fddd5 --- /dev/null +++ b/examples/qt3d/compute-particles/compute-particles.qrc @@ -0,0 +1,11 @@ + + + main.qml + ComputeFrameGraph.qml + ComputeMaterial.qml + particles.frag + particles.vert + ParticlesScene.qml + particles.comp + + diff --git a/examples/qt3d/compute-particles/main.cpp b/examples/qt3d/compute-particles/main.cpp new file mode 100644 index 000000000..1095df57b --- /dev/null +++ b/examples/qt3d/compute-particles/main.cpp @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2015 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:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +int main(int argc, char* argv[]) +{ + QGuiApplication app(argc, argv); + + QQuickView view; + + view.resize(500, 500); + view.setResizeMode(QQuickView::SizeRootObjectToView); + view.setSource(QUrl("qrc:/main.qml")); + view.show(); + + return app.exec(); +} diff --git a/examples/qt3d/compute-particles/main.qml b/examples/qt3d/compute-particles/main.qml new file mode 100644 index 000000000..a0b43590e --- /dev/null +++ b/examples/qt3d/compute-particles/main.qml @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** Copyright (C) 2015 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:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Scene3D 2.0 +import QtQuick.Controls 1.4 +import QtQuick.Layouts 1.1 + +Item { + + Scene3D { + anchors.fill: parent + aspects: "input" + ParticlesScene { + id: scene + particleStep: stepSlider.value + finalCollisionFactor: collisionSlider.value + } + } + + ColumnLayout { + id: colorLayout + anchors.left: parent.left + anchors.leftMargin: 35 + anchors.right: parent.right + anchors.rightMargin: 35 + anchors.bottom: parent.bottom + anchors.bottomMargin: 35 + spacing: 15 + + RowLayout { + Text { + text: "Particles Step:" + color: "white" + } + Slider { + height: 35 + id: stepSlider + Layout.fillWidth: true + minimumValue: 0.0 + maximumValue: 2 + value: 0.4 + } + } + RowLayout { + Text { + text: "Particles Collision:" + color: "white" + } + Slider { + height: 35 + id: collisionSlider + Layout.fillWidth: true + minimumValue: 0.0 + maximumValue: 2 + value: 0.2 + } + } + RowLayout { + Button { + text: "Reset Particles" + onClicked: scene.reset() + } + } + RowLayout { + Text { + text: "Particles Shape:" + color: "white" + } + ExclusiveGroup { + id: particlesTypeGroup + } + CheckBox { + text: "Sphere" + checked: true + exclusiveGroup: particlesTypeGroup + onClicked: scene.particlesShape = scene._SPHERE + } + CheckBox + { text: "Cube" + checked: false + exclusiveGroup: particlesTypeGroup + onClicked: scene.particlesShape = scene._CUBE + } + CheckBox { + text: "Cylinder" + checked: false + exclusiveGroup: particlesTypeGroup + onClicked: scene.particlesShape = scene._CYLINDER + } + CheckBox { + text: "Torus" + checked: false + exclusiveGroup: particlesTypeGroup + onClicked: scene.particlesShape = scene._TORUS + } + } + } +} diff --git a/examples/qt3d/compute-particles/particles.comp b/examples/qt3d/compute-particles/particles.comp new file mode 100644 index 000000000..7feaf5fdd --- /dev/null +++ b/examples/qt3d/compute-particles/particles.comp @@ -0,0 +1,41 @@ +#version 430 core + +uniform float particleStep; +uniform float finalCollisionFactor; + +layout (local_size_x = 1024) in; + +struct ParticleData +{ + vec3 position; + vec3 direction; + vec3 color; +}; + +// Particles from previouse frame +layout (std430, binding = 0) coherent buffer Particles +{ + ParticleData particles[]; +} data; + +void main(void) +{ + uint globalId = gl_GlobalInvocationID.x; + + // Retrieve current particle from previous frame + ParticleData currentParticle = data.particles[globalId]; + + // New position = old position + distance traveled over step duration + currentParticle.position = currentParticle.position + currentParticle.direction * particleStep; + + // Make acceleration more or less point toward the center of the scene + vec3 acceleration = normalize(vec3(0.0) - currentParticle.position) * finalCollisionFactor; + + // New velocity = old velocity + acceleration over step duration + currentParticle.direction = currentParticle.direction + acceleration * particleStep; + + + + // Save updated particle + data.particles[globalId] = currentParticle; +} diff --git a/examples/qt3d/compute-particles/particles.frag b/examples/qt3d/compute-particles/particles.frag new file mode 100644 index 000000000..3f11b9868 --- /dev/null +++ b/examples/qt3d/compute-particles/particles.frag @@ -0,0 +1,33 @@ +#version 430 core + +out vec4 color; + +in VertexBlock +{ + flat vec3 color; + vec3 pos; + vec3 normal; +} frag_in; + +const vec4 lightPosition = vec4(0.0, 0.0, 0.0, 0.0); +const vec3 lightIntensity = vec3(1.0, 1.0, 1.0); +const vec3 ka = vec3(0.1, 0.1, 0.1); +const vec3 ks = vec3(0.8, 0.8, 0.8); +const float shininess = 50.0; + +vec3 ads() +{ + vec3 n = normalize( frag_in.normal); + vec3 s = normalize( vec3(lightPosition) - frag_in.pos ); + vec3 v = normalize( -frag_in.pos ); + vec3 h = normalize( v + s ); + return lightIntensity * (ka + + frag_in.color * max( dot(s, frag_in.normal ), 0.0 ) + + ks * pow( max( dot( h, n ), 0.0 ), shininess ) ); +} + + +void main(void) +{ + color = vec4(ads(), 1.0); +} diff --git a/examples/qt3d/compute-particles/particles.vert b/examples/qt3d/compute-particles/particles.vert new file mode 100644 index 000000000..5f2da2a00 --- /dev/null +++ b/examples/qt3d/compute-particles/particles.vert @@ -0,0 +1,27 @@ +#version 430 core + +in vec3 vertexPosition; +in vec3 vertexNormal; + +in vec3 particlePosition; +in vec3 particleColor; + +out VertexBlock +{ + flat vec3 color; + vec3 pos; + vec3 normal; +} v_out; + +uniform mat4 mvp; +uniform mat3 modelViewNormal; +uniform mat4 modelView; + +void main(void) +{ + vec4 pos = vec4(vertexPosition.xyz, 1.0) + vec4(particlePosition, 0.0); + gl_Position = mvp * pos; + v_out.pos = vec4(modelView * pos).xyz; + v_out.normal = normalize(modelViewNormal * vertexNormal); + v_out.color = mix(particleColor * 0.2, particleColor, smoothstep(0.5, 0.8, abs(v_out.normal).z)); +} diff --git a/examples/qt3d/qt3d.pro b/examples/qt3d/qt3d.pro index 829eb2789..afba0a352 100644 --- a/examples/qt3d/qt3d.pro +++ b/examples/qt3d/qt3d.pro @@ -44,7 +44,8 @@ SUBDIRS += \ instanced-arrays-qml \ picking-qml \ transforms-qml \ - lights + lights \ + compute-particles # qmake seems to break in some CI configurations, disable this for now #SUBDIRS += qgltf -- cgit v1.2.3