diff options
author | Laszlo Agocs <laszlo.agocs@qt.io> | 2018-01-08 13:56:15 +0100 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@qt.io> | 2018-01-10 12:28:20 +0000 |
commit | 9dcbce5bfe4977a65b21e5eb593878cc14db8252 (patch) | |
tree | 570be05ded5f51dd50d3e6babe7516b99cfd8980 | |
parent | 409d4273f15643aa440ef1f4a6b2dc83bdbdb531 (diff) |
Post-processing effect plumbing
Can run (no animation yet) simple single-pass effects like sepia.
Task-number: QT3DS-793
Change-Id: I7eae7ee4c4f43363a54141a1b3bbb61126ec6e54
Reviewed-by: Andy Nichols <andy.nichols@qt.io>
-rw-r--r-- | res/effectlib/effect.glsllib | 16 | ||||
-rw-r--r-- | src/runtime/q3dseffect.cpp | 44 | ||||
-rw-r--r-- | src/runtime/q3dseffect.h | 2 | ||||
-rw-r--r-- | src/runtime/q3dsmaterial.cpp | 11 | ||||
-rw-r--r-- | src/runtime/q3dsscenemanager.cpp | 286 | ||||
-rw-r--r-- | src/runtime/q3dsscenemanager.h | 52 | ||||
-rw-r--r-- | src/runtime/shadergenerator/q3dsshadermanager.cpp | 22 | ||||
-rw-r--r-- | src/runtime/shadergenerator/q3dsshadermanager_p.h | 5 |
8 files changed, 376 insertions, 62 deletions
diff --git a/res/effectlib/effect.glsllib b/res/effectlib/effect.glsllib index 802a846..087afe1 100644 --- a/res/effectlib/effect.glsllib +++ b/res/effectlib/effect.glsllib @@ -79,11 +79,12 @@ vec4 GetTextureValuePreMult( sampler2D sampler, vec2 inUVCoords ) #ifdef VERTEX_SHADER // Attributes and uniforms used throughout the system. -attribute vec3 attr_pos; -attribute vec2 attr_uv; +// NB! Matches Qt3D. +attribute vec3 vertexPosition; +attribute vec2 vertexTexCoord; +uniform mat4 modelMatrix; #endif -uniform mat4 ModelViewProjectionMatrix; //x holds the texture width, y holds the texture height //z holds 0,1 value if it should be premultiplied uniform vec4 Texture0Info; @@ -92,11 +93,6 @@ uniform sampler2D Texture0; varying vec2 TexCoord; uniform vec2 FragColorAlphaSettings; //x > 0.0 premultiply result, y is an alpha multiplier (opacity setting) -vec4 Transform( mat4 ModelViewProjectionMatrix, vec2 inDestSize, vec4 inVertex ) -{ - vec4 temp = ModelViewProjectionMatrix * vec4( inDestSize.x * .5 * inVertex.x, inDestSize.y * .5 * inVertex.y, inVertex.z, inVertex.w ); - return temp; -} //////////////////////////////////////////////////////////// // provide the texture lookup functions for the default // texture (Texture0). @@ -127,8 +123,8 @@ void colorOutput(vec4 c) void vert(); void main() { - gl_Position = Transform( ModelViewProjectionMatrix, DestSize, vec4(attr_pos, 1.0) ); - TexCoord = attr_uv; + gl_Position = modelMatrix * vec4(vertexPosition, 1.0); + TexCoord = vertexTexCoord; vert(); } diff --git a/src/runtime/q3dseffect.cpp b/src/runtime/q3dseffect.cpp index 17a2507..c037020 100644 --- a/src/runtime/q3dseffect.cpp +++ b/src/runtime/q3dseffect.cpp @@ -62,6 +62,50 @@ const QVector<Q3DSMaterial::Pass> &Q3DSEffect::passes() const return m_passes; } +QString Q3DSEffect::addPropertyUniforms(const QString &shaderSrc) const +{ + QString s; + + auto addUniform = [&s](const char *type, const QString &name) { + s += QLatin1String("uniform ") + QString::fromUtf8(type) + QLatin1Char(' ') + name + QLatin1String(";\n"); + }; + + for (const Q3DSMaterial::PropertyElement &prop : m_properties) { + switch (prop.type) { + case Q3DS::Float: + addUniform("float", prop.name); + break; + case Q3DS::Boolean: + addUniform("bool", prop.name); + break; + case Q3DS::Long: + addUniform("int", prop.name); + break; + case Q3DS::Float2: + addUniform("vec2", prop.name); + break; + case Q3DS::Vector: + case Q3DS::Scale: + case Q3DS::Rotation: + case Q3DS::Color: + addUniform("vec3", prop.name); + break; + case Q3DS::Texture: + addUniform("sampler2D", prop.name); + break; + + // ### there could be more that needs handling here (Buffer?) + + default: + qWarning("Effect property %s has unsupported type; ignored", qPrintable(prop.name)); + break; + } + } + + s += shaderSrc; + return s; +} + Q3DSEffect Q3DSEffectParser::parse(const QString &filename, bool *ok) { if (!setSource(filename)) { diff --git a/src/runtime/q3dseffect.h b/src/runtime/q3dseffect.h index ce9b9fc..6bb0246 100644 --- a/src/runtime/q3dseffect.h +++ b/src/runtime/q3dseffect.h @@ -46,6 +46,8 @@ public: const QMap<QString, Q3DSMaterial::PassBuffer>& buffers() const; const QVector<Q3DSMaterial::Pass> &passes() const; + QString addPropertyUniforms(const QString &shaderSrc) const; + private: QMap<QString, Q3DSMaterial::PropertyElement> m_properties; diff --git a/src/runtime/q3dsmaterial.cpp b/src/runtime/q3dsmaterial.cpp index c3ca4e4..cb90c0b 100644 --- a/src/runtime/q3dsmaterial.cpp +++ b/src/runtime/q3dsmaterial.cpp @@ -331,15 +331,11 @@ Shader parserShaderElement(QXmlStreamReader *r) } else if (r->name() == QStringLiteral("VertexShader")) { if ( r->readNext() == QXmlStreamReader::Characters) { shader.vertexShader = r->text().toString().trimmed(); - if (shader.vertexShader.isEmpty()) - shader.vertexShader = QLatin1String("void vert(){}\n"); r->skipCurrentElement(); } } else if (r->name() == QStringLiteral("FragmentShader")) { if ( r->readNext() == QXmlStreamReader::Characters) { shader.fragmentShader = r->text().toString().trimmed(); - if (shader.fragmentShader.isEmpty()) - shader.fragmentShader = QLatin1String("void frag(){}\n"); r->skipCurrentElement(); } } else if (r->name() == QStringLiteral("GeometryShader")) { @@ -351,6 +347,13 @@ Shader parserShaderElement(QXmlStreamReader *r) r->skipCurrentElement(); } } + + if (shader.vertexShader.isEmpty()) + shader.vertexShader = QLatin1String("void vert(){}\n"); + + if (shader.fragmentShader.isEmpty()) + shader.fragmentShader = QLatin1String("void frag(){}\n"); + return shader; } diff --git a/src/runtime/q3dsscenemanager.cpp b/src/runtime/q3dsscenemanager.cpp index 07ce181..d5a5c22 100644 --- a/src/runtime/q3dsscenemanager.cpp +++ b/src/runtime/q3dsscenemanager.cpp @@ -262,6 +262,23 @@ Q_LOGGING_CATEGORY(lcScene, "q3ds.scene") } } } + + // 6. Post-processing effect passes + FrameGraphNode { + NoDraw { } [so that the rest below can be added/deleted dynamically] + // effect 1 pass 1 + RenderTargetSelector { + // input is either layerTexture or the output of another pass + // output is either effLayerTexture or one of the intermediate textures + [BlitFramebuffer - NoDraw] ... // from BufferBlit commands or to resolve samples when layer is MSAA + LayerFilter { + layers: [ layer1_eff1_pass1_quad_tag ] + // said quad has a single renderpass with the desired material and render states + } + } + // effect 1 pass 2, ..., effect 2 pass 1, etc. + ... + } } } } } @@ -662,7 +679,7 @@ Q3DSSceneManager::Scene Q3DSSceneManager::buildScene(Q3DSPresentation *presentat } fsQuadPassNames << QLatin1String("ssao") << QLatin1String("progaa"); fsQuadPassProgs << sm.getSsaoTextureShader(m_rootEntity) << sm.getProgAABlendShader(m_rootEntity); - buildFsQuad(m_rootEntity, fsQuadPassNames, fsQuadPassProgs, m_fsQuadTag); + buildFsQuad(m_rootEntity, fsQuadPassNames, fsQuadPassProgs, m_fsQuadTag, {}); Scene sc; sc.rootEntity = m_rootEntity; @@ -979,6 +996,10 @@ void Q3DSSceneManager::buildLayer(Q3DSLayerNode *layer3DS, if (transparentPassOnly) transLayerFilter->addLayer(opaqueTag); + // Post-processing effect passes + Qt3DRender::QFrameGraphNode *effectRoot = new Qt3DRender::QFrameGraphNode(mainTechniqueSelector); + new Qt3DRender::QNoDraw(effectRoot); + Q3DSLayerAttached *data = new Q3DSLayerAttached; data->entity = m_rootEntity; // must set an entity to to make Q3DSLayerNode properties animatable, just use the root data->layer3DS = layer3DS; @@ -1003,6 +1024,7 @@ void Q3DSSceneManager::buildLayer(Q3DSLayerNode *layer3DS, data->depthTextureData.rtSelector = depthRtSelector; data->ssaoTextureData.rtSelector = ssaoRtSelector; data->shadowMapData.shadowRoot = shadowRoot; + data->effectData.effectRoot = effectRoot; // textures that are resized automatically to match the layer's dimensions data->sizeManagedTextures << colorTex << dsTexOrRb; @@ -1051,6 +1073,9 @@ void Q3DSSceneManager::buildLayer(Q3DSLayerNode *layer3DS, [this](Q3DSModelNode *model3DS) { buildModelMaterial(model3DS); }, true); // include hidden ones too + // Set up effects. + finalizeEffects(layer3DS); + // Make sure the QCamera we will use is parented correctly. reparentCamera(layer3DS); } @@ -2474,7 +2499,7 @@ void Q3DSSceneManager::updateProgressiveAA(Q3DSLayerNode *layer3DS) if (data->progAA.enabled) { qCDebug(lcScene, "Stopping progressive AA for layer %s", layer3DS->id().constData()); data->progAA.enabled = false; - data->compositorSourceParam->setValue(QVariant::fromValue(data->layerTexture)); + data->compositorSourceParam->setValue(QVariant::fromValue(data->effLayerTexture ? data->effLayerTexture : data->layerTexture)); // Do not delete and then recreate the framegraph subtree since // that is likely way too expensive. Keep it around instead and @@ -2554,6 +2579,8 @@ void Q3DSSceneManager::updateProgressiveAA(Q3DSLayerNode *layer3DS) // ### what if data->layerTexture is multisample? + // ### all the below stuff does not yet handle data->effLayerTexture + // For data->progAA.accumTex there is no new texture needed - instead, // steal data->layerTexture. if (factorsIdx == 0) { @@ -2654,15 +2681,6 @@ void Q3DSSceneManager::updateProgressiveAA(Q3DSLayerNode *layer3DS) ++data->progAA.pass; } -void Q3DSSceneManager::buildEffect(Q3DSEffectInstance *eff3DS, Q3DSLayerNode *layer3DS) -{ - Q3DSLayerAttached *layerData = static_cast<Q3DSLayerAttached *>(layer3DS->attached()); - Q3DSEffectAttached *effData = new Q3DSEffectAttached; - effData->entity = layerData->entity; - eff3DS->setAttached(effData); - layerData->effects.append(eff3DS); -} - static void setLayerBlending(Qt3DRender::QBlendEquation *blendFunc, Qt3DRender::QBlendEquationArguments *blendArgs, Q3DSLayerNode *layer3DS) @@ -2976,7 +2994,7 @@ void Q3DSSceneManager::buildCompositor(Qt3DRender::QFrameGraphNode *parent, Qt3D baseLayerParam->setValue(QVariant::fromValue(data->advBlend.tempTexture)); Qt3DRender::QParameter *blendLayerParam = new Qt3DRender::QParameter; blendLayerParam->setName(QLatin1String("blend_layer")); - blendLayerParam->setValue(QVariant::fromValue(data->layerTexture)); + blendLayerParam->setValue(QVariant::fromValue(data->effLayerTexture ? data->effLayerTexture : data->layerTexture)); renderPass->addParameter(baseLayerParam); renderPass->addParameter(blendLayerParam); } else { @@ -3035,7 +3053,8 @@ void Q3DSSceneManager::buildGuiPass(Qt3DRender::QFrameGraphNode *parent, Qt3DCor void Q3DSSceneManager::buildFsQuad(Qt3DCore::QEntity *parentEntity, const QStringList &passNames, const QVector<Qt3DRender::QShaderProgram *> &passProgs, - Qt3DRender::QLayer *tag) + Qt3DRender::QLayer *tag, + const QVector<Qt3DRender::QParameter *> ¶ms) { Qt3DCore::QEntity *fsQuadEntity = new Qt3DCore::QEntity(parentEntity); fsQuadEntity->setObjectName(QObject::tr("fullscreen quad")); @@ -3067,6 +3086,9 @@ void Q3DSSceneManager::buildFsQuad(Qt3DCore::QEntity *parentEntity, pass->setShaderProgram(passProgs[i]); + for (Qt3DRender::QParameter *param : params) + pass->addParameter(param); + technique->addRenderPass(pass); } @@ -4136,12 +4158,12 @@ void Q3DSSceneManager::updateDefaultMaterial(Q3DSDefaultMaterial *m) updateTextureParameters(data->translucencyMapParams, m->translucencyMap()); } -typedef std::function<void(const QString &, const QVariant &, const Q3DSMaterial::PropertyElement &)> CustomMaterialPropertyCallback; +typedef std::function<void(const QString &, const QVariant &, const Q3DSMaterial::PropertyElement &)> CustomPropertyCallback; -static void forAllCustomMaterialProperties(Q3DSCustomMaterialInstance *m, CustomMaterialPropertyCallback callback) +static void iterateCustomProperties(const QVariantMap *properties, + const QMap<QString, Q3DSMaterial::PropertyElement> &propertiesMeta, + CustomPropertyCallback callback) { - const QVariantMap *properties = m->materialPropertyValues(); - const QMap<QString, Q3DSMaterial::PropertyElement> &propertiesMeta(m->material()->properties()); for (auto it = properties->cbegin(), itEnd = properties->cend(); it != itEnd; ++it) { const QString &propName(it.key()); const QVariant &propValue(it.value()); @@ -4150,16 +4172,32 @@ static void forAllCustomMaterialProperties(Q3DSCustomMaterialInstance *m, Custom } } -Qt3DRender::QAbstractTexture *Q3DSSceneManager::createCustomMaterialTexture(const Q3DSCustomMaterialAttached::Parameter &p) +static inline void forAllCustomProperties(Q3DSCustomMaterialInstance *m, CustomPropertyCallback callback) +{ + iterateCustomProperties(m->materialPropertyValues(), m->material()->properties(), callback); +} + +static inline void forAllCustomProperties(Q3DSEffectInstance *eff3DS, CustomPropertyCallback callback) +{ + iterateCustomProperties(eff3DS->effectPropertyValues(), eff3DS->effect()->properties(), callback); +} + +Qt3DRender::QAbstractTexture *Q3DSSceneManager::createCustomPropertyTexture(const Q3DSCustomPropertyParameter &p) { const QString source = p.inputValue.toString(); - qCDebug(lcScene, "Creating custom material texture %s", qPrintable(source)); Qt3DRender::QTexture2D *texture = new Qt3DRender::QTexture2D(m_rootEntity); - m_profiler->trackNewObject(texture, Q3DSProfiler::Texture2DObject, - "Custom material texture %s", qPrintable(source)); - Qt3DRender::QTextureImage *textureImage = new Qt3DRender::QTextureImage; - textureImage->setSource(QUrl::fromLocalFile(source)); - texture->addTextureImage(textureImage); + if (!source.isEmpty()) { + qCDebug(lcScene, "Creating custom property texture %s", qPrintable(source)); + m_profiler->trackNewObject(texture, Q3DSProfiler::Texture2DObject, + "Custom property texture %s", qPrintable(source)); + Qt3DRender::QTextureImage *textureImage = new Qt3DRender::QTextureImage; + textureImage->setSource(QUrl::fromLocalFile(source)); + texture->addTextureImage(textureImage); + } else { + qCDebug(lcScene, "Creating intermediate custom property texture for property %s", qPrintable(p.meta.name)); + m_profiler->trackNewObject(texture, Q3DSProfiler::Texture2DObject, + "Intermediate texture for custom property %s", qPrintable(p.meta.name)); + } switch (p.meta.magFilterType) { case Q3DSMaterial::Nearest: @@ -4224,13 +4262,13 @@ QVector<Qt3DRender::QParameter *> Q3DSSceneManager::prepareCustomMaterial(Q3DSCu // Generate QParameters QVector<Qt3DRender::QParameter *> paramList; - forAllCustomMaterialProperties(m, [¶mList, data](const QString &propKey, const QVariant &, const Q3DSMaterial::PropertyElement &propMeta) { + forAllCustomProperties(m, [¶mList, data](const QString &propKey, const QVariant &, const Q3DSMaterial::PropertyElement &propMeta) { QVariant v(0); // initial value is something dummy, ignore propValue for now Qt3DRender::QParameter *param = new Qt3DRender::QParameter; param->setName(propKey); param->setValue(v); paramList.append(param); - data->params.insert(propKey, Q3DSCustomMaterialAttached::Parameter(param, v, propMeta)); + data->params.insert(propKey, Q3DSCustomPropertyParameter(param, v, propMeta)); }); return paramList; @@ -4241,11 +4279,11 @@ void Q3DSSceneManager::updateCustomMaterial(Q3DSCustomMaterialInstance *m) Q3DSCustomMaterialAttached *data = static_cast<Q3DSCustomMaterialAttached *>(m->attached()); // set all dynamic property values to the corresponding QParameters - forAllCustomMaterialProperties(m, [data, this](const QString &propKey, const QVariant &propValue, const Q3DSMaterial::PropertyElement &) { + forAllCustomProperties(m, [data, this](const QString &propKey, const QVariant &propValue, const Q3DSMaterial::PropertyElement &) { if (!data->params.contains(propKey)) // we do not currently support new dynamic properties appearing out of nowhere return; - Q3DSCustomMaterialAttached::Parameter &p(data->params[propKey]); + Q3DSCustomPropertyParameter &p(data->params[propKey]); if (propValue == p.inputValue) return; @@ -4256,7 +4294,7 @@ void Q3DSSceneManager::updateCustomMaterial(Q3DSCustomMaterialInstance *m) // point whereas we need a proper Qt 3D texture. switch (p.meta.type) { case Q3DS::Texture: - p.param->setValue(QVariant::fromValue(createCustomMaterialTexture(p))); + p.param->setValue(QVariant::fromValue(createCustomPropertyTexture(p))); break; // Buffer, Image2D, etc. are not used for custom materials @@ -4268,6 +4306,196 @@ void Q3DSSceneManager::updateCustomMaterial(Q3DSCustomMaterialInstance *m) }); } +void Q3DSSceneManager::buildEffect(Q3DSEffectInstance *eff3DS, Q3DSLayerNode *layer3DS) +{ + Q3DSLayerAttached *layerData = static_cast<Q3DSLayerAttached *>(layer3DS->attached()); + Q3DSEffectAttached *effData = new Q3DSEffectAttached; + effData->entity = layerData->entity; + effData->layer3DS = layer3DS; + eff3DS->setAttached(effData); + layerData->effectData.effects.append(eff3DS); + + if (!layerData->effLayerTexture) { + const QSize sz = safeLayerPixelSize(layerData); + layerData->effLayerTexture = newColorBuffer(sz, layerData->msaaSampleCount); + m_profiler->trackNewObject(layerData->effLayerTexture, Q3DSProfiler::Texture2DObject, + "Effect buffer for layer %s", layer3DS->id().constData()); + layerData->sizeManagedTextures.append(layerData->effLayerTexture); + } +} + +void Q3DSSceneManager::finalizeEffects(Q3DSLayerNode *layer3DS) +{ + Q3DSLayerAttached *layerData = static_cast<Q3DSLayerAttached *>(layer3DS->attached()); + if (layerData->effectData.effects.isEmpty()) + return; + + for (Q3DSEffectInstance *eff3DS : layerData->effectData.effects) { + Q3DSEffectAttached *effData = static_cast<Q3DSEffectAttached *>(eff3DS->attached()); + qCDebug(lcScene, "Applying post-processing effect %s to layer %s", + eff3DS->id().constData(), layer3DS->id().constData()); + const Q3DSEffect *effDesc = eff3DS->effect(); + if (effDesc->passes().isEmpty()) { + qWarning("Effect %s: No passes; effect ignored", eff3DS->id().constData()); + continue; + } + + QVector<Qt3DRender::QParameter *> paramList; + + // Create QParameters for built-in uniforms (see effect.glsllib). + effData->texture0Param = new Qt3DRender::QParameter; + effData->texture0Param->setName(QLatin1String("Texture0")); + paramList.append(effData->texture0Param); + + effData->texture0InfoParam = new Qt3DRender::QParameter; + effData->texture0InfoParam->setName(QLatin1String("Texture0Info")); + paramList.append(effData->texture0InfoParam); + + effData->fragColorAlphaParam = new Qt3DRender::QParameter; + effData->fragColorAlphaParam->setName(QLatin1String("FragColorAlphaSettings")); + paramList.append(effData->fragColorAlphaParam); + + effData->destSizeParam = new Qt3DRender::QParameter; + effData->destSizeParam->setName(QLatin1String("DestSize")); + paramList.append(effData->destSizeParam); + + // Create QParameters for custom properties. + forAllCustomProperties(eff3DS, [¶mList, effData](const QString &propKey, const QVariant &, const Q3DSMaterial::PropertyElement &propMeta) { + Qt3DRender::QParameter *param = new Qt3DRender::QParameter; + param->setName(propKey); + paramList.append(param); + effData->params.insert(propKey, Q3DSCustomPropertyParameter(param, QVariant(), propMeta)); + }); + + // Update QParameter values. + updateEffect(eff3DS); + + const QMap<QString, Q3DSMaterial::Shader> &shaderPrograms = effDesc->shaders(); + const QMap<QString, Q3DSMaterial::PassBuffer> &buffers = effDesc->buffers(); + + // Each pass leads to creating a new framegraph subtree parented to effectRoot. + for (const Q3DSMaterial::Pass &pass : effDesc->passes()) { + if (!shaderPrograms.contains(pass.shaderName)) { + qWarning("Effect %s: Unknown shader program %s; pass ignored", + eff3DS->id().constData(), qPrintable(pass.shaderName)); + continue; + } + qCDebug(lcScene, " Registered pass with shader program %s input %s output %s %d extra commands", + qPrintable(pass.shaderName), qPrintable(pass.input), qPrintable(pass.output), pass.commands.count()); + for (const Q3DSMaterial::PassCommand &cmd : pass.commands) { + switch (cmd.type()) { + case Q3DSMaterial::PassCommand::BufferInputType: + { + const QString bufferName = cmd.data()->value; + if (buffers.contains(bufferName)) { + // ### + } else { + qWarning("Effect %s: Unknown buffer %s", eff3DS->id().constData(), qPrintable(bufferName)); + } + } + break; + // ### + default: + break; + } + } + + Qt3DRender::QAbstractTexture *passInput = nullptr; + Qt3DRender::QAbstractTexture *passOutput = nullptr; + if (pass.input == QStringLiteral("[source]")) { + passInput = layerData->layerTexture; + } else { + if (buffers.contains(pass.input)) { + // ### + } else { + qWarning("Effect %s: Unknown input buffer %s; pass ignored", + eff3DS->id().constData(), qPrintable(pass.input)); + continue; + } + } + if (pass.output == QStringLiteral("[dest]")) { + passOutput = layerData->effLayerTexture; + } else { + if (buffers.contains(pass.output)) { + // ### + } else { + qWarning("Effect %s: Unknown output buffer %s; pass ignored", + eff3DS->id().constData(), qPrintable(pass.output)); + continue; + } + } + Q_ASSERT(passInput && passOutput); + + const Q3DSMaterial::Shader &shaderProgram(shaderPrograms.value(pass.shaderName)); + const QString decoratedShaderName = QString::fromUtf8(eff3DS->id()) + QLatin1Char('_') + pass.shaderName; + const QString decoratedVertexShader = effDesc->addPropertyUniforms(shaderProgram.vertexShader); + const QString decoratedFragmentShader = effDesc->addPropertyUniforms(shaderProgram.fragmentShader); + Qt3DRender::QShaderProgram *prog = Q3DSShaderManager::instance().getEffectShader(m_rootEntity, + decoratedShaderName, + decoratedVertexShader, + decoratedFragmentShader); + + effData->quadEntityTag = new Qt3DRender::QLayer; + buildFsQuad(m_rootEntity, { QLatin1String("eff") }, { prog }, effData->quadEntityTag, paramList); + + Qt3DRender::QRenderTargetSelector *rtSel = new Qt3DRender::QRenderTargetSelector(layerData->effectData.effectRoot); + Qt3DRender::QRenderTarget *rt = new Qt3DRender::QRenderTarget; + Qt3DRender::QRenderTargetOutput *color = new Qt3DRender::QRenderTargetOutput; + color->setAttachmentPoint(Qt3DRender::QRenderTargetOutput::Color0); + color->setTexture(layerData->effLayerTexture); + rt->addOutput(color); + rtSel->setTarget(rt); + + Qt3DRender::QClearBuffers *clearBuf = new Qt3DRender::QClearBuffers(rtSel); + clearBuf->setBuffers(Qt3DRender::QClearBuffers::ColorBuffer); + + Qt3DRender::QLayerFilter *layerFilter = new Qt3DRender::QLayerFilter(clearBuf); + layerFilter->addLayer(effData->quadEntityTag); + } + } + + // The layer compositor must use the output of the effect passes from now on. + layerData->compositorSourceParam->setValue(QVariant::fromValue(layerData->effLayerTexture)); +} + +void Q3DSSceneManager::updateEffect(Q3DSEffectInstance *eff3DS) +{ + Q3DSEffectAttached *effData = static_cast<Q3DSEffectAttached *>(eff3DS->attached()); + Q3DSLayerAttached *layerData = static_cast<Q3DSLayerAttached *>(effData->layer3DS->attached()); + + effData->texture0Param->setValue(QVariant::fromValue(layerData->layerTexture)); + effData->texture0InfoParam->setValue(QVector4D(layerData->layerTexture->width(), + layerData->layerTexture->height(), + 0, // ### isPremultiplied? + 0)); + effData->fragColorAlphaParam->setValue(QVector2D(1.0f, 0.0f)); + effData->destSizeParam->setValue(QVector2D(layerData->effLayerTexture->width(), + layerData->effLayerTexture->height())); + + forAllCustomProperties(eff3DS, [effData, this](const QString &propKey, const QVariant &propValue, const Q3DSMaterial::PropertyElement &) { + if (!effData->params.contains(propKey)) + return; + + Q3DSCustomPropertyParameter &p(effData->params[propKey]); + if (propValue == p.inputValue) + return; + + p.inputValue = propValue; + + switch (p.meta.type) { + case Q3DS::Texture: + p.param->setValue(QVariant::fromValue(createCustomPropertyTexture(p))); + break; + + // ### others? + + default: + p.param->setValue(p.inputValue); + break; + } + }); +} + void Q3DSSceneManager::gatherLights(Q3DSGraphObject *root, QVector<Q3DSLightSource> *allLights, QVector<Q3DSLightSource> *nonAreaLights, diff --git a/src/runtime/q3dsscenemanager.h b/src/runtime/q3dsscenemanager.h index 1cbef91..70b889f 100644 --- a/src/runtime/q3dsscenemanager.h +++ b/src/runtime/q3dsscenemanager.h @@ -183,6 +183,7 @@ public: QVector<SizeManagedTexture> sizeManagedTextures; QVector<SizeChangeCallback> layerSizeChangeCallbacks; Qt3DRender::QAbstractTexture *layerTexture = nullptr; + Qt3DRender::QAbstractTexture *effLayerTexture = nullptr; Qt3DRender::QAbstractTexture *layerDS = nullptr; Qt3DRender::QParameter *compositorSourceParam = nullptr; std::function<void()> updateCompositorCalculations = nullptr; @@ -275,7 +276,10 @@ public: Qt3DRender::QRenderTarget *tempRt = nullptr; } advBlend; - QVector<Q3DSEffectInstance *> effects; + struct EffectData { + Qt3DRender::QFrameGraphNode *effectRoot = nullptr; + QVector<Q3DSEffectInstance *> effects; + } effectData; }; Q_DECLARE_OPERATORS_FOR_FLAGS(Q3DSLayerAttached::SizeManagedTexture::Flags) @@ -379,29 +383,37 @@ public: Q3DSTextureParameters translucencyMapParams; }; +struct Q3DSCustomPropertyParameter { + Q3DSCustomPropertyParameter(Qt3DRender::QParameter *param_, const QVariant &value, const Q3DSMaterial::PropertyElement &meta_) + : param(param_), + inputValue(value), + meta(meta_) + { } + Q3DSCustomPropertyParameter() { } + Qt3DRender::QParameter *param = nullptr; + QVariant inputValue; // e.g. Texture: inputValue is a string whereas param->value is a QAbstractTexture* + Q3DSMaterial::PropertyElement meta; +}; + +Q_DECLARE_TYPEINFO(Q3DSCustomPropertyParameter, Q_MOVABLE_TYPE); + class Q3DSCustomMaterialAttached : public Q3DSMaterialAttached { public: - struct Parameter { - Parameter(Qt3DRender::QParameter *param_, const QVariant &value, const Q3DSMaterial::PropertyElement &meta_) - : param(param_), - inputValue(value), - meta(meta_) - { } - Parameter() { } - Qt3DRender::QParameter *param = nullptr; - QVariant inputValue; // e.g. Texture: inputValue is a string whereas param->value is a QAbstractTexture* - Q3DSMaterial::PropertyElement meta; - }; - QHash<QString, Parameter> params; + QHash<QString, Q3DSCustomPropertyParameter> params; }; -Q_DECLARE_TYPEINFO(Q3DSCustomMaterialAttached::Parameter, Q_MOVABLE_TYPE); - class Q3DSEffectAttached : public Q3DSGraphObjectAttached { public: Qt3DCore::QEntity *entity = nullptr; // for animations + Q3DSLayerNode *layer3DS = nullptr; + Qt3DRender::QLayer *quadEntityTag = nullptr; + QHash<QString, Q3DSCustomPropertyParameter> params; + Qt3DRender::QParameter *texture0Param = nullptr; + Qt3DRender::QParameter *texture0InfoParam = nullptr; + Qt3DRender::QParameter *fragColorAlphaParam = nullptr; + Qt3DRender::QParameter *destSizeParam = nullptr; }; class Q3DSSlideAttached : public Q3DSGraphObjectAttached @@ -568,19 +580,20 @@ private: void retagSubMeshes(Q3DSModelNode *model3DS); void prepareTextureParameters(Q3DSTextureParameters &textureParameters, const QString &name, Q3DSImage *image3DS); QVector<Qt3DRender::QParameter *> prepareDefaultMaterial(Q3DSDefaultMaterial *m, Q3DSModelNode *model3DS); - Qt3DRender::QAbstractTexture *createCustomMaterialTexture(const Q3DSCustomMaterialAttached::Parameter &p); + Qt3DRender::QAbstractTexture *createCustomPropertyTexture(const Q3DSCustomPropertyParameter &p); QVector<Qt3DRender::QParameter *> prepareCustomMaterial(Q3DSCustomMaterialInstance *m, Q3DSModelNode *model3DS); void setImageTextureFromSubPresentation(Qt3DRender::QParameter *sampler, Q3DSImage *image); void updateTextureParameters(Q3DSTextureParameters &textureParameters, Q3DSImage *image); void updateDefaultMaterial(Q3DSDefaultMaterial *m); void updateCustomMaterial(Q3DSCustomMaterialInstance *m); + void buildEffect(Q3DSEffectInstance *eff3DS, Q3DSLayerNode *layer3DS); + void finalizeEffects(Q3DSLayerNode *layer3DS); + void updateEffect(Q3DSEffectInstance *eff3DS); void gatherLights(Q3DSGraphObject *root, QVector<Q3DSLightSource> *allLights, QVector<Q3DSLightSource> *nonAreaLights, QVector<Q3DSLightSource> *areaLights, QVector<Q3DSLightNode *> *lightNodes); void updateLightsBuffer(const QVector<Q3DSLightSource> &lights, Qt3DRender::QBuffer *uniformBuffer); void updateModel(Q3DSModelNode *model3DS); - void buildEffect(Q3DSEffectInstance *eff3DS, Q3DSLayerNode *layer3DS); - void buildLayerQuadEntity(Q3DSLayerNode *layer3DS, Qt3DCore::QEntity *parentEntity, Qt3DRender::QLayer *tag, BuildLayerQuadFlags flags, Qt3DRender::QRenderPass **renderPass); void buildCompositor(Qt3DRender::QFrameGraphNode *parent, Qt3DCore::QEntity *parentEntity); @@ -589,7 +602,8 @@ private: void buildFsQuad(Qt3DCore::QEntity *parentEntity, const QStringList &passNames, const QVector<Qt3DRender::QShaderProgram *> &passProgs, - Qt3DRender::QLayer *tag); + Qt3DRender::QLayer *tag, + const QVector<Qt3DRender::QParameter *> ¶ms); void handlePropertyChange(Q3DSGraphObject *obj, const QSet<QString> &keys, int changeFlags); void updateNodeFromChangeFlags(Q3DSNode *node, Qt3DCore::QTransform *transform, int changeFlags); diff --git a/src/runtime/shadergenerator/q3dsshadermanager.cpp b/src/runtime/shadergenerator/q3dsshadermanager.cpp index 361469f..6a1db41 100644 --- a/src/runtime/shadergenerator/q3dsshadermanager.cpp +++ b/src/runtime/shadergenerator/q3dsshadermanager.cpp @@ -850,6 +850,28 @@ Qt3DRender::QShaderProgram *Q3DSShaderManager::getBlendColorDodgeShader(Qt3DCore return prog; } +Qt3DRender::QShaderProgram *Q3DSShaderManager::getEffectShader(Qt3DCore::QNode *parent, + const QString &name, + const QString &vertexShaderSrc, + const QString &fragmentShaderSrc) +{ + // No cache on this level. m_shaderProgramGenerator has one. + + m_shaderProgramGenerator->beginProgram(); + Q3DSAbstractShaderStageGenerator *vertexShader = m_shaderProgramGenerator->getStage(Q3DSShaderGeneratorStages::Vertex); + Q3DSAbstractShaderStageGenerator *fragmentShader = m_shaderProgramGenerator->getStage(Q3DSShaderGeneratorStages::Fragment); + + vertexShader->append("\n#define VERTEX_SHADER\n#include \"effect.glsllib\"\n"); + vertexShader->append(vertexShaderSrc.toUtf8().constData()); + + fragmentShader->append("\n#define FRAGMENT_SHADER\n#include \"effect.glsllib\"\n"); + fragmentShader->append(fragmentShaderSrc.toUtf8().constData()); + + Qt3DRender::QShaderProgram *prog = m_shaderProgramGenerator->compileGeneratedShader(name, Q3DSShaderFeatureSet()); + prog->setParent(parent); + return prog; +} + Q3DSShaderManager::Q3DSShaderManager() : m_materialShaderGenerator(&Q3DSDefaultMaterialShaderGenerator::createDefaultMaterialShaderGenerator()) , m_customMaterialShaderGenerator(&Q3DSCustomMaterialShaderGenerator::createCustomMaterialShaderGenerator()) diff --git a/src/runtime/shadergenerator/q3dsshadermanager_p.h b/src/runtime/shadergenerator/q3dsshadermanager_p.h index e5b6916..f099903 100644 --- a/src/runtime/shadergenerator/q3dsshadermanager_p.h +++ b/src/runtime/shadergenerator/q3dsshadermanager_p.h @@ -95,6 +95,11 @@ public: Qt3DRender::QShaderProgram *getBlendColorBurnShader(Qt3DCore::QNode *parent, int msaaSampleCount); Qt3DRender::QShaderProgram *getBlendColorDodgeShader(Qt3DCore::QNode *parent, int msaaSampleCount); + Qt3DRender::QShaderProgram *getEffectShader(Qt3DCore::QNode *parent, + const QString &name, + const QString &vertexShaderSrc, + const QString &fragmentShaderSrc); + private: Q3DSShaderManager(); |