From 2cf01c729ba92ec67474116be5c5c4af0176e8de Mon Sep 17 00:00:00 2001 From: Svenn-Arne Dragly Date: Tue, 21 Mar 2017 11:14:00 +0100 Subject: [PATCH] Add simple example and add README.md --- README.md | 34 ++++++ app/Node.qml | 9 -- examples/examples.pro | 3 +- examples/sharedmaterials/sharedmaterials.pro | 6 - examples/sharednodes/main_sharednodes.qml | 111 ++++++++++++++----- examples/sharednodes/sharednodes.pro | 6 - examples/simple/main_simple.cpp | 20 ++++ examples/simple/main_simple.qml | 75 +++++++++++++ examples/simple/qml.qrc | 5 + examples/simple/simple.pro | 11 ++ src/shaderbuilder.cpp | 12 +- src/shadernode.cpp | 48 ++++++-- src/shadernode.h | 3 + src/shaderuniformvalue.cpp | 10 +- src/shaderuniformvalue.h | 6 +- 15 files changed, 285 insertions(+), 74 deletions(-) create mode 100644 README.md create mode 100644 examples/simple/main_simple.cpp create mode 100644 examples/simple/main_simple.qml create mode 100644 examples/simple/qml.qrc create mode 100644 examples/simple/simple.pro diff --git a/README.md b/README.md new file mode 100644 index 0000000..a62514d --- /dev/null +++ b/README.md @@ -0,0 +1,34 @@ +# ShaderNodes # + +ShaderNodes is a shader generator for Qt3D inspired by material designers found +in 3D software like Blender. +It produces GLSL shaders based on an object graph built in QML or C++. + +Currently, only graphs built in QML are supported. + +The simplest way to use ShaderNodes is to use the ShaderBuilderMaterial. +This can be used directly in place of any Qt3D material: + +```qml +Entity { + components: [ + ShaderBuilderMaterial { + id: material + fragmentColor: StandardMaterial { + color: "green" + normal: Bump { + texture: Noise { + vector: material.fragment.position + } + } + } + }, + SphereMesh { + id: mesh + } + ] +} +``` + +You can also build your own materials by using a ShaderBuilderEffect +or by generating the shader code with ShaderBuilder directly. diff --git a/app/Node.qml b/app/Node.qml index cacf6c8..26957bc 100644 --- a/app/Node.qml +++ b/app/Node.qml @@ -51,12 +51,6 @@ Item { updateHandleConnectionPoints() } - function reloadShaderNode() { -// var tmp = loader.source -// loader.source = "" -// loader.source = tmp - } - function updateHandleConnectionPoints() { for(var i in allHandles) { var handle = allHandles[i] @@ -70,7 +64,6 @@ Item { console.log(handleComponent.errorString()) return } -// var glslType = ShaderNodes.glslType(value) var properties = { name: name, identifier: name, @@ -142,8 +135,6 @@ Item { allHandles = inputHandles.concat(outputHandles) -// object.destroy() - updateHandleConnectionPoints() } diff --git a/examples/examples.pro b/examples/examples.pro index 564d391..0be4b1e 100644 --- a/examples/examples.pro +++ b/examples/examples.pro @@ -2,4 +2,5 @@ TEMPLATE = subdirs SUBDIRS += \ sharedmaterials \ - sharednodes + sharednodes \ + simple diff --git a/examples/sharedmaterials/sharedmaterials.pro b/examples/sharedmaterials/sharedmaterials.pro index dc9168b..386c2cf 100644 --- a/examples/sharedmaterials/sharedmaterials.pro +++ b/examples/sharedmaterials/sharedmaterials.pro @@ -6,10 +6,4 @@ SOURCES += main.cpp RESOURCES += qml.qrc -# Additional import path used to resolve QML modules in Qt Creator's code model -QML_IMPORT_PATH = - -# Default rules for deployment. -include(deployment.pri) - include(../../package_vendor.pri) diff --git a/examples/sharednodes/main_sharednodes.qml b/examples/sharednodes/main_sharednodes.qml index 61b9424..7e33f87 100644 --- a/examples/sharednodes/main_sharednodes.qml +++ b/examples/sharednodes/main_sharednodes.qml @@ -52,18 +52,18 @@ ApplicationWindow { camera: mainCamera } - Entity { - components: [ - mesh, - transform1, - material1 - ] - - Transform { - id: transform1 - translation: Qt.vector3d(-4, 0, 0) - } - } +// Entity { +// components: [ +// mesh, +// transform1, +// material1 +// ] + +// Transform { +// id: transform1 +// translation: Qt.vector3d(-4, 0, 0) +// } +// } Entity { components: [ mesh, @@ -87,27 +87,34 @@ ApplicationWindow { position: Qt.vector3d(0, 4, 4) } - ShaderBuilderMaterial { - id: material1 - - fragmentColor: StandardMaterial { - color: "green" - lights: [ - light1, - light2 - ] - } - } +// ShaderBuilderMaterial { +// id: material1 + +// fragmentColor: StandardMaterial { +// color: "green" +// lights: [ +// light1, +// light2 +// ] +// } +// } ShaderBuilderMaterial { id: material2 - fragmentColor: StandardMaterial { - color: "green" - lights: [ - light1, - light2 - ] +// fragmentColor: StandardMaterial { +// id: standardMaterial2 +// color: "green" +// lights: [ +// light1, +// light2 +// ] +// } + + fragmentColor: Mix { + id: standardMaterial2 + value1: 1.0 + value2: Qt.vector3d(0.1, 0.1, 0.1) } } @@ -123,5 +130,51 @@ ApplicationWindow { value: 0.5 width: 300 } + + Timer { + property ShaderNode node: null + running: true + repeat: true + interval: 60 + onTriggered: { + if(node) { + standardMaterial2.value1 = 2.3 + standardMaterial2.value1 = Qt.vector3d(2.0, 1.0, 2.0) + node.destroy() + node = null + } else { + var object = Qt.createQmlObject("import ShaderNodes 1.0; Mix {}", material2) + standardMaterial2.value1 = object + node = object + } + } + } + +// Timer { +// running: true +// repeat: true +// interval: 100 +// onTriggered: { +// standardMaterial2.value1 = 1.0 +// } +// } + +// Timer { +// running: true +// repeat: true +// interval: 150 +// onTriggered: { +// standardMaterial2.value1 = node +// } +// } + +// Timer { +// running: true +// repeat: true +// interval: 180 +// onTriggered: { +// standardMaterial2.value1 = Qt.vector3d(1.0, 0.5, 0.1) +// } +// } } } diff --git a/examples/sharednodes/sharednodes.pro b/examples/sharednodes/sharednodes.pro index 3db9933..1cf4a30 100644 --- a/examples/sharednodes/sharednodes.pro +++ b/examples/sharednodes/sharednodes.pro @@ -6,10 +6,4 @@ SOURCES += main.cpp RESOURCES += qml.qrc -# Additional import path used to resolve QML modules in Qt Creator's code model -QML_IMPORT_PATH = - -# Default rules for deployment. -include(deployment.pri) - include(../../package_vendor.pri) diff --git a/examples/simple/main_simple.cpp b/examples/simple/main_simple.cpp new file mode 100644 index 0000000..d4d974c --- /dev/null +++ b/examples/simple/main_simple.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + QSurfaceFormat format; + format.setMajorVersion(3); + format.setMinorVersion(3); + QSurfaceFormat::setDefaultFormat(format); + + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QGuiApplication app(argc, argv); + QQmlApplicationEngine engine; + qpm::init(app, engine); + engine.load(QUrl(QStringLiteral("qrc:/main_simple.qml"))); + + return app.exec(); +} diff --git a/examples/simple/main_simple.qml b/examples/simple/main_simple.qml new file mode 100644 index 0000000..3b4ab40 --- /dev/null +++ b/examples/simple/main_simple.qml @@ -0,0 +1,75 @@ +import QtQuick 2.7 +import QtQuick.Controls 1.0 as QQC1 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.0 + +import QtQuick.Scene3D 2.0 + +import Qt3D.Core 2.0 +import Qt3D.Extras 2.0 +import Qt3D.Input 2.0 +import Qt3D.Logic 2.0 +import Qt3D.Render 2.0 + +import ShaderNodes 1.0 + +ApplicationWindow { + id: window + + visible: true + width: 1280 + height: 1024 + title: qsTr("Simple example") + + Scene3D { + id: root + + anchors.fill: parent + + aspects: ["logic", "input"] + Entity { + components: [ + RenderSettings{ + activeFrameGraph: ForwardRenderer { + camera: Camera { + id: mainCamera + projectionType: CameraLens.PerspectiveProjection + fieldOfView: 50 + aspectRatio: root.width / root.height + nearPlane: 1.0 + farPlane: 100.0 + position: Qt.vector3d(8, 4, 8) + viewCenter: Qt.vector3d(0, 0, 0) + upVector: Qt.vector3d(0.0, 1.0, 0.0) + } + clearColor: Qt.rgba(0.2, 0.2, 0.2) + } + }, + InputSettings {} + ] + + OrbitCameraController { + camera: mainCamera + } + + Entity { + components: [ + ShaderBuilderMaterial { + id: material + fragmentColor: StandardMaterial { + color: "green" + normal: Bump { + texture: Noise { + vector: material.fragment.position + } + } + } + }, + SphereMesh { + id: mesh + } + ] + } + } + } +} diff --git a/examples/simple/qml.qrc b/examples/simple/qml.qrc new file mode 100644 index 0000000..317c973 --- /dev/null +++ b/examples/simple/qml.qrc @@ -0,0 +1,5 @@ + + + main_simple.qml + + diff --git a/examples/simple/simple.pro b/examples/simple/simple.pro new file mode 100644 index 0000000..7501563 --- /dev/null +++ b/examples/simple/simple.pro @@ -0,0 +1,11 @@ +TEMPLATE = app + +QT += qml quick +CONFIG += c++11 + +SOURCES += \ + main_simple.cpp + +RESOURCES += qml.qrc + +include(../../package_vendor.pri) diff --git a/src/shaderbuilder.cpp b/src/shaderbuilder.cpp index fa9a8e4..8d9672d 100644 --- a/src/shaderbuilder.cpp +++ b/src/shaderbuilder.cpp @@ -47,12 +47,12 @@ void ShaderBuilder::clear() m_renderPass->removeParameter(uniform->m_parameter); } } + m_uniforms.clear(); disconnectDependencies(); m_dependencies.clear(); - m_uniforms.clear(); m_finalShader = ""; } @@ -194,14 +194,16 @@ void ShaderBuilder::rebuildShader() connect(node, &ShaderNode::identifierChanged, this, &ShaderBuilder::markDirty); connect(node, &ShaderNode::propertyTypeChanged, this, &ShaderBuilder::markDirty); connect(node, &ShaderNode::markDirty, this, &ShaderBuilder::markDirty); - } - if(m_renderPass) { - for(const ShaderUniformValue *uniform : m_uniforms) { - m_renderPass->addParameter(uniform->m_parameter); + if(m_renderPass) { + for(ShaderUniformValue *uniform : node->m_uniforms) { + m_uniforms.append(uniform); + m_renderPass->addParameter(uniform->m_parameter); + } } } + QString header = ""; header += "\n// ------ begin generated header ------\n\n"; for(ShaderOutput *output : m_outputs) { diff --git a/src/shadernode.cpp b/src/shadernode.cpp index 25eca20..f3ea4f1 100644 --- a/src/shadernode.cpp +++ b/src/shadernode.cpp @@ -13,7 +13,27 @@ #include #include -const QStringList builtinNames = QStringList{"objectName","parent","enabled","name","type","result","source","header","identifier","headerFile","requirement","dependencies","data","childNodes","exportedTypeName","arrayProperties", "headerFiles"}; +const QStringList builtinNames = QStringList{ + "objectName", + "parent", + "enabled", + "name", + "type", + "result", + "source", + "header", + "identifier", + "headerFile", + "requirement", + "dependencies", + "data", + "childNodes", + "exportedTypeName", + "arrayProperties", + "headerFiles", + "propertyTrackMode", + "trackedProperties" + }; ShaderNode::ShaderNode(Qt3DCore::QNode *parent) : Qt3DCore::QNode(parent) @@ -138,7 +158,7 @@ QString ShaderNode::createUniform(const QString &propertyName, const QVariant &v QString uniformPrefix = "node_uniform"; QString targetIdentifier = uniformPrefix + "_" + propertyNameNoUnderscores + "_" + ShaderUtils::generateName(); - ShaderUniformValue *uniform = new ShaderUniformValue(this, propertyName, targetIdentifier, value); + ShaderUniformValue *uniform = new ShaderUniformValue(propertyName, targetIdentifier, value, this); if(!metaProperty.hasNotifySignal()) { qWarning() << "WARNING: ShaderBuilder::addUniform(): Property" << propertyName << "on" << name() @@ -150,7 +170,7 @@ QString ShaderNode::createUniform(const QString &propertyName, const QVariant &v m_uniforms.append(uniform); - shaderBuilder->addUniform(uniform); +// shaderBuilder->addUniform(uniform); return targetIdentifier; } @@ -182,8 +202,22 @@ ShaderNodeSetupResult ShaderNode::setup(ShaderBuilder* shaderBuilder, QString te sourceContent += currentIdentifier + " = " + m_result + ";\n"; } + // Cleanup + qDeleteAll(m_uniforms); + m_uniforms.clear(); + m_resolvedDependencies.clear(); + // TODO old signal mappers need to be deleted at some point + for(QSignalMapper *mapper : m_signalMappers) { + disconnect(this, 0, mapper, SLOT(map())); + disconnect(mapper, SIGNAL(mapped(int)), this, SLOT(handlePropertyChange(int))); + mapper->deleteLater(); + } + m_signalMappers.clear(); + + // End cleanup + for(ShaderNode *dependency : m_declaredDependencies) { if(dependency == this) { continue; @@ -196,14 +230,6 @@ ShaderNodeSetupResult ShaderNode::setup(ShaderBuilder* shaderBuilder, QString te m_resolvedDependencies.unite(dependencySetup.m_dependencies); } - // TODO old signal mappers need to be deleted at some point - for(QSignalMapper *mapper : m_signalMappers) { - disconnect(this, 0, mapper, SLOT(map())); - disconnect(mapper, SIGNAL(mapped(int)), this, SLOT(handlePropertyChange(int))); - mapper->deleteLater(); - } - m_signalMappers.clear(); - QStringList propertiesInSource; // matches '$property' or '$(property, type)' QRegularExpression propertyRegex("\\$(?:\\(\\s*)?([_a-zA-Z0-9]+)\\s*\\)?(?:\\s*,\\s*([_a-zA-Z0-9]+)\\s*\\))?"); diff --git a/src/shadernode.h b/src/shadernode.h index d0d5c4e..592c22e 100644 --- a/src/shadernode.h +++ b/src/shadernode.h @@ -75,6 +75,7 @@ class ShaderNode : public Qt3DCore::QNode QStringList arrayProperties() const; QList headerFiles() const; QVector parameters() const; + QMutex m_mutex; signals: void nameChanged(QString name); @@ -137,6 +138,8 @@ private slots: QString createUniform(const QString &propertyName, const QVariant &value, ShaderBuilder *shaderBuilder); QStringList m_arrayProperties; QList m_headerFiles; + + friend class ShaderBuilder; }; #endif // SHADERNODE_H diff --git a/src/shaderuniformvalue.cpp b/src/shaderuniformvalue.cpp index ca74124..df18af2 100644 --- a/src/shaderuniformvalue.cpp +++ b/src/shaderuniformvalue.cpp @@ -3,17 +3,19 @@ #include "shaderutils.h" #include "shadernode.h" -ShaderUniformValue::ShaderUniformValue(ShaderNode *parent, - const QString &propertyName, +#include + +ShaderUniformValue::ShaderUniformValue(const QString &propertyName, const QString &identifier, - const QVariant &value) + const QVariant &value, + ShaderNode *parent) : Qt3DCore::QNode(parent) , m_node(parent) , m_propertyName(propertyName) , m_identifier(identifier) , m_value(value) , m_type(ShaderUtils::glslType(m_value)) - , m_parameter(new Qt3DRender::QParameter(identifier, value, this)) + , m_parameter(new Qt3DRender::QParameter(identifier, value)) { } diff --git a/src/shaderuniformvalue.h b/src/shaderuniformvalue.h index a861da6..921c2a2 100644 --- a/src/shaderuniformvalue.h +++ b/src/shaderuniformvalue.h @@ -10,10 +10,10 @@ class ShaderUniformValue : public Qt3DCore::QNode { Q_OBJECT public: - explicit ShaderUniformValue(ShaderNode* parent, - const QString& propertyName, + explicit ShaderUniformValue(const QString& propertyName, const QString& identifier, - const QVariant& value); + const QVariant& value, + ShaderNode* parent); public: ShaderNode *m_node;