summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2018-01-08 13:56:15 +0100
committerLaszlo Agocs <laszlo.agocs@qt.io>2018-01-10 12:28:20 +0000
commit9dcbce5bfe4977a65b21e5eb593878cc14db8252 (patch)
tree570be05ded5f51dd50d3e6babe7516b99cfd8980
parent409d4273f15643aa440ef1f4a6b2dc83bdbdb531 (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.glsllib16
-rw-r--r--src/runtime/q3dseffect.cpp44
-rw-r--r--src/runtime/q3dseffect.h2
-rw-r--r--src/runtime/q3dsmaterial.cpp11
-rw-r--r--src/runtime/q3dsscenemanager.cpp286
-rw-r--r--src/runtime/q3dsscenemanager.h52
-rw-r--r--src/runtime/shadergenerator/q3dsshadermanager.cpp22
-rw-r--r--src/runtime/shadergenerator/q3dsshadermanager_p.h5
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 *> &params)
{
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, [&paramList, data](const QString &propKey, const QVariant &, const Q3DSMaterial::PropertyElement &propMeta) {
+ forAllCustomProperties(m, [&paramList, 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, [&paramList, 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 *> &params);
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();