summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2018-01-10 12:54:50 +0100
committerLaszlo Agocs <laszlo.agocs@qt.io>2018-01-15 17:22:26 +0000
commit43c06d91f08c561b81575924d22db04efe10ba9b (patch)
tree40fdee67c6ae77b9ac36d8ef9d4d87e2a2f2c756
parent72905889ea2e13fc1160491024e920e1e6507efd (diff)
effects: A whole lot more plumbing
You can have any effect you want, as long as it's a corona. Change-Id: I242158d05825d179250e7a05f8d17c45835e7fc6 Reviewed-by: Andy Nichols <andy.nichols@qt.io>
-rw-r--r--src/runtime/q3dseffect.cpp7
-rw-r--r--src/runtime/q3dsscenemanager.cpp332
-rw-r--r--src/runtime/q3dsscenemanager.h30
-rw-r--r--tests/scenes/effects/Corona.effect97
-rw-r--r--tests/scenes/effects/corona.uip48
-rw-r--r--tests/scenes/effects/maps/effects/noise.ddsbin0 -> 4224 bytes
6 files changed, 449 insertions, 65 deletions
diff --git a/src/runtime/q3dseffect.cpp b/src/runtime/q3dseffect.cpp
index c037020..ad1f936 100644
--- a/src/runtime/q3dseffect.cpp
+++ b/src/runtime/q3dseffect.cpp
@@ -92,6 +92,13 @@ QString Q3DSEffect::addPropertyUniforms(const QString &shaderSrc) const
break;
case Q3DS::Texture:
addUniform("sampler2D", prop.name);
+ // In addition we must add:
+ // - uniform vec4 <name>Info that contains (width, height, isPremultiplied, 0)
+ // - a texture2D_<name> function
+ // The flag uniform from 3DS1 is dropped since its purpose was unknown.
+ // The SNAPPER macros are not used, we insert the uniform/function code directly here.
+ addUniform("vec4", prop.name + QLatin1String("Info"));
+ s += QString(QLatin1String("vec4 texture2D_%1(vec2 uv) { return GetTextureValue(%1, uv, %1Info.z); }\n")).arg(prop.name);
break;
// ### there could be more that needs handling here (Buffer?)
diff --git a/src/runtime/q3dsscenemanager.cpp b/src/runtime/q3dsscenemanager.cpp
index b7d318e..96c1141 100644
--- a/src/runtime/q3dsscenemanager.cpp
+++ b/src/runtime/q3dsscenemanager.cpp
@@ -1501,12 +1501,14 @@ void Q3DSSceneManager::setLayerSizeProperties(Q3DSLayerNode *layer3DS)
const QSize layerPixelSize = safeLayerPixelSize(data);
const QSize layerSize = safeLayerPixelSize(data->layerSize, 1); // for when SSAA is to be ignored
for (const Q3DSLayerAttached::SizeManagedTexture &t : data->sizeManagedTextures) {
- if (!t.flags.testFlag(Q3DSLayerAttached::SizeManagedTexture::IgnoreSSAA)) {
- t.texture->setWidth(layerPixelSize.width());
- t.texture->setHeight(layerPixelSize.height());
- } else {
- t.texture->setWidth(layerSize.width());
- t.texture->setHeight(layerSize.height());
+ if (!t.flags.testFlag(Q3DSLayerAttached::SizeManagedTexture::CustomSizeCalculation)) {
+ if (!t.flags.testFlag(Q3DSLayerAttached::SizeManagedTexture::IgnoreSSAA)) {
+ t.texture->setWidth(layerPixelSize.width());
+ t.texture->setHeight(layerPixelSize.height());
+ } else {
+ t.texture->setWidth(layerSize.width());
+ t.texture->setHeight(layerSize.height());
+ }
}
if (t.sizeChangeCallback)
t.sizeChangeCallback(layer3DS);
@@ -1660,7 +1662,8 @@ void Q3DSSceneManager::setCameraProperties(Q3DSCameraNode *camNode, int changeFl
static void prepareSizeDependentTexture(Qt3DRender::QAbstractTexture *texture,
Q3DSLayerNode *layer3DS,
- Q3DSLayerAttached::SizeChangeCallback callback = nullptr)
+ Q3DSLayerAttached::SizeChangeCallback callback = nullptr,
+ Q3DSLayerAttached::SizeManagedTexture::Flags flags = 0)
{
Q3DSLayerAttached *data = static_cast<Q3DSLayerAttached *>(layer3DS->attached());
@@ -1669,7 +1672,7 @@ static void prepareSizeDependentTexture(Qt3DRender::QAbstractTexture *texture,
texture->setHeight(layerPixelSize.height());
// the layer will resize the texture automatically
- data->sizeManagedTextures << Q3DSLayerAttached::SizeManagedTexture(texture, callback);
+ data->sizeManagedTextures << Q3DSLayerAttached::SizeManagedTexture(texture, callback, flags);
}
void Q3DSSceneManager::setDepthTextureEnabled(Q3DSLayerNode *layer3DS, bool enabled)
@@ -4189,17 +4192,13 @@ Qt3DRender::QAbstractTexture *Q3DSSceneManager::createCustomPropertyTexture(cons
{
const QString source = p.inputValue.toString();
Qt3DRender::QTexture2D *texture = new Qt3DRender::QTexture2D(m_rootEntity);
+ m_profiler->trackNewObject(texture, Q3DSProfiler::Texture2DObject,
+ "Custom property texture %s", qPrintable(source));
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) {
@@ -4343,41 +4342,55 @@ void Q3DSSceneManager::finalizeEffects(Q3DSLayerNode *layer3DS)
continue;
}
- QVector<Qt3DRender::QParameter *> paramList;
+ // Set up textures for Buffers
+ createEffectBuffers(eff3DS);
- // Create QParameters for built-in uniforms (see effect.glsllib).
- effData->texture0Param = new Qt3DRender::QParameter;
- effData->texture0Param->setName(QLatin1String("Texture0"));
- paramList.append(effData->texture0Param);
+ QVector<Qt3DRender::QParameter *> commonParamList;
- effData->texture0InfoParam = new Qt3DRender::QParameter;
- effData->texture0InfoParam->setName(QLatin1String("Texture0Info"));
- paramList.append(effData->texture0InfoParam);
+ // Create QParameters for built-in uniforms (see effect.glsllib).
+ // Texture0 and friends depend on the input so those are per pass.
+ effData->appFrameParam = new Qt3DRender::QParameter;
+ effData->appFrameParam->setName(QLatin1String("AppFrame"));
+ commonParamList.append(effData->appFrameParam);
- effData->fragColorAlphaParam = new Qt3DRender::QParameter;
- effData->fragColorAlphaParam->setName(QLatin1String("FragColorAlphaSettings"));
- paramList.append(effData->fragColorAlphaParam);
+ effData->fpsParam = new Qt3DRender::QParameter;
+ effData->fpsParam->setName(QLatin1String("FPS"));
+ commonParamList.append(effData->fpsParam);
- effData->destSizeParam = new Qt3DRender::QParameter;
- effData->destSizeParam->setName(QLatin1String("DestSize"));
- paramList.append(effData->destSizeParam);
+ effData->cameraClipRangeParam = new Qt3DRender::QParameter;
+ effData->cameraClipRangeParam->setName(QLatin1String("CameraClipRange"));
+ commonParamList.append(effData->cameraClipRangeParam);
// Create QParameters for custom properties.
- forAllCustomProperties(eff3DS, [&paramList, effData](const QString &propKey, const QVariant &, const Q3DSMaterial::PropertyElement &propMeta) {
+ forAllCustomProperties(eff3DS, [&commonParamList, effData](const QString &propKey, const QVariant &propValue, const Q3DSMaterial::PropertyElement &propMeta) {
+ // textures with no filename are effectively samplers (to be used in a BufferInput f.ex.)
+ if (propMeta.type == Q3DS::Texture && propValue.toString().isEmpty())
+ return;
+
Qt3DRender::QParameter *param = new Qt3DRender::QParameter;
param->setName(propKey);
- paramList.append(param);
- effData->params.insert(propKey, Q3DSCustomPropertyParameter(param, QVariant(), propMeta));
+ commonParamList.append(param);
+ Qt3DRender::QParameter *infoParam = nullptr;
+ // textures do not just get a sampler uniform but also an additional vec4
+ if (propMeta.type == Q3DS::Texture) {
+ infoParam = new Qt3DRender::QParameter;
+ infoParam->setName(propKey + QLatin1String("Info"));
+ commonParamList.append(infoParam);
+ }
+ Q3DSCustomPropertyParameter pp(param, QVariant(), propMeta);
+ pp.infoParam = infoParam;
+ effData->params.insert(propKey, pp);
});
- // Update QParameter values.
+ // Set initial QParameter (uniform) 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()) {
+ auto passes = effDesc->passes();
+ for (int passIdx = 0; passIdx < passes.count(); ++passIdx) {
+ const Q3DSMaterial::Pass &pass(passes[passIdx]);
if (!shaderPrograms.contains(pass.shaderName)) {
qWarning("Effect %s: Unknown shader program %s; pass ignored",
eff3DS->id().constData(), qPrintable(pass.shaderName));
@@ -4385,49 +4398,100 @@ void Q3DSSceneManager::finalizeEffects(Q3DSLayerNode *layer3DS)
}
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());
+
+ QVector<Qt3DRender::QParameter *> paramList;
+ paramList << commonParamList;
+
for (const Q3DSMaterial::PassCommand &cmd : pass.commands) {
switch (cmd.type()) {
case Q3DSMaterial::PassCommand::BufferInputType:
{
const QString bufferName = cmd.data()->value;
- if (buffers.contains(bufferName)) {
- // ###
+ if (bufferName == QStringLiteral("[source]")) {
+ Qt3DRender::QParameter *texParam = new Qt3DRender::QParameter;
+ texParam->setName(cmd.data()->param);
+ texParam->setValue(QVariant::fromValue(layerData->layerTexture));
+ paramList.append(texParam);
+ Qt3DRender::QParameter *texInfoParam = new Qt3DRender::QParameter;
+ texInfoParam->setName(cmd.data()->param + QLatin1String("Info"));
+ texInfoParam->setValue(QVector4D(layerData->layerTexture->width(), layerData->layerTexture->height(), 0, 0)); // ### 3rd value is isPremultiplied, is that correct?
+ effData->sourceDepTextureInfoParams.append(texInfoParam);
+ paramList.append(texInfoParam);
+ } else if (effData->textureBuffers.contains(bufferName)) {
+ Q3DSEffectAttached::TextureBuffer &tb(effData->textureBuffers[bufferName]);
+ Qt3DRender::QParameter *texParam = new Qt3DRender::QParameter;
+ texParam->setName(cmd.data()->param);
+ texParam->setValue(QVariant::fromValue(tb.texture));
+ paramList.append(texParam);
+ Qt3DRender::QParameter *texInfoParam = new Qt3DRender::QParameter;
+ texInfoParam->setName(cmd.data()->param + QLatin1String("Info"));
+ texInfoParam->setValue(QVector4D(tb.texture->width(), tb.texture->height(), 0, 0)); // ### 3rd value is isPremultiplied, is that correct?
+ tb.textureInfoParams.append(texInfoParam);
+ paramList.append(texInfoParam);
} 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)) {
- // ###
+ if (effData->textureBuffers.contains(pass.input)) {
+ passInput = effData->textureBuffers.value(pass.input).texture;
} else {
qWarning("Effect %s: Unknown input buffer %s; pass ignored",
eff3DS->id().constData(), qPrintable(pass.input));
continue;
}
}
+
+ bool outputNeedsClear = false;
+ Qt3DRender::QAbstractTexture *passOutput = nullptr;
if (pass.output == QStringLiteral("[dest]")) {
passOutput = layerData->effLayerTexture;
+ outputNeedsClear = true;
} else {
- if (buffers.contains(pass.output)) {
- // ###
+ if (effData->textureBuffers.contains(pass.output)) {
+ auto tb = effData->textureBuffers.value(pass.output);
+ passOutput = tb.texture;
+ outputNeedsClear = tb.hasSceneLifetime;
} else {
qWarning("Effect %s: Unknown output buffer %s; pass ignored",
eff3DS->id().constData(), qPrintable(pass.output));
continue;
}
}
- Q_ASSERT(passInput && passOutput);
+
+ Qt3DRender::QParameter *texture0Param = new Qt3DRender::QParameter;
+ texture0Param->setName(QLatin1String("Texture0"));
+ texture0Param->setValue(QVariant::fromValue(passInput));
+ paramList.append(texture0Param);
+
+ Qt3DRender::QParameter *texture0InfoParam = new Qt3DRender::QParameter;
+ texture0InfoParam->setName(QLatin1String("Texture0Info"));
+ paramList.append(texture0InfoParam);
+
+ Qt3DRender::QParameter *fragColorAlphaParam = new Qt3DRender::QParameter;
+ fragColorAlphaParam->setName(QLatin1String("FragColorAlphaSettings"));
+ fragColorAlphaParam->setValue(QVector2D(1.0f, 0.0f));
+ paramList.append(fragColorAlphaParam);
+
+ Qt3DRender::QParameter *destSizeParam = new Qt3DRender::QParameter;
+ destSizeParam->setName(QLatin1String("DestSize"));
+ paramList.append(destSizeParam);
+
+ Q3DSEffectAttached::PassData pd;
+ pd.passInput = passInput;
+ pd.texture0InfoParam = texture0InfoParam;
+ pd.passOutput = passOutput;
+ pd.destSizeParam = destSizeParam;
+ effData->passData.append(pd);
const Q3DSMaterial::Shader &shaderProgram(shaderPrograms.value(pass.shaderName));
const QString decoratedShaderName = QString::fromUtf8(eff3DS->id()) + QLatin1Char('_') + pass.shaderName;
@@ -4445,35 +4509,145 @@ void Q3DSSceneManager::finalizeEffects(Q3DSLayerNode *layer3DS)
Qt3DRender::QRenderTarget *rt = new Qt3DRender::QRenderTarget;
Qt3DRender::QRenderTargetOutput *color = new Qt3DRender::QRenderTargetOutput;
color->setAttachmentPoint(Qt3DRender::QRenderTargetOutput::Color0);
- color->setTexture(layerData->effLayerTexture);
+ color->setTexture(passOutput);
rt->addOutput(color);
rtSel->setTarget(rt);
Qt3DRender::QClearBuffers *clearBuf = new Qt3DRender::QClearBuffers(rtSel);
- clearBuf->setBuffers(Qt3DRender::QClearBuffers::ColorBuffer);
+ clearBuf->setClearColor(Qt::transparent);
+ clearBuf->setBuffers(outputNeedsClear ? Qt3DRender::QClearBuffers::ColorBuffer : Qt3DRender::QClearBuffers::None);
Qt3DRender::QLayerFilter *layerFilter = new Qt3DRender::QLayerFilter(clearBuf);
layerFilter->addLayer(effData->quadEntityTag);
}
+
+ // set initial values for per-frame uniforms
+ // (or the ones that depend on pass input/output size and are easier to handle this way)
+ updateEffectForNextFrame(eff3DS, 0);
}
// The layer compositor must use the output of the effect passes from now on.
layerData->compositorSourceParam->setValue(QVariant::fromValue(layerData->effLayerTexture));
}
+void Q3DSSceneManager::setupEffectTextureBuffer(Q3DSEffectAttached::TextureBuffer *tb,
+ const Q3DSMaterial::PassBuffer &bufDesc,
+ Q3DSLayerNode *layer3DS)
+{
+ Qt3DRender::QAbstractTexture *texture = new Qt3DRender::QTexture2D(m_rootEntity);
+ tb->texture = texture;
+
+ switch (bufDesc.filter()) {
+ case Q3DSMaterial::Nearest:
+ texture->setMinificationFilter(Qt3DRender::QAbstractTexture::Nearest);
+ texture->setMagnificationFilter(Qt3DRender::QAbstractTexture::Nearest);
+ break;
+ default:
+ texture->setMinificationFilter(Qt3DRender::QAbstractTexture::Linear);
+ texture->setMagnificationFilter(Qt3DRender::QAbstractTexture::Linear);
+ break;
+ }
+
+ Qt3DRender::QTextureWrapMode wrapMode;
+ switch (bufDesc.wrap()) {
+ case Q3DSMaterial::Repeat:
+ wrapMode.setX(Qt3DRender::QTextureWrapMode::Repeat);
+ wrapMode.setY(Qt3DRender::QTextureWrapMode::Repeat);
+ break;
+ default:
+ wrapMode.setX(Qt3DRender::QTextureWrapMode::ClampToEdge);
+ wrapMode.setY(Qt3DRender::QTextureWrapMode::ClampToEdge);
+ break;
+ }
+ texture->setWrapMode(wrapMode);
+
+ switch (bufDesc.textureFormat()) {
+ case Q3DSMaterial::Depth24Stencil8:
+ texture->setFormat(Qt3DRender::QAbstractTexture::D24S8);
+ break;
+ case Q3DSMaterial::RGB8:
+ texture->setFormat(Qt3DRender::QAbstractTexture::RGB8_UNorm);
+ break;
+ case Q3DSMaterial::Alpha8:
+ texture->setFormat(Qt3DRender::QAbstractTexture::AlphaFormat);
+ break;
+ case Q3DSMaterial::Luminance8:
+ texture->setFormat(Qt3DRender::QAbstractTexture::LuminanceFormat);
+ break;
+ case Q3DSMaterial::LuminanceAlpha8:
+ texture->setFormat(Qt3DRender::QAbstractTexture::LuminanceAlphaFormat);
+ break;
+ case Q3DSMaterial::RG8:
+ texture->setFormat(Qt3DRender::QAbstractTexture::RG8_UNorm);
+ break;
+ case Q3DSMaterial::RGB565:
+ texture->setFormat(Qt3DRender::QAbstractTexture::R5G6B5);
+ break;
+ case Q3DSMaterial::RGBA5551:
+ texture->setFormat(Qt3DRender::QAbstractTexture::RGB5A1);
+ break;
+ case Q3DSMaterial::RGBA16F:
+ texture->setFormat(Qt3DRender::QAbstractTexture::RGBA16F);
+ break;
+ case Q3DSMaterial::RG16F:
+ texture->setFormat(Qt3DRender::QAbstractTexture::RG16F);
+ break;
+ case Q3DSMaterial::RGBA32F:
+ texture->setFormat(Qt3DRender::QAbstractTexture::RGBA32F);
+ break;
+ case Q3DSMaterial::RG32F:
+ texture->setFormat(Qt3DRender::QAbstractTexture::RG32F);
+ break;
+ default: // incl. Unknown that is set for "source"
+ texture->setFormat(Qt3DRender::QAbstractTexture::RGBA8_UNorm);
+ break;
+ }
+
+ Q3DSLayerAttached *layerData = static_cast<Q3DSLayerAttached *>(layer3DS->attached());
+ float sizeMultiplier = bufDesc.size();
+ auto sizeCalc = [texture, layerData, sizeMultiplier](Q3DSLayerNode*) {
+ const QSize sz = safeLayerPixelSize(layerData);
+ texture->setWidth(int(sz.width() * sizeMultiplier));
+ texture->setHeight(int(sz.height() * sizeMultiplier));
+ };
+ prepareSizeDependentTexture(texture, layer3DS, sizeCalc, Q3DSLayerAttached::SizeManagedTexture::CustomSizeCalculation);
+ sizeCalc(layer3DS);
+}
+
+void Q3DSSceneManager::createEffectBuffers(Q3DSEffectInstance *eff3DS)
+{
+ Q3DSEffectAttached *effData = static_cast<Q3DSEffectAttached *>(eff3DS->attached());
+ const Q3DSEffect *effDesc = eff3DS->effect();
+ const QMap<QString, Q3DSMaterial::PassBuffer> &bufDescs = effDesc->buffers();
+ for (const Q3DSMaterial::PassBuffer &bufDesc : bufDescs) {
+ if (bufDesc.passBufferType() == Q3DSMaterial::BufferType) {
+ if (effData->textureBuffers.contains(bufDesc.name())) {
+ qWarning("Texture Buffer name %s reused", qPrintable(bufDesc.name()));
+ continue;
+ }
+ Q3DSEffectAttached::TextureBuffer tb;
+ tb.hasSceneLifetime = bufDesc.hasSceneLifetime();
+ setupEffectTextureBuffer(&tb, bufDesc, effData->layer3DS);
+ effData->textureBuffers.insert(bufDesc.name(), tb);
+ } else {
+ // ###
+ qWarning("Effect %s: Unsupported buffer type", eff3DS->id().constData());
+ }
+ }
+}
+
+// called once on load from finalizeEffect, and then every time an effect property has changed
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()));
+ QVector2D cameraClipRange(0, 5000);
+ if (layerData->cam3DS) {
+ cameraClipRange.setX(layerData->cam3DS->clipNear());
+ cameraClipRange.setY(layerData->cam3DS->clipFar());
+ }
+ effData->cameraClipRangeParam->setValue(cameraClipRange);
forAllCustomProperties(eff3DS, [effData, this](const QString &propKey, const QVariant &propValue, const Q3DSMaterial::PropertyElement &) {
if (!effData->params.contains(propKey))
@@ -4487,7 +4661,11 @@ void Q3DSSceneManager::updateEffect(Q3DSEffectInstance *eff3DS)
switch (p.meta.type) {
case Q3DS::Texture:
- p.param->setValue(QVariant::fromValue(createCustomPropertyTexture(p)));
+ {
+ Qt3DRender::QAbstractTexture *tex = createCustomPropertyTexture(p);
+ p.param->setValue(QVariant::fromValue(tex));
+ p.infoParam->setValue(QVector4D(tex->width(), tex->height(), 0, 0)); // ### 3rd value is isPremultiplied, is that correct?
+ }
break;
// ### others?
@@ -4499,6 +4677,29 @@ void Q3DSSceneManager::updateEffect(Q3DSEffectInstance *eff3DS)
});
}
+// called after each frame
+void Q3DSSceneManager::updateEffectForNextFrame(Q3DSEffectInstance *eff3DS, qint64 nextFrameNo)
+{
+ Q3DSEffectAttached *effData = static_cast<Q3DSEffectAttached *>(eff3DS->attached());
+ Q3DSLayerAttached *layerData = static_cast<Q3DSLayerAttached *>(effData->layer3DS->attached());
+
+ effData->appFrameParam->setValue(float(nextFrameNo));
+ effData->fpsParam->setValue(60.0f); // heh
+ for (const auto &pd : effData->passData) {
+ pd.texture0InfoParam->setValue(QVector4D(pd.passInput->width(),
+ pd.passInput->height(),
+ 0, // ### isPremultiplied?
+ 0));
+ pd.destSizeParam->setValue(QVector2D(pd.passOutput->width(), pd.passOutput->height()));
+ }
+ for (const auto &tb : effData->textureBuffers) {
+ for (Qt3DRender::QParameter *param : tb.textureInfoParams)
+ param->setValue(QVector4D(tb.texture->width(), tb.texture->height(), 0, 0)); // ### 3rd value is isPremultiplied, is that correct?
+ }
+ for (Qt3DRender::QParameter *param : effData->sourceDepTextureInfoParams)
+ param->setValue(QVector4D(layerData->layerTexture->width(), layerData->layerTexture->height(), 0, 0)); // ### 3rd value is isPremultiplied, is that correct?
+}
+
void Q3DSSceneManager::gatherLights(Q3DSGraphObject *root,
QVector<Q3DSLightSource> *allLights,
QVector<Q3DSLightSource> *nonAreaLights,
@@ -4810,10 +5011,18 @@ void Q3DSSceneManager::prepareNextFrame()
updateSubTree(m_scene);
- // Dirty flags now up-to-date -> update progressive AA status
- Q3DSPresentation::forAllLayers(m_scene, [this](Q3DSLayerNode *layer3DS) {
+ qint64 nextFrameNo = m_frameUpdater->frameCounter() + 1;
+ Q3DSPresentation::forAllLayers(m_scene, [this, nextFrameNo](Q3DSLayerNode *layer3DS) {
+ // Dirty flags now up-to-date -> update progressive AA status
if (layer3DS->progressiveAA() != Q3DSLayerNode::NoPAA)
updateProgressiveAA(layer3DS);
+
+ // Post-processing effects have uniforms that need to be updated on every frame.
+ Q3DSLayerAttached *layerData = static_cast<Q3DSLayerAttached *>(layer3DS->attached());
+ if (layerData) {
+ for (Q3DSEffectInstance *eff3DS : qAsConst(layerData->effectData.effects))
+ updateEffectForNextFrame(eff3DS, nextFrameNo);
+ }
});
}
@@ -4938,6 +5147,10 @@ void Q3DSSceneManager::updateSubTreeRecursive(Q3DSGraphObject *obj)
layerData->cam3DS = cam3DS;
layerData->cameraSelector->setCamera(data->camera);
reparentCamera(data->layer3DS);
+ // Camera has changed -> trigger a property value update
+ // for effects since they may rely on the camera clip range.
+ for (Q3DSEffectInstance *eff3DS : layerData->effectData.effects)
+ updateEffect(eff3DS);
}
setCameraProperties(cam3DS, data->changeFlags); // handles both Node- and Camera-level properties
setLayerCameraSizeProperties(data->layer3DS);
@@ -5194,10 +5407,9 @@ void Q3DSSceneManager::setAnimationsRunning(Q3DSSlide *slide, bool running)
void Q3DSFrameUpdater::frameAction(float dt)
{
- static qint64 frameCounter = 0;
static const bool animDebug = qEnvironmentVariableIntValue("Q3DS_DEBUG") >= 3;
if (Q_UNLIKELY(animDebug))
- qDebug().nospace() << "frame action " << frameCounter << ", delta=" << dt << ", applying animations and updating nodes";
+ qDebug().nospace() << "frame action " << m_frameCounter << ", delta=" << dt << ", applying animations and updating nodes";
// Record new frame event.
m_sceneManager->profiler()->reportNewFrame(dt * 1000.0f);
@@ -5207,8 +5419,8 @@ void Q3DSFrameUpdater::frameAction(float dt)
// pending visibility changes, update light cbuffers, etc.
m_sceneManager->prepareNextFrame();
// Update profiling statistics for this frame.
- m_sceneManager->profiler()->updateFrameStats(frameCounter);
- ++frameCounter;
+ m_sceneManager->profiler()->updateFrameStats(m_frameCounter);
+ ++m_frameCounter;
}
void Q3DSSceneManager::setProfileUiVisible(bool visible)
diff --git a/src/runtime/q3dsscenemanager.h b/src/runtime/q3dsscenemanager.h
index 70b889f..30f37dd 100644
--- a/src/runtime/q3dsscenemanager.h
+++ b/src/runtime/q3dsscenemanager.h
@@ -169,7 +169,8 @@ public:
typedef std::function<void(Q3DSLayerNode *)> SizeChangeCallback;
struct SizeManagedTexture {
enum Flag {
- IgnoreSSAA = 0x01
+ IgnoreSSAA = 0x01,
+ CustomSizeCalculation = 0x02
};
Q_DECLARE_FLAGS(Flags, Flag)
SizeManagedTexture() { }
@@ -393,6 +394,7 @@ struct Q3DSCustomPropertyParameter {
Qt3DRender::QParameter *param = nullptr;
QVariant inputValue; // e.g. Texture: inputValue is a string whereas param->value is a QAbstractTexture*
Q3DSMaterial::PropertyElement meta;
+ Qt3DRender::QParameter *infoParam = nullptr;
};
Q_DECLARE_TYPEINFO(Q3DSCustomPropertyParameter, Q_MOVABLE_TYPE);
@@ -410,10 +412,23 @@ public:
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;
+ Qt3DRender::QParameter *appFrameParam = nullptr;
+ Qt3DRender::QParameter *fpsParam = nullptr;
+ Qt3DRender::QParameter *cameraClipRangeParam = nullptr;
+ struct TextureBuffer {
+ Qt3DRender::QAbstractTexture *texture = nullptr;
+ QVector<Qt3DRender::QParameter *> textureInfoParams;
+ bool hasSceneLifetime = false;
+ };
+ QHash<QString, TextureBuffer> textureBuffers;
+ struct PassData {
+ Qt3DRender::QAbstractTexture *passInput = nullptr;
+ Qt3DRender::QParameter *texture0InfoParam = nullptr;
+ Qt3DRender::QAbstractTexture *passOutput = nullptr;
+ Qt3DRender::QParameter *destSizeParam = nullptr;
+ };
+ QVector<PassData> passData;
+ QVector<Qt3DRender::QParameter *> sourceDepTextureInfoParams;
};
class Q3DSSlideAttached : public Q3DSGraphObjectAttached
@@ -588,7 +603,10 @@ private:
void updateCustomMaterial(Q3DSCustomMaterialInstance *m);
void buildEffect(Q3DSEffectInstance *eff3DS, Q3DSLayerNode *layer3DS);
void finalizeEffects(Q3DSLayerNode *layer3DS);
+ void setupEffectTextureBuffer(Q3DSEffectAttached::TextureBuffer *tb, const Q3DSMaterial::PassBuffer &bufDesc, Q3DSLayerNode *layer3DS);
+ void createEffectBuffers(Q3DSEffectInstance *eff3DS);
void updateEffect(Q3DSEffectInstance *eff3DS);
+ void updateEffectForNextFrame(Q3DSEffectInstance *eff3DS, qint64 nextFrameNo);
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);
@@ -667,9 +685,11 @@ public:
Q3DSFrameUpdater(Q3DSSceneManager *manager) : m_sceneManager(manager) { }
void frameAction(float dt);
+ qint64 frameCounter() const { return m_frameCounter; }
private:
Q3DSSceneManager *m_sceneManager;
+ qint64 m_frameCounter = 0;
};
Q3DSV_EXPORT QDebug operator<<(QDebug dbg, const Q3DSSceneManager::SceneBuilderParams &p);
diff --git a/tests/scenes/effects/Corona.effect b/tests/scenes/effects/Corona.effect
new file mode 100644
index 0000000..6b3d113
--- /dev/null
+++ b/tests/scenes/effects/Corona.effect
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<Effect>
+ <MetaData>
+ <!--Creates a corona around a sprite.-->
+ <Property name="HBlurBias" formalName="Horizontal Blur" min="0" max="10" default="2" description="Amount of corona horizontally."/>
+ <Property name="VBlurBias" formalName="Vertical Blur" min="0" max="10" default="2" description="Amount of corona vertically."/>
+ <Property name="Trailfade" formalName="Fade Amount" min="0" max="1" default="0.8" description="0=no glow, 0.5=fade quickly, 1.0=persistent trails"/>
+ <Property name="GlowSampler" filter="nearest" clamp="clamp" type="Texture" />
+ <Property name="GlowCol" formalName="Glow Color" type="Color" default="1 0.6 0.0" description="The color to use for the glow."/>
+ <Property name="NoiseSamp" formalName="Noise" filter="linear" clamp="repeat" default="./maps/effects/noise.dds" type="Texture" description="Texture to be used for the noise texture"/>
+ <Property name="NoiseScale" formalName="Noise Density" min="0" max="10" default="2" description="The density of the noise in corona. The higher the value, the denser and smaller of the noise; the lower the value, the bigger of the noise scale."/>
+ <Property name="NoiseBright" formalName="Noise Brightness" min="0" max="5" default="4" description="Brightness of the noise."/>
+ <Property name="NoiseRatio" formalName="Noise Amount" min="0" max="1" default=".15" description="Magnitude of the noise."/>
+ <Property name="CrawlLen" formalName="Crawl Length" min="0" max="1" default=".3" description="Length of the corona trail in animation."/>
+ <Property name="CrawlAngle" formalName="Crawl Angle" default="0" description="Angle of the corona trail in animation."/>
+ <Property name="Sprite" filter="nearest" clamp="clamp" type="Texture" />
+ </MetaData>
+ <Shaders>
+ <Shared>
+#include "blur.glsllib"
+uniform float AppFrame; // frame number since app starts
+uniform float FPS;
+ </Shared>
+ <Shader name="CORONA_HBLUR">
+ <Shared>
+varying vec2 crawl; // corona crawl direction and magnitude
+ </Shared>
+ <VertexShader>
+void vert ()
+{
+ SetupHorizontalGaussianBlur(Texture0Info.x, HBlurBias, TexCoord);
+ // compute crawl
+ float alpha = radians(CrawlAngle + 180.0);
+ crawl = vec2(CrawlLen * sin(alpha), CrawlLen * cos(alpha));
+}
+ </VertexShader>
+ <FragmentShader>
+void frag()
+{
+ //Passing in 1.0 means the value will not get alpha-multiplied again
+ float OutCol = GaussianAlphaBlur( GlowSampler, 1.0 );
+ OutCol *= Trailfade; // fade away glow color
+ OutCol += texture2D_0( TexCoord ).a; // add glow color in the original tex area
+
+ vec2 nuv = NoiseScale * TexCoord3 + AppFrame / FPS * crawl;
+ vec4 noise = texture2D_NoiseSamp(fract(nuv));
+ float ns = (1.0 - NoiseRatio) + NoiseRatio * NoiseBright * noise.x;
+ OutCol *= ns;
+ gl_FragColor = vec4( OutCol );
+}
+ </FragmentShader>
+ </Shader>
+ <Shader name="CORONA_VBLUR">
+ <VertexShader>
+void vert ()
+{
+ SetupVerticalGaussianBlur( Texture0Info.y, VBlurBias, TexCoord );
+}
+ </VertexShader>
+ <FragmentShader>
+void frag() // PS_Blur_Vertical_9tap
+{
+ float OutCol = GaussianAlphaBlur( Texture0, Texture0Info.z );
+ gl_FragColor = OutCol * vec4(GlowCol, 1.0);
+}
+ </FragmentShader>
+ </Shader>
+ <Shader name="CORONA_BLEND">
+ <VertexShader>
+void vert()
+{
+}
+ </VertexShader>
+ <FragmentShader>
+void frag ()
+{
+ vec4 src = texture2D_0( TexCoord );
+ vec4 dst = texture2D_Sprite(TexCoord);
+ colorOutput( src * (1.0 - dst.a) + dst );
+}
+ </FragmentShader>
+ </Shader>
+ </Shaders>
+ <Passes>
+ <Buffer name="glow_buffer" type="ubyte" format="rgba" filter="linear" wrap="clamp" size="0.55" lifetime="scene"/>
+ <Buffer name="temp_buffer" type="ubyte" format="rgba" filter="linear" wrap="clamp" size="0.55" lifetime="frame"/>
+
+ <Pass shader="CORONA_HBLUR" input="[source]" output="temp_buffer">
+ <BufferInput param="GlowSampler" value="glow_buffer"/>
+ </Pass>
+ <Pass shader="CORONA_VBLUR" input="temp_buffer" output="glow_buffer"/>
+
+ <Pass shader="CORONA_BLEND" input="glow_buffer">
+ <BufferInput param="Sprite" value="[source]"/>
+ </Pass>
+ </Passes>
+</Effect>
diff --git a/tests/scenes/effects/corona.uip b/tests/scenes/effects/corona.uip
new file mode 100644
index 0000000..8446708
--- /dev/null
+++ b/tests/scenes/effects/corona.uip
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<UIP version="3" >
+ <Project >
+ <ProjectSettings author="" company="" presentationWidth="1280" presentationHeight="720" maintainAspect="False" >
+ <CustomColors count="16" >#ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff</CustomColors>
+ </ProjectSettings>
+ <Classes >
+ <Effect id="Corona" name="Corona" sourcepath="Corona.effect" />
+ </Classes>
+ <Graph >
+ <Scene id="Scene" >
+ <Layer id="Layer" >
+ <Camera id="Camera" />
+ <Light id="Light" />
+ <Model id="Cube" >
+ <Material id="Default" name="Default" />
+ </Model>
+ <Model id="Sphere" >
+ <Material id="Default_001" name="Default" />
+ </Model>
+ <Effect id="Corona_001" class="#Corona" />
+ </Layer>
+ </Scene>
+ </Graph>
+ <Logic >
+ <State name="Master Slide" component="#Scene" >
+ <Add ref="#Layer" />
+ <Add ref="#Camera" />
+ <Add ref="#Light" />
+ <State id="Scene-Slide1" name="Slide1" >
+ <Add ref="#Cube" name="Cube" position="-343.203 96.5458 0" rotation="-22.9052 -70.9856 10.3556" sourcepath="#Cube" >
+ <AnimationTrack property="rotation.x" type="EaseInOut" >0 -22.9052 100 100 10 -22.905 100 100</AnimationTrack>
+ <AnimationTrack property="rotation.y" type="EaseInOut" >0 -70.9856 100 100 10 200 100 100</AnimationTrack>
+ <AnimationTrack property="rotation.z" type="EaseInOut" >0 10.3556 100 100 10 10.356 100 100</AnimationTrack>
+ </Add>
+ <Add ref="#Default" />
+ <Add ref="#Sphere" name="Sphere" position="182.186 -32.7165 0" rotation="71.3254 -100.135 -168.32" scale="2.45138 1 1.78719" sourcepath="#Sphere" >
+ <AnimationTrack property="rotation.x" type="EaseInOut" >0 71.3254 100 100 10 71.325 100 100</AnimationTrack>
+ <AnimationTrack property="rotation.y" type="EaseInOut" >0 -100.135 100 100 10 300 100 100</AnimationTrack>
+ <AnimationTrack property="rotation.z" type="EaseInOut" >0 -168.32 100 100 10 -168.32 100 100</AnimationTrack>
+ </Add>
+ <Add ref="#Default_001" />
+ <Add ref="#Corona_001" name="Corona" />
+ </State>
+ </State>
+ </Logic>
+ </Project>
+</UIP>
diff --git a/tests/scenes/effects/maps/effects/noise.dds b/tests/scenes/effects/maps/effects/noise.dds
new file mode 100644
index 0000000..fdb5f20
--- /dev/null
+++ b/tests/scenes/effects/maps/effects/noise.dds
Binary files differ