diff options
author | Sean Harmer <sean.harmer@kdab.com> | 2015-08-12 14:12:49 -0700 |
---|---|---|
committer | Sean Harmer <sean.harmer@kdab.com> | 2015-10-19 10:51:19 +0000 |
commit | d9ae5577ea87ae23731fe54dd79fd80ecd1de1fa (patch) | |
tree | 6aa31bf99d839cf8ab9c3de757410052581d045a | |
parent | 6753c0238bd137f2d5f2528ada2d333e38ef2376 (diff) |
Add an example showing instancing using VBO with divisor of 1
Change-Id: I710df314902ca592c236e2120119718fc3b90c2c
Reviewed-by: Paul Lemire <paul.lemire@kdab.com>
-rw-r--r-- | examples/qt3d/instanced-arrays-qml/instancebuffer.cpp | 80 | ||||
-rw-r--r-- | examples/qt3d/instanced-arrays-qml/instancebuffer.h | 62 | ||||
-rw-r--r-- | examples/qt3d/instanced-arrays-qml/instanced-arrays-qml.pro | 17 | ||||
-rw-r--r-- | examples/qt3d/instanced-arrays-qml/instanced-arrays-qml.qrc | 7 | ||||
-rw-r--r-- | examples/qt3d/instanced-arrays-qml/instanced.frag | 43 | ||||
-rw-r--r-- | examples/qt3d/instanced-arrays-qml/instanced.vert | 51 | ||||
-rw-r--r-- | examples/qt3d/instanced-arrays-qml/main.cpp | 68 | ||||
-rw-r--r-- | examples/qt3d/instanced-arrays-qml/main.qml | 155 | ||||
-rw-r--r-- | examples/qt3d/qt3d.pro | 3 | ||||
-rw-r--r-- | src/render/geometry/qbuffer.h | 2 |
10 files changed, 486 insertions, 2 deletions
diff --git a/examples/qt3d/instanced-arrays-qml/instancebuffer.cpp b/examples/qt3d/instanced-arrays-qml/instancebuffer.cpp new file mode 100644 index 000000000..f457c96b9 --- /dev/null +++ b/examples/qt3d/instanced-arrays-qml/instancebuffer.cpp @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** 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 "instancebuffer.h" + +#include <QtGui/qvector3d.h> + +static const int rowCount = 20; +static const int colCount = 20; +static const int maxInstanceCount = rowCount * colCount; + +InstanceBuffer::InstanceBuffer(Qt3DCore::QNode *parent) + : Qt3DRender::QBuffer(QBuffer::VertexBuffer, parent) + , m_instanceCount(maxInstanceCount) +{ + // Create some per instance data - position of each instance + QByteArray ba; + ba.resize(maxInstanceCount * sizeof(QVector3D)); + QVector3D *posData = reinterpret_cast<QVector3D *>(ba.data()); + for (int j = 0; j < rowCount; ++j) { + const float z = float(j); + for (int i = 0; i < colCount; ++i) { + const float x = float(i); + const QVector3D pos(x, 0.0f, z); + *posData = pos; + ++posData; + } + } + + // Put the data into the buffer + setData(ba); +} + +int InstanceBuffer::instanceCount() const +{ + return m_instanceCount; +} + +void InstanceBuffer::setInstanceCount(int instanceCount) +{ + if (m_instanceCount == instanceCount) + return; + + m_instanceCount = instanceCount; + emit instanceCountChanged(instanceCount); +} + diff --git a/examples/qt3d/instanced-arrays-qml/instancebuffer.h b/examples/qt3d/instanced-arrays-qml/instancebuffer.h new file mode 100644 index 000000000..6bea7ca97 --- /dev/null +++ b/examples/qt3d/instanced-arrays-qml/instancebuffer.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef INSTANCEBUFFER_H +#define INSTANCEBUFFER_H + +#include <Qt3DRenderer/QBuffer> + +class InstanceBuffer : public Qt3DRender::QBuffer +{ + Q_OBJECT + Q_PROPERTY(int instanceCount READ instanceCount WRITE setInstanceCount NOTIFY instanceCountChanged) + +public: + InstanceBuffer(Qt3DCore::QNode *parent = 0); + + int instanceCount() const; + +public slots: + void setInstanceCount(int instanceCount); + +signals: + void instanceCountChanged(int instanceCount); + +private: + int m_instanceCount; +}; + +#endif // INSTANCEBUFFER_H diff --git a/examples/qt3d/instanced-arrays-qml/instanced-arrays-qml.pro b/examples/qt3d/instanced-arrays-qml/instanced-arrays-qml.pro new file mode 100644 index 000000000..a6f569ffc --- /dev/null +++ b/examples/qt3d/instanced-arrays-qml/instanced-arrays-qml.pro @@ -0,0 +1,17 @@ +!include( ../examples.pri ) { + error( "Couldn't find the examples.pri file!" ) +} + +QT += qml quick 3dcore 3drenderer 3dinput 3dquick + +SOURCES += \ + main.cpp \ + instancebuffer.cpp + +RESOURCES += \ + instanced-arrays-qml.qrc + +OTHER_FILES += *.qml + +HEADERS += \ + instancebuffer.h diff --git a/examples/qt3d/instanced-arrays-qml/instanced-arrays-qml.qrc b/examples/qt3d/instanced-arrays-qml/instanced-arrays-qml.qrc new file mode 100644 index 000000000..3e4910f7a --- /dev/null +++ b/examples/qt3d/instanced-arrays-qml/instanced-arrays-qml.qrc @@ -0,0 +1,7 @@ +<RCC> + <qresource prefix="/"> + <file>main.qml</file> + <file>instanced.frag</file> + <file>instanced.vert</file> + </qresource> +</RCC> diff --git a/examples/qt3d/instanced-arrays-qml/instanced.frag b/examples/qt3d/instanced-arrays-qml/instanced.frag new file mode 100644 index 000000000..cc41fee8e --- /dev/null +++ b/examples/qt3d/instanced-arrays-qml/instanced.frag @@ -0,0 +1,43 @@ +#version 150 core + +uniform vec4 lightPosition = vec4( 0.0, 0.0, 0.0, 1.0 ); +uniform vec3 lightIntensity = vec3( 1.0, 1.0, 1.0 ); + +uniform vec3 ka; // Ambient reflectivity +uniform vec3 ks = vec3( 1.0, 1.0, 1.0 ); // Specular reflectivity +uniform float shininess = 150.0; // Specular shininess factor + +in vec3 position; +in vec3 normal; +in vec3 kd; // Diffuse reflectivity + +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( lightPosition ) - pos ); + + // Calculate the vector from the fragment to the eye position + // (origin since this is in "eye" or "camera" space) + vec3 v = normalize( -pos ); + + // Reflect the light beam using the normal at this fragment + vec3 r = reflect( -s, n ); + + // Calculate the diffuse component + float diffuse = max( dot( s, n ), 0.0 ); + + // Calculate the specular component + float specular = 0.0; + if ( dot( s, n ) > 0.0 ) + specular = pow( max( dot( r, v ), 0.0 ), shininess ); + + // Combine the ambient, diffuse and specular contributions + return lightIntensity * ( ka + kd * diffuse + ks * specular ); +} + +void main() +{ + fragColor = vec4( adsModel( position, normalize( normal ) ), 1.0 ); +} diff --git a/examples/qt3d/instanced-arrays-qml/instanced.vert b/examples/qt3d/instanced-arrays-qml/instanced.vert new file mode 100644 index 000000000..6cbab9d40 --- /dev/null +++ b/examples/qt3d/instanced-arrays-qml/instanced.vert @@ -0,0 +1,51 @@ +#version 150 core + +in vec3 vertexPosition; +in vec3 vertexNormal; +in vec3 pos; + +out vec3 position; +out vec3 normal; +out vec3 kd; + +uniform mat4 modelView; +uniform mat3 modelViewNormal; +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() +{ + normal = normalize( modelViewNormal * vertexNormal ); + + vec3 offsetPos = vertexPosition + pos; + position = vec3(modelView * vec4(offsetPos, 1.0)); + + float hue = fract( pos.x / 10.0 ); + float saturation = fract( pos.z / 20.0 ); + kd = hsvToRGB( hue, saturation, 1.0 ); + + gl_Position = mvp * vec4(offsetPos, 1.0); +} diff --git a/examples/qt3d/instanced-arrays-qml/main.cpp b/examples/qt3d/instanced-arrays-qml/main.cpp new file mode 100644 index 000000000..4638d910f --- /dev/null +++ b/examples/qt3d/instanced-arrays-qml/main.cpp @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** 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: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 "instancebuffer.h" +#include <window.h> +#include <Qt3DRenderer/QRenderAspect> +#include <Qt3DInput/QInputAspect> +#include <Qt3DQuick/QQmlAspectEngine> +#include <QtQml> +#include <QGuiApplication> + +int main(int argc, char* argv[]) +{ + QGuiApplication app(argc, argv); + + Window view; + Qt3DCore::Quick::QQmlAspectEngine engine; + + engine.aspectEngine()->registerAspect(new Qt3DRender::QRenderAspect()); + engine.aspectEngine()->registerAspect(new Qt3DInput::QInputAspect()); + engine.aspectEngine()->initialize(); + QVariantMap data; + data.insert(QStringLiteral("surface"), QVariant::fromValue(static_cast<QSurface *>(&view))); + data.insert(QStringLiteral("eventSource"), QVariant::fromValue(&view)); + engine.aspectEngine()->setData(data); + + InstanceBuffer buffer; + engine.qmlEngine()->rootContext()->setContextProperty("_instanceBuffer", &buffer); + + engine.setSource(QUrl("qrc:/main.qml")); + + view.show(); + + return app.exec(); +} diff --git a/examples/qt3d/instanced-arrays-qml/main.qml b/examples/qt3d/instanced-arrays-qml/main.qml new file mode 100644 index 000000000..6f16af66e --- /dev/null +++ b/examples/qt3d/instanced-arrays-qml/main.qml @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** 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: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.Renderer 2.0 +import QtQuick 2.2 as QQ2 + +Entity { + id: sceneRoot + + Camera { + id: camera + projectionType: CameraLens.PerspectiveProjection + fieldOfView: 22.5 + aspectRatio: 16/9 + nearPlane : 0.1 + farPlane : 1000.0 + position: Qt.vector3d(10.0, 7.0, 35.0) + upVector: Qt.vector3d(0.0, 1.0, 0.0) + viewCenter: Qt.vector3d(10.0, 0.5, 0.0) + } + + Configuration { + controlledCamera: camera + } + + components: [ + FrameGraph { + activeFrameGraph: ForwardRenderer { + clearColor: Qt.rgba(0, 0.5, 1, 1) + camera: camera + } + } + ] + + Material { + id: instancedPhongMaterial + effect: Effect { + techniques: Technique { + openGLFilter { + api: OpenGLFilter.Desktop + profile: OpenGLFilter.Core + minorVersion: 2 + majorVersion: 3 + } + renderPasses: RenderPass { + bindings: [ + ParameterMapping { parameterName: "pos"; shaderVariableName: "pos"; bindingType: ParameterMapping.Attribute } + ] + shaderProgram: ShaderProgram { + vertexShaderCode: loadSource("qrc:/instanced.vert") + fragmentShaderCode: loadSource("qrc:/instanced.frag") + } + } + } + } + } + + // Create a GeometryRenderer component that uses the standard CylinderGeometry to + // create the base vertex and index data buffers and attributes. + GeometryRenderer { + id: cylinderMeshInstanced + enabled: instanceCount != 0 + + geometry: CylinderGeometry { + rings: 50 + slices: 30 + radius: 0.3 + length: 3.0 + + attributes: [ instanceDataAttribute ] + } + + // Use our buffer created from C++ as per-instance position data to render + // many instances (copies) of the base cylinder geometry in a single OpenGL + // draw call where supported (OpenGL >=3.3 or OpenGL ES 3). On older versions + // of OpenGL the instancing is emulated on the CPU using multiple draw calls. + QQ2.SequentialAnimation { + running: true + loops: QQ2.Animation.Infinite + + QQ2.NumberAnimation { + target: cylinderMeshInstanced + property: "instanceCount" + duration: 5000 + from: 0 + to: _instanceBuffer.instanceCount + } + + QQ2.PauseAnimation { + duration: 3000 + } + + QQ2.NumberAnimation { + target: cylinderMeshInstanced + property: "instanceCount" + duration: 5000 + from: _instanceBuffer.instanceCount + to: 0 + } + + QQ2.PauseAnimation { + duration: 3000 + } + } + + Attribute { + id: instanceDataAttribute + name: "pos" + attributeType: AbstractAttribute.VertexAttribute + dataType: AbstractAttribute.Float + dataSize: 3 + divisor: 1 + buffer: _instanceBuffer + } + } + + Entity { + id: torusEntity + components: [ cylinderMeshInstanced, instancedPhongMaterial ] + } +} diff --git a/examples/qt3d/qt3d.pro b/examples/qt3d/qt3d.pro index 001729a61..26fbd89a5 100644 --- a/examples/qt3d/qt3d.pro +++ b/examples/qt3d/qt3d.pro @@ -40,7 +40,8 @@ SUBDIRS += \ mouseinput-qml \ custom-mesh-cpp \ bigscene-instanced-qml \ - custom-mesh-qml + custom-mesh-qml \ + instanced-arrays-qml # TODO Port the old examples to new APIs #SUBDIRS += qt3d diff --git a/src/render/geometry/qbuffer.h b/src/render/geometry/qbuffer.h index c2da32fbe..da1e4293f 100644 --- a/src/render/geometry/qbuffer.h +++ b/src/render/geometry/qbuffer.h @@ -85,7 +85,7 @@ public: }; Q_ENUM(UsageType) - QBuffer(BufferType ty = QBuffer::VertexBuffer, Qt3DCore::QNode *parent = 0); + explicit QBuffer(BufferType ty = QBuffer::VertexBuffer, Qt3DCore::QNode *parent = 0); ~QBuffer(); void setUsage(UsageType usage); |