aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.cmake.conf2
-rw-r--r--dependencies.yaml8
-rw-r--r--examples/quick3d/hellocube/main.qml6
-rw-r--r--examples/quick3d/lights/main.qml12
-rw-r--r--src/3rdparty/tinyexr/qt_attribution.json4
-rw-r--r--src/3rdparty/tinyexr/tinyexr.h3
-rw-r--r--src/assetutils/qquick3druntimeloader.cpp32
-rw-r--r--src/helpers/randominstancing.cpp1
-rw-r--r--src/quick3d/qquick3dinstancing.cpp2
-rw-r--r--src/quick3d/qquick3dloader.cpp5
-rw-r--r--src/quick3d/qquick3dmodel.cpp4
-rw-r--r--src/quick3d/qquick3dresourceloader.cpp4
-rw-r--r--src/quick3d/qquick3dskin.cpp6
-rw-r--r--src/quick3d/qquick3dtexture.cpp1
-rw-r--r--src/quick3dparticles/qquick3dparticlemodelblendparticle.cpp8
-rw-r--r--src/quick3dparticles/qquick3dparticlespriteparticle.cpp2
-rw-r--r--src/runtimerender/graphobjects/qssgrendergraphobject_p.h1
-rw-r--r--src/runtimerender/qssgrenderdefaultmaterialshadergenerator.cpp6
-rw-r--r--src/runtimerender/qssgrhicontext.cpp15
-rw-r--r--src/runtimerender/qssgrhicontext_p.h3
-rw-r--r--src/runtimerender/qssgrhicustommaterialsystem.cpp1
-rw-r--r--src/runtimerender/qssgrhiparticles.cpp1
-rw-r--r--src/runtimerender/rendererimpl/qssgrenderer.cpp11
-rw-r--r--src/runtimerender/rendererimpl/qssgvertexpipelineimpl.cpp8
-rw-r--r--src/runtimerender/rendererimpl/qssgvertexpipelineimpl_p.h1
-rw-r--r--src/runtimerender/resourcemanager/qssgrenderbuffermanager.cpp189
-rw-r--r--src/runtimerender/resourcemanager/qssgrenderbuffermanager_p.h11
-rw-r--r--tests/manual/dynamic3DTest/CMakeLists.txt2
-rw-r--r--tests/manual/dynamic3DTest/RiggedFigure.qml545
-rw-r--r--tests/manual/dynamic3DTest/main.qml59
-rw-r--r--tests/manual/dynamic3DTest/qml.qrc2
-rw-r--r--tests/manual/dynamic3DTest/riggedfigure.meshbin0 -> 26332 bytes
32 files changed, 802 insertions, 153 deletions
diff --git a/.cmake.conf b/.cmake.conf
index 647dec24..0435c0f3 100644
--- a/.cmake.conf
+++ b/.cmake.conf
@@ -1,3 +1,3 @@
-set(QT_REPO_MODULE_VERSION "6.5.6")
+set(QT_REPO_MODULE_VERSION "6.5.7")
set(QT_REPO_MODULE_PRERELEASE_VERSION_SEGMENT "alpha1")
list(APPEND QT_EXTRA_INTERNAL_TARGET_DEFINES "QT_NO_AS_CONST=1")
diff --git a/dependencies.yaml b/dependencies.yaml
index 70f269fd..e11d4e35 100644
--- a/dependencies.yaml
+++ b/dependencies.yaml
@@ -1,13 +1,13 @@
dependencies:
../tqtc-qtbase:
- ref: 5d8e9a8415562ba004b38508d91e1fa0254c17d3
+ ref: fc0e66eefe3a08428ca4a6e92c66f37ac126d3c4
required: true
../tqtc-qtdeclarative:
- ref: ff0a47c8f267e905113b82c53af2742027f0eca6
+ ref: 844f9b9b376838bcb44324984876f8bf99d85d38
required: true
../tqtc-qtquicktimeline:
- ref: 8d8c195e7206974608b1eedcc79c51b41eb34a1c
+ ref: 7190a3e4664062401263ecad62b2c33ca00f60cf
required: false
../tqtc-qtshadertools:
- ref: ac330781f44d174045e7a6770ed81c1dd29691f8
+ ref: 4c6749e750764297ee4237d9a1f2657b8313c4f7
required: true
diff --git a/examples/quick3d/hellocube/main.qml b/examples/quick3d/hellocube/main.qml
index a020a65b..ae1da5f8 100644
--- a/examples/quick3d/hellocube/main.qml
+++ b/examples/quick3d/hellocube/main.qml
@@ -133,7 +133,11 @@ Window {
}
onClicked: {
- if (clickme.state == "flipped") {
+ // do nothing while animating
+ if (flip1.running || flip2.running)
+ return;
+
+ if (clickme.state === "flipped") {
clickme.state = "";
flip2.start();
} else {
diff --git a/examples/quick3d/lights/main.qml b/examples/quick3d/lights/main.qml
index 3cf129a0..f79eb0ec 100644
--- a/examples/quick3d/lights/main.qml
+++ b/examples/quick3d/lights/main.qml
@@ -113,8 +113,8 @@ Window {
scale: Qt.vector3d(15, 15, 15)
eulerRotation.x: -90
materials: [
- DefaultMaterial {
- diffuseColor: Qt.rgba(0.8, 0.6, 0.4, 1.0)
+ PrincipledMaterial {
+ baseColor: Qt.rgba(0.8, 0.6, 0.4, 1.0)
}
]
}
@@ -123,8 +123,8 @@ Window {
z: -400
scale: Qt.vector3d(15, 15, 15)
materials: [
- DefaultMaterial {
- diffuseColor: Qt.rgba(0.8, 0.8, 0.9, 1.0)
+ PrincipledMaterial {
+ baseColor: Qt.rgba(0.8, 0.8, 0.9, 1.0)
}
]
}
@@ -132,8 +132,8 @@ Window {
RotatingTeaPot {
visible: !checkBoxCustomMaterial.checked
- material: DefaultMaterial {
- diffuseColor: Qt.rgba(0.9, 0.9, 0.9, 1.0)
+ material: PrincipledMaterial {
+ baseColor: Qt.rgba(0.9, 0.9, 0.9, 1.0)
}
animate: checkBoxAnimate.checked
}
diff --git a/src/3rdparty/tinyexr/qt_attribution.json b/src/3rdparty/tinyexr/qt_attribution.json
index a6c08f5d..aca61c02 100644
--- a/src/3rdparty/tinyexr/qt_attribution.json
+++ b/src/3rdparty/tinyexr/qt_attribution.json
@@ -7,8 +7,8 @@
"SecurityCritical": true,
"Homepage": "https://github.com/syoyo/tinyexr",
- "Version": "v1.0.8",
- "DownloadLocation": "https://github.com/syoyo/tinyexr/releases/tag/v1.0.8",
+ "Version": "v1.0.9",
+ "DownloadLocation": "https://github.com/syoyo/tinyexr/releases/tag/v1.0.9",
"License": "BSD 3-clause \"New\" or \"Revised\" License",
"LicenseId": "BSD-3-Clause",
diff --git a/src/3rdparty/tinyexr/tinyexr.h b/src/3rdparty/tinyexr/tinyexr.h
index d4001575..537e1984 100644
--- a/src/3rdparty/tinyexr/tinyexr.h
+++ b/src/3rdparty/tinyexr/tinyexr.h
@@ -9287,9 +9287,6 @@ int SaveEXR(const float *data, int width, int height, int components,
}
int ret = SaveEXRImageToFile(&image, &header, outfilename, err);
- if (ret != TINYEXR_SUCCESS) {
- return ret;
- }
free(header.channels);
free(header.pixel_types);
diff --git a/src/assetutils/qquick3druntimeloader.cpp b/src/assetutils/qquick3druntimeloader.cpp
index ed332802..04cd638f 100644
--- a/src/assetutils/qquick3druntimeloader.cpp
+++ b/src/assetutils/qquick3druntimeloader.cpp
@@ -176,26 +176,26 @@ void QQuick3DRuntimeLoader::loadSource()
break;
}
- emit statusChanged();
- emit errorStringChanged();
-
- if (m_status != Status::Success) {
+ if (m_status == Status::Success) {
+ // We create a dummy root node here, as it will be the parent to the first-level nodes
+ // and resources. If we use 'this' those first-level nodes/resources won't be deleted
+ // when a new scene is loaded.
+ m_root = new QQuick3DNode(this);
+ m_imported = QSSGRuntimeUtils::createScene(*m_root, scene);
+ m_assetId = scene.id;
+ m_boundsDirty = true;
+ m_instancingChanged = m_instancing != nullptr;
+ updateModels();
+ // Cleanup scene before deleting.
+ scene.cleanup();
+ } else {
m_source.clear();
emit sourceChanged();
- return;
}
- // We create a dummy root node here, as it will be the parent to the first-level nodes
- // and resources. If we use 'this' those first-level nodes/resources won't be deleted
- // when a new scene is loaded.
- m_root = new QQuick3DNode(this);
- m_imported = QSSGRuntimeUtils::createScene(*m_root, scene);
- m_assetId = scene.id;
- m_boundsDirty = true;
- m_instancingChanged = m_instancing != nullptr;
- updateModels();
- // Cleanup scene before deleting.
- scene.cleanup();
+ emit statusChanged();
+ emit errorStringChanged();
+
}
void QQuick3DRuntimeLoader::updateModels()
diff --git a/src/helpers/randominstancing.cpp b/src/helpers/randominstancing.cpp
index 37cb3b41..d63c8d9f 100644
--- a/src/helpers/randominstancing.cpp
+++ b/src/helpers/randominstancing.cpp
@@ -192,6 +192,7 @@ void QQuick3DRandomInstancing::setInstanceCount(int instanceCount)
if (instanceCount == m_randomCount)
return;
m_randomCount = instanceCount;
+ emit instanceCountChanged();
m_dirty = true;
markDirty();
}
diff --git a/src/quick3d/qquick3dinstancing.cpp b/src/quick3d/qquick3dinstancing.cpp
index ee63e54b..6046f5a2 100644
--- a/src/quick3d/qquick3dinstancing.cpp
+++ b/src/quick3d/qquick3dinstancing.cpp
@@ -689,7 +689,7 @@ void QQuick3DInstanceListEntry::setRotation(QQuaternion rotation)
}
/*!
- \qmlproperty vector3d QtQuick3D::InstanceListEntry::color
+ \qmlproperty color QtQuick3D::InstanceListEntry::color
This property specifies the color for the instance.
*/
diff --git a/src/quick3d/qquick3dloader.cpp b/src/quick3d/qquick3dloader.cpp
index c1a1ea19..49e9de3f 100644
--- a/src/quick3d/qquick3dloader.cpp
+++ b/src/quick3d/qquick3dloader.cpp
@@ -61,12 +61,9 @@ QQuick3DLoader::QQuick3DLoader(QQuick3DNode *parent)
QQuick3DLoader::~QQuick3DLoader()
{
- delete m_itemContext;
- m_itemContext = nullptr;
+ clear();
delete m_incubator;
m_incubator = nullptr;
- disposeInitialPropertyValues();
- clear();
}
/*!
diff --git a/src/quick3d/qquick3dmodel.cpp b/src/quick3d/qquick3dmodel.cpp
index 597bb62d..53b455fc 100644
--- a/src/quick3d/qquick3dmodel.cpp
+++ b/src/quick3d/qquick3dmodel.cpp
@@ -1033,7 +1033,7 @@ void QQuick3DModel::qmlClearMaterials(QQmlListProperty<QQuick3DMaterial> *list)
mat.refed = false;
}
}
- mat.material->disconnect(self, SLOT(onMaterialDestroyed(QObject*)));
+ disconnect(mat.material, &QQuick3DMaterial::destroyed, self, &QQuick3DModel::onMaterialDestroyed);
}
self->m_materials.clear();
self->markDirty(QQuick3DModel::MaterialsDirty);
@@ -1110,7 +1110,7 @@ void QQuick3DModel::qmlClearMorphTargets(QQmlListProperty<QQuick3DMorphTarget> *
for (const auto &morph : std::as_const(self->m_morphTargets)) {
if (morph->parentItem() == nullptr)
QQuick3DObjectPrivate::get(morph)->derefSceneManager();
- morph->disconnect(self, SLOT(onMorphTargetDestroyed(QObject*)));
+ disconnect(morph, &QQuick3DMorphTarget::destroyed, self, &QQuick3DModel::onMorphTargetDestroyed);
}
self->m_morphTargets.clear();
self->m_numMorphAttribs = 0;
diff --git a/src/quick3d/qquick3dresourceloader.cpp b/src/quick3d/qquick3dresourceloader.cpp
index f508ae73..ddeb8a02 100644
--- a/src/quick3d/qquick3dresourceloader.cpp
+++ b/src/quick3d/qquick3dresourceloader.cpp
@@ -236,7 +236,7 @@ void QQuick3DResourceLoader::qmlClearGeometries(QQmlListProperty<QQuick3DGeometr
for (const auto &geometry : std::as_const(self->m_geometries)) {
if (geometry->parentItem() == nullptr)
QQuick3DObjectPrivate::get(geometry)->derefSceneManager();
- geometry->disconnect(self, SLOT(onMorphTargetDestroyed(QObject*)));
+ disconnect(geometry, &QQuick3DGeometry::destroyed, self, &QQuick3DResourceLoader::onGeometryDestroyed);
}
self->m_geometries.clear();
@@ -292,7 +292,7 @@ void QQuick3DResourceLoader::qmlClearTextures(QQmlListProperty<QQuick3DTexture>
for (const auto &data : std::as_const(self->m_textures)) {
if (data->parentItem() == nullptr)
QQuick3DObjectPrivate::get(data)->derefSceneManager();
- data->disconnect(self, SLOT(onMorphTargetDestroyed(QObject*)));
+ disconnect(data, &QQuick3DTextureData::destroyed, self, &QQuick3DResourceLoader::onTextureDestroyed);
}
self->m_textures.clear();
self->markDirty(QQuick3DResourceLoader::TexturesDirty);
diff --git a/src/quick3d/qquick3dskin.cpp b/src/quick3d/qquick3dskin.cpp
index e5f0568b..688a847f 100644
--- a/src/quick3d/qquick3dskin.cpp
+++ b/src/quick3d/qquick3dskin.cpp
@@ -145,9 +145,9 @@ qsizetype QQuick3DSkin::qmlJointsCount(QQmlListProperty<QQuick3DNode> *list)
void QQuick3DSkin::qmlClearJoints(QQmlListProperty<QQuick3DNode> *list)
{
QQuick3DSkin *self = static_cast<QQuick3DSkin *>(list->object);
- for (const auto &joint : std::as_const(self->m_joints)) {
- joint->disconnect(self, SLOT(onJointDestroyed(QObject*)));
- }
+ for (const auto &joint : std::as_const(self->m_joints))
+ disconnect(joint, &QQuick3DNode::destroyed, self, &QQuick3DSkin::onJointDestroyed);
+
self->m_joints.clear();
self->m_boneData.clear();
self->markDirty();
diff --git a/src/quick3d/qquick3dtexture.cpp b/src/quick3d/qquick3dtexture.cpp
index fb6427cd..1372da8b 100644
--- a/src/quick3d/qquick3dtexture.cpp
+++ b/src/quick3d/qquick3dtexture.cpp
@@ -8,6 +8,7 @@
#include <QtQml/QQmlFile>
#include <QtQuick/QQuickItem>
#include <QtQuick/private/qquickitem_p.h>
+#include <QSGTextureProvider>
#include <QtCore/qmath.h>
#include "qquick3dobject_p.h"
diff --git a/src/quick3dparticles/qquick3dparticlemodelblendparticle.cpp b/src/quick3dparticles/qquick3dparticlemodelblendparticle.cpp
index 1e2eb2f4..911a42f7 100644
--- a/src/quick3dparticles/qquick3dparticlemodelblendparticle.cpp
+++ b/src/quick3dparticles/qquick3dparticlemodelblendparticle.cpp
@@ -568,9 +568,11 @@ QSSGRenderGraphObject *QQuick3DParticleModelBlendParticle::updateSpatialNode(QSS
Q_QUICK3D_PROFILE_ASSIGN_ID_SG(this, spatialNode);
}
#if QT_CONFIG(qml_debug)
- auto *geometrySpatialNode = QQuick3DObjectPrivate::get(m_modelGeometry)->spatialNode;
- if (geometrySpatialNode)
- Q_QUICK3D_PROFILE_ASSIGN_ID_SG(this, geometrySpatialNode);
+ if (m_modelGeometry) {
+ auto *geometrySpatialNode = QQuick3DObjectPrivate::get(m_modelGeometry)->spatialNode;
+ if (geometrySpatialNode)
+ Q_QUICK3D_PROFILE_ASSIGN_ID_SG(this, geometrySpatialNode);
+ }
#endif
QSSGRenderModel *model = static_cast<QSSGRenderModel *>(spatialNode);
diff --git a/src/quick3dparticles/qquick3dparticlespriteparticle.cpp b/src/quick3dparticles/qquick3dparticlespriteparticle.cpp
index 4a743977..e66b5903 100644
--- a/src/quick3dparticles/qquick3dparticlespriteparticle.cpp
+++ b/src/quick3dparticles/qquick3dparticlespriteparticle.cpp
@@ -766,7 +766,7 @@ void QQuick3DParticleSpriteParticle::qmlClearLights(QQmlListProperty<QQuick3DAbs
for (const auto &light : std::as_const(self->m_lights)) {
if (light->parentItem() == nullptr)
QQuick3DObjectPrivate::get(light)->derefSceneManager();
- light->disconnect(self, SLOT(onLightDestroyed(QObject*)));
+ disconnect(light, &QQuick3DParticleSpriteParticle::destroyed, self, &QQuick3DParticleSpriteParticle::onLightDestroyed);
}
self->m_lights.clear();
self->updateFeatureLevel();
diff --git a/src/runtimerender/graphobjects/qssgrendergraphobject_p.h b/src/runtimerender/graphobjects/qssgrendergraphobject_p.h
index 3a163fa8..6ebfc1b7 100644
--- a/src/runtimerender/graphobjects/qssgrendergraphobject_p.h
+++ b/src/runtimerender/graphobjects/qssgrendergraphobject_p.h
@@ -126,6 +126,7 @@ struct Q_QUICK3DRUNTIMERENDER_EXPORT QSSGRenderGraphObject
|| (isTexture(type))
|| (type == Type::Geometry)
|| (type == Type::TextureData)
+ || (type == Type::ModelInstance)
|| (type == Type::ResourceLoader));
}
diff --git a/src/runtimerender/qssgrenderdefaultmaterialshadergenerator.cpp b/src/runtimerender/qssgrenderdefaultmaterialshadergenerator.cpp
index 380f25ce..8e612584 100644
--- a/src/runtimerender/qssgrenderdefaultmaterialshadergenerator.cpp
+++ b/src/runtimerender/qssgrenderdefaultmaterialshadergenerator.cpp
@@ -362,11 +362,13 @@ static void generateShadowMapOcclusion(QSSGStageGeneratorBase &fragmentShader,
fragmentShader.addUniform(names.shadowControlStem, "vec4");
fragmentShader.addUniform(names.shadowMatrixStem, "mat4");
+ fragmentShader << " if (" << names.shadowControlStem << ".y > 0.01) {\n";
if (inType != QSSGRenderLight::Type::DirectionalLight) {
- fragmentShader << " qt_shadow_map_occl = qt_sampleCubemap(" << names.shadowCubeStem << ", " << names.shadowControlStem << ", " << names.shadowMatrixStem << ", " << lightVarNames.lightPos << ".xyz, qt_varWorldPos, vec2(1.0, " << names.shadowControlStem << ".z));\n";
+ fragmentShader << " qt_shadow_map_occl = qt_sampleCubemap(" << names.shadowCubeStem << ", " << names.shadowControlStem << ", " << names.shadowMatrixStem << ", " << lightVarNames.lightPos << ".xyz, qt_varWorldPos, vec2(1.0, " << names.shadowControlStem << ".z));\n";
} else {
- fragmentShader << " qt_shadow_map_occl = qt_sampleOrthographic(" << names.shadowMapStem << ", " << names.shadowControlStem << ", " << names.shadowMatrixStem << ", qt_varWorldPos, vec2(1.0, " << names.shadowControlStem << ".z));\n";
+ fragmentShader << " qt_shadow_map_occl = qt_sampleOrthographic(" << names.shadowMapStem << ", " << names.shadowControlStem << ", " << names.shadowMatrixStem << ", qt_varWorldPos, vec2(1.0, " << names.shadowControlStem << ".z));\n";
}
+ fragmentShader << " }\n";
} else {
fragmentShader << " qt_shadow_map_occl = 1.0;\n";
}
diff --git a/src/runtimerender/qssgrhicontext.cpp b/src/runtimerender/qssgrhicontext.cpp
index 03ac1a28..09f4adc4 100644
--- a/src/runtimerender/qssgrhicontext.cpp
+++ b/src/runtimerender/qssgrhicontext.cpp
@@ -962,6 +962,12 @@ QRhiShaderResourceBindings *QSSGRhiContext::srb(const QSSGRhiShaderResourceBindi
return srb;
}
+void QSSGRhiContext::releaseCachedSrb(QSSGRhiShaderResourceBindingList &bindings)
+{
+ auto srb = m_srbCache.take(bindings);
+ delete srb;
+}
+
void QSSGRhiContext::releaseDrawCallData(QSSGRhiDrawCallData &dcd)
{
delete dcd.ubuf;
@@ -1281,4 +1287,13 @@ void QSSGRhiContextStats::printRenderPass(const QSSGRhiContextStats::RenderPassI
}
}
+void QSSGRhiContext::releaseInstanceBuffer(QSSGRenderInstanceTable *instanceTable)
+{
+ auto it = m_instanceBuffers.constFind(instanceTable);
+ if (it != m_instanceBuffers.constEnd()) {
+ it->buffer->destroy();
+ m_instanceBuffers.erase(it);
+ }
+}
+
QT_END_NAMESPACE
diff --git a/src/runtimerender/qssgrhicontext_p.h b/src/runtimerender/qssgrhicontext_p.h
index 4aaee51a..f4e4104e 100644
--- a/src/runtimerender/qssgrhicontext_p.h
+++ b/src/runtimerender/qssgrhicontext_p.h
@@ -951,6 +951,7 @@ public:
QRhiShaderResourceBindings *srb(const QSSGRhiShaderResourceBindingList &bindings);
void releaseDrawCallData(QSSGRhiDrawCallData &dcd);
+ void releaseCachedSrb(QSSGRhiShaderResourceBindingList &bindings);
QRhiGraphicsPipeline *pipeline(const QSSGGraphicsPipelineStateKey &key,
QRhiRenderPassDescriptor *rpDesc,
QRhiShaderResourceBindings *srb);
@@ -1000,6 +1001,8 @@ public:
return m_instanceBuffersLod[model];
}
+ void releaseInstanceBuffer(QSSGRenderInstanceTable *instanceTable);
+
QSSGRhiParticleData &particleData(const QSSGRenderGraphObject *particlesOrModel)
{
return m_particleData[particlesOrModel];
diff --git a/src/runtimerender/qssgrhicustommaterialsystem.cpp b/src/runtimerender/qssgrhicustommaterialsystem.cpp
index 2e873f80..cb372ec4 100644
--- a/src/runtimerender/qssgrhicustommaterialsystem.cpp
+++ b/src/runtimerender/qssgrhicustommaterialsystem.cpp
@@ -468,6 +468,7 @@ void QSSGCustomMaterialSystem::rhiPrepareRenderable(QSSGRhiGraphicsPipelineState
bool srbChanged = false;
if (!srb || bindings != dcd.bindings) {
srb = rhiCtx->srb(bindings);
+ rhiCtx->releaseCachedSrb(dcd.bindings);
dcd.bindings = bindings;
srbChanged = true;
}
diff --git a/src/runtimerender/qssgrhiparticles.cpp b/src/runtimerender/qssgrhiparticles.cpp
index f84b00ba..f121f35e 100644
--- a/src/runtimerender/qssgrhiparticles.cpp
+++ b/src/runtimerender/qssgrhiparticles.cpp
@@ -490,6 +490,7 @@ void QSSGParticleRenderer::rhiPrepareRenderable(QSSGRhiShaderPipeline &shaderPip
bool srbChanged = false;
if (!srb || bindings != dcd.bindings) {
srb = rhiCtx->srb(bindings);
+ rhiCtx->releaseCachedSrb(dcd.bindings);
dcd.bindings = bindings;
srbChanged = true;
}
diff --git a/src/runtimerender/rendererimpl/qssgrenderer.cpp b/src/runtimerender/rendererimpl/qssgrenderer.cpp
index 951a6609..6e1d1358 100644
--- a/src/runtimerender/rendererimpl/qssgrenderer.cpp
+++ b/src/runtimerender/rendererimpl/qssgrenderer.cpp
@@ -202,9 +202,13 @@ static void cleanupResourcesImpl(const QSSGRenderContextInterface &rci, const Co
} else if (resource->type == QSSGRenderGraphObject::Type::Model) {
auto model = static_cast<QSSGRenderModel*>(resource);
rhi->cleanupDrawCallData(model);
+ delete model->particleBuffer;
} else if (resource->type == QSSGRenderGraphObject::Type::TextureData) {
auto textureData = static_cast<QSSGRenderTextureData *>(resource);
bufferManager->releaseTextureData(textureData);
+ } else if (resource->type == QSSGRenderGraphObject::Type::ModelInstance) {
+ auto *table = static_cast<QSSGRenderInstanceTable *>(resource);
+ rhi->releaseInstanceBuffer(table);
}
// ### There might be more types that need to be supported
@@ -853,7 +857,7 @@ static void setupCameraForShadowMap(const QSSGRenderCamera &inCamera,
theCamera.clipFar = 0.5f * finalDims.z();
theCamera.localTransform = QSSGRenderNode::calculateTransformMatrix(center, QSSGRenderNode::initScale, inLightPivot, QQuaternion::fromDirection(forward, up));
} else if (inLight->type == QSSGRenderLight::Type::PointLight) {
- theCamera.lookAt(inLightPos, QVector3D(0, 1.0, 0), QVector3D(0, 0, 0), inLightPivot);
+ theCamera.lookAt(inLightPos, QVector3D(0, 1.0, 0), QVector3D(0, 0, 0), QVector3D(0, 0, 0));
}
theCamera.calculateGlobalVariables(theViewport);
@@ -971,14 +975,14 @@ static void setupCubeShadowCameras(const QSSGRenderLight *inLight, QSSGRenderCam
};
const QVector3D inLightPos = inLight->getGlobalPos();
- const QVector3D inLightPivot = inLight->pivot;
+ const QVector3D lightPivot = QVector3D(0, 0, 0);
for (int i = 0; i < 6; ++i) {
inCameras[i].parent = nullptr;
inCameras[i].clipNear = 1.0f;
inCameras[i].clipFar = qMax<float>(2.0f, inLight->m_shadowMapFar);
inCameras[i].fov = qDegreesToRadians(90.f);
- inCameras[i].localTransform = QSSGRenderNode::calculateTransformMatrix(inLightPos, QSSGRenderNode::initScale, inLightPivot, rotOfs[i]);
+ inCameras[i].localTransform = QSSGRenderNode::calculateTransformMatrix(inLightPos, QSSGRenderNode::initScale, lightPivot, rotOfs[i]);
inCameras[i].calculateGlobalVariables(theViewport);
}
@@ -1449,6 +1453,7 @@ void RenderHelpers::rhiPrepareRenderable(QSSGRhiContext *rhiCtx,
bool srbChanged = false;
if (!srb || bindings != dcd.bindings) {
srb = rhiCtx->srb(bindings);
+ rhiCtx->releaseCachedSrb(dcd.bindings);
dcd.bindings = bindings;
srbChanged = true;
}
diff --git a/src/runtimerender/rendererimpl/qssgvertexpipelineimpl.cpp b/src/runtimerender/rendererimpl/qssgvertexpipelineimpl.cpp
index 830aca17..20add5d6 100644
--- a/src/runtimerender/rendererimpl/qssgvertexpipelineimpl.cpp
+++ b/src/runtimerender/rendererimpl/qssgvertexpipelineimpl.cpp
@@ -181,7 +181,6 @@ void QSSGMaterialVertexPipeline::beginVertexGeneration(const QSSGShaderDefaultMa
if (materialAdapter->usesCustomSkinning()) {
vertexShader.addInclude("skinanim.glsllib");
vertexShader.addUniform("qt_boneTexture", "sampler2D");
- m_hasSkinning = false;
}
if (!materialAdapter->isUnshaded()) {
@@ -310,7 +309,8 @@ void QSSGMaterialVertexPipeline::beginVertexGeneration(const QSSGShaderDefaultMa
if (m_hasMorphing && !hasCustomVertexShader)
vertexShader.append(" qt_vertPosition.xyz = qt_getMorphPosition(qt_vertPosition.xyz);");
- if (m_hasSkinning) {
+ m_needsSkinning = m_hasSkinning && !materialAdapter->usesCustomSkinning();
+ if (m_needsSkinning) {
vertexShader.append(" mat4 skinMat = mat4(1);");
vertexShader.append(" if (qt_vertWeights != vec4(0.0)) {");
vertexShader.append(" skinMat = qt_getSkinMatrix(qt_vertJoints, qt_vertWeights);");
@@ -400,7 +400,7 @@ void QSSGMaterialVertexPipeline::doGenerateVarTangent(const QSSGShaderDefaultMat
{
if (m_hasMorphing)
vertex() << " qt_vertTangent = qt_getMorphTangent(qt_vertTangent);\n";
- if (m_hasSkinning) {
+ if (m_needsSkinning) {
vertex() << " if (qt_vertWeights != vec4(0.0))\n"
<< " qt_vertTangent = (skinMat * vec4(qt_vertTangent, 0.0)).xyz;\n";
@@ -420,7 +420,7 @@ void QSSGMaterialVertexPipeline::doGenerateVarBinormal(const QSSGShaderDefaultMa
{
if (m_hasMorphing)
vertex() << " qt_vertBinormal = qt_getMorphBinormal(qt_vertBinormal);\n";
- if (m_hasSkinning) {
+ if (m_needsSkinning) {
vertex() << " if (qt_vertWeights != vec4(0.0))\n"
<< " qt_vertBinormal = (skinMat * vec4(qt_vertBinormal, 0.0)).xyz;\n";
}
diff --git a/src/runtimerender/rendererimpl/qssgvertexpipelineimpl_p.h b/src/runtimerender/rendererimpl/qssgvertexpipelineimpl_p.h
index 3fea10a2..d9dfe3e2 100644
--- a/src/runtimerender/rendererimpl/qssgvertexpipelineimpl_p.h
+++ b/src/runtimerender/rendererimpl/qssgvertexpipelineimpl_p.h
@@ -49,6 +49,7 @@ struct QSSGMaterialVertexPipeline
GenerationFlags m_generationFlags;
bool m_hasSkinning;
+ bool m_needsSkinning;
bool m_hasMorphing;
TStrTableStrMap m_interpolationParameters;
QList<QByteArray> m_addedFunctions;
diff --git a/src/runtimerender/resourcemanager/qssgrenderbuffermanager.cpp b/src/runtimerender/resourcemanager/qssgrenderbuffermanager.cpp
index 721ba570..8d2fe95b 100644
--- a/src/runtimerender/resourcemanager/qssgrenderbuffermanager.cpp
+++ b/src/runtimerender/resourcemanager/qssgrenderbuffermanager.cpp
@@ -207,7 +207,7 @@ QSSGRenderImageTexture QSSGBufferManager::loadRenderImage(const QSSGRenderImage
CreateRhiTextureFlags rhiTexFlags = ScanForTransparency;
if (image->type == QSSGRenderGraphObject::Type::ImageCube)
rhiTexFlags |= CubeMap;
- if (!createRhiTexture(foundIt.value().renderImageTexture, theLoadedTexture.data(), inMipMode, rhiTexFlags, QFileInfo(path).fileName())) {
+ if (!setRhiTexture(foundIt.value().renderImageTexture, theLoadedTexture.data(), inMipMode, rhiTexFlags, QFileInfo(path).fileName())) {
foundIt.value() = ImageData();
} else {
#ifdef QSSG_RENDERBUFFER_DEBUGGING
@@ -237,10 +237,15 @@ QSSGRenderImageTexture QSSGBufferManager::loadTextureData(QSSGRenderTextureData
if (theImageData == customTextureMap.end()) {
theImageData = customTextureMap.insert(imageKey, ImageData());
} else if (data->generationId() != theImageData->generationId) {
- // release first
- releaseTextureData(imageKey);
- // reinsert the placeholder since releaseTextureData removed from map
- theImageData = customTextureMap.insert(imageKey, ImageData());
+ auto &renderImageTexture = theImageData.value().renderImageTexture;
+ if (toRhiFormat(data->format()) != renderImageTexture.m_texture->format()
+ || data->size() != renderImageTexture.m_texture->pixelSize()) {
+ // release first
+ releaseTextureData(imageKey);
+ // reinsert the placeholder since releaseTextureData removed from map
+ theImageData = customTextureMap.insert(imageKey, ImageData());
+ }
+ theImageData->generationId = data->generationId();
} else {
// Return the currently loaded texture
theImageData.value().usageCounts[currentLayer]++;
@@ -252,12 +257,14 @@ QSSGRenderImageTexture QSSGBufferManager::loadTextureData(QSSGRenderTextureData
if (!data->textureData().isNull()) {
theLoadedTexture.reset(QSSGLoadedTexture::loadTextureData(data));
theLoadedTexture->ownsData = false;
- if (createRhiTexture(theImageData.value().renderImageTexture, theLoadedTexture.data(), inMipMode, {}, data->debugObjectName)) {
-#ifdef QSSG_RENDERBUFFER_DEBUGGING
- qDebug() << "+ uploadTexture: " << data << currentLayer;
-#endif
- theImageData.value().generationId = data->generationId();
- increaseMemoryStat(theImageData.value().renderImageTexture.m_texture);
+
+ bool wasTextureCreated = false;
+
+ if (setRhiTexture(theImageData.value().renderImageTexture, theLoadedTexture.data(), inMipMode, {}, data->debugObjectName, &wasTextureCreated)) {
+ if (wasTextureCreated) {
+ theImageData.value().generationId = data->generationId();
+ increaseMemoryStat(theImageData.value().renderImageTexture.m_texture);
+ }
} else {
theImageData.value() = ImageData();
}
@@ -286,7 +293,7 @@ QSSGRenderImageTexture QSSGBufferManager::loadLightmap(const QSSGRenderModel &mo
qCWarning(WARNING, "Failed to load lightmap image: %s", qPrintable(imagePath));
foundIt = imageMap.insert(imageKey, ImageData());
if (theLoadedTexture) {
- if (!createRhiTexture(foundIt.value().renderImageTexture, theLoadedTexture.data(), MipModeDisable, {}, imagePath))
+ if (!setRhiTexture(foundIt.value().renderImageTexture, theLoadedTexture.data(), MipModeDisable, {}, imagePath))
foundIt.value() = ImageData();
result = foundIt.value().renderImageTexture;
}
@@ -887,111 +894,134 @@ bool QSSGBufferManager::createEnvironmentMap(const QSSGLoadedTexture *inImage, Q
return true;
}
-bool QSSGBufferManager::createRhiTexture(QSSGRenderImageTexture &texture,
- const QSSGLoadedTexture *inTexture,
- MipMode inMipMode,
- CreateRhiTextureFlags inFlags,
- const QString &debugObjectName)
+bool QSSGBufferManager::setRhiTexture(QSSGRenderImageTexture &texture,
+ const QSSGLoadedTexture *inTexture,
+ MipMode inMipMode,
+ CreateRhiTextureFlags inFlags,
+ const QString &debugObjectName,
+ bool *wasTextureCreated)
{
Q_ASSERT(inMipMode != MipModeFollowRenderImage);
QVarLengthArray<QRhiTextureUploadEntry, 16> textureUploads;
int textureSampleCount = 1;
QRhiTexture::Flags textureFlags;
- int mipmapCount = 1;
const bool checkTransp = inFlags.testFlag(ScanForTransparency);
bool hasTransp = false;
const auto &context = m_contextInterface->rhiContext();
auto *rhi = context->rhi();
- QRhiTexture::Format rhiFormat = QRhiTexture::UnknownFormat;
- QSize size;
- if (inTexture->format.format == QSSGRenderTextureFormat::Format::RGBE8)
- texture.m_flags.setRgbe8(true);
- if (inMipMode == MipModeBsdf && (inTexture->data || inTexture->textureFileData.isValid())) {
- // Before creating an environment map, check if the provided texture is a
- // pre-baked environment map
- if (inTexture->textureFileData.isValid() && inTexture->textureFileData.keyValueMetadata().contains("QT_IBL_BAKER_VERSION")) {
- Q_ASSERT(inTexture->textureFileData.numFaces() == 6);
- Q_ASSERT(inTexture->textureFileData.numLevels() >= 5);
-
- const QTextureFileData &tex = inTexture->textureFileData;
- rhiFormat = toRhiFormat(inTexture->format.format);
- size = tex.size();
- mipmapCount = tex.numLevels();
- const int faceCount = tex.numFaces();
- QRhiTexture *environmentCubeMap = rhi->newTexture(rhiFormat, size, 1, QRhiTexture::CubeMap | QRhiTexture::MipMapped);
- environmentCubeMap->setName(debugObjectName.toLatin1());
- environmentCubeMap->create();
+
+ QRhiTexture::Format rhiFormat = toRhiFormat(inTexture->format.format);
+ const QTextureFileData &texFileData = inTexture->textureFileData;
+ QSize size = texFileData.isValid() ? texFileData.size() : QSize(inTexture->width, inTexture->height);
+ int mipmapCount = texFileData.isValid() ? texFileData.numLevels() : 1;
+ bool generateMipmaps = false;
+
+ if (wasTextureCreated)
+ *wasTextureCreated = false;
+
+ if (texture.m_texture == nullptr) {
+ if (inTexture->format.format == QSSGRenderTextureFormat::Format::RGBE8)
+ texture.m_flags.setRgbe8(true);
+ if (inMipMode == MipModeBsdf && (inTexture->data || texFileData.isValid())) {
+ // Before creating an environment map, check if the provided texture is a
+ // pre-baked environment map
+ if (texFileData.isValid() && texFileData.keyValueMetadata().contains("QT_IBL_BAKER_VERSION")) {
+ Q_ASSERT(texFileData.numFaces() == 6);
+ Q_ASSERT(texFileData.numLevels() >= 5);
+
+ QRhiTexture *environmentCubeMap = rhi->newTexture(rhiFormat, size, 1, QRhiTexture::CubeMap | QRhiTexture::MipMapped);
+ environmentCubeMap->setName(debugObjectName.toLatin1());
+ environmentCubeMap->create();
+ texture.m_texture = environmentCubeMap;
+ context->registerTexture(texture.m_texture);
+ if (wasTextureCreated)
+ *wasTextureCreated = true;
+ // If we get this far then we need to create an environment map at runtime.
+ } else if (createEnvironmentMap(inTexture, &texture, debugObjectName)) {
+ context->registerTexture(texture.m_texture);
+ if (wasTextureCreated)
+ *wasTextureCreated = true;
+ return true;
+ } else {
+ qWarning() << "Failed to create environment map";
+ return false;
+ }
+ } else {
+ if (inMipMode == MipModeEnable && mipmapCount == 1) {
+ textureFlags |= QRhiTexture::Flag::UsedWithGenerateMips;
+ generateMipmaps = true;
+ mipmapCount = rhi->mipLevelsForSize(size);
+ }
+
+ if (mipmapCount > 1)
+ textureFlags |= QRhiTexture::Flag::MipMapped;
+
+ if (inFlags.testFlag(CubeMap))
+ textureFlags |= QRhiTexture::CubeMap;
+
+ texture.m_texture = rhi->newTexture(rhiFormat, size, textureSampleCount, textureFlags);
+
+ texture.m_texture->setName(debugObjectName.toLatin1());
+ texture.m_texture->create();
+ context->registerTexture(texture.m_texture);
+ if (wasTextureCreated)
+ *wasTextureCreated = true;
+ }
+ }
+
+ // Update resources
+ if (inMipMode == MipModeBsdf && (inTexture->data || texFileData.isValid())) {
+ if (texFileData.isValid() && texFileData.keyValueMetadata().contains("QT_IBL_BAKER_VERSION")) {
+ const int faceCount = texFileData.numFaces();
for (int layer = 0; layer < faceCount; ++layer) {
for (int level = 0; level < mipmapCount; ++level) {
QRhiTextureSubresourceUploadDescription subDesc;
subDesc.setSourceSize(sizeForMipLevel(level, size));
- subDesc.setData(tex.getDataView(level, layer).toByteArray());
+ subDesc.setData(texFileData.getDataView(level, layer).toByteArray());
textureUploads << QRhiTextureUploadEntry { layer, level, subDesc };
}
}
- texture.m_texture = environmentCubeMap;
QRhiTextureUploadDescription uploadDescription;
uploadDescription.setEntries(textureUploads.cbegin(), textureUploads.cend());
auto *rub = rhi->nextResourceUpdateBatch();
- rub->uploadTexture(environmentCubeMap, uploadDescription);
+ rub->uploadTexture(texture.m_texture, uploadDescription);
context->commandBuffer()->resourceUpdate(rub);
texture.m_mipmapCount = mipmapCount;
- context->registerTexture(texture.m_texture);
- return true;
- }
-
- // If we get this far then we need to create an environment map at runtime.
- if (createEnvironmentMap(inTexture, &texture, debugObjectName)) {
- context->registerTexture(texture.m_texture);
return true;
- } else {
- qWarning() << "Failed to create environment map";
- return false;
}
- } else if (inTexture->textureFileData.isValid()) {
- const QTextureFileData &tex = inTexture->textureFileData;
- size = tex.size();
- mipmapCount = tex.numLevels();
-
+ } else if (texFileData.isValid()) {
int numFaces = 1;
// Just having a container with 6 faces is not enough, we only treat it
// as a cubemap if it was requested to be treated as such. Otherwise
// only face 0 is used.
- if (tex.numFaces() == 6 && inFlags.testFlag(CubeMap))
+ if (texFileData.numFaces() == 6 && inFlags.testFlag(CubeMap))
numFaces = 6;
- for (int level = 0; level < tex.numLevels(); ++level) {
+ for (int level = 0; level < texFileData.numLevels(); ++level) {
QRhiTextureSubresourceUploadDescription subDesc;
subDesc.setSourceSize(sizeForMipLevel(level, size));
for (int face = 0; face < numFaces; ++face) {
- subDesc.setData(tex.getDataView(level, face).toByteArray());
+ subDesc.setData(texFileData.getDataView(level, face).toByteArray());
textureUploads << QRhiTextureUploadEntry{ face, level, subDesc };
}
}
-
- rhiFormat = toRhiFormat(inTexture->format.format);
if (checkTransp) {
- auto glFormat = tex.glInternalFormat() ? tex.glInternalFormat() : tex.glFormat();
+ auto glFormat = texFileData.glInternalFormat() ? texFileData.glInternalFormat() : texFileData.glFormat();
hasTransp = !QSGCompressedTexture::formatIsOpaque(glFormat);
}
} else {
QRhiTextureSubresourceUploadDescription subDesc;
if (!inTexture->image.isNull()) {
- rhiFormat = toRhiFormat(inTexture->format.format);
- size = inTexture->image.size();
subDesc.setImage(inTexture->image);
if (checkTransp)
hasTransp = QImageData::get(inTexture->image)->checkForAlphaPixels();
} else if (inTexture->data) {
- rhiFormat = toRhiFormat(inTexture->format.format);
- size = QSize(inTexture->width, inTexture->height);
QByteArray buf(static_cast<const char *>(inTexture->data), qMax(0, int(inTexture->dataSizeInBytes)));
subDesc.setData(buf);
if (checkTransp)
hasTransp = inTexture->scanForTransparency();
-
}
subDesc.setSourceSize(size);
if (!subDesc.data().isEmpty() || !subDesc.image().isNull())
@@ -1006,19 +1036,6 @@ bool QSSGBufferManager::createRhiTexture(QSSGRenderImageTexture &texture,
const auto validTexSize = size.width() <= maxTextureSize && size.height() <= maxTextureSize;
QSSG_ASSERT_X(validTexSize, qPrintable(textureSizeWarning(size, maxTextureSize)), return false);
- bool generateMipmaps = false;
- if (inMipMode == MipModeEnable && mipmapCount == 1) {
- textureFlags |= QRhiTexture::Flag::UsedWithGenerateMips;
- generateMipmaps = true;
- mipmapCount = rhi->mipLevelsForSize(size);
- }
-
- if (mipmapCount > 1)
- textureFlags |= QRhiTexture::Flag::MipMapped;
-
- if (inFlags.testFlag(CubeMap))
- textureFlags |= QRhiTexture::CubeMap;
-
if (textureUploads.isEmpty() || size.isEmpty() || rhiFormat == QRhiTexture::UnknownFormat) {
qWarning() << "Could not load texture";
return false;
@@ -1027,28 +1044,20 @@ bool QSSGBufferManager::createRhiTexture(QSSGRenderImageTexture &texture,
return false;
}
- auto *tex = rhi->newTexture(rhiFormat, size, textureSampleCount, textureFlags);
-
- QSSG_ASSERT(tex != nullptr, return false);
-
- tex->setName(debugObjectName.toLatin1());
- tex->create();
+ QSSG_ASSERT(texture.m_texture != nullptr, return false);
if (checkTransp)
texture.m_flags.setHasTransparency(hasTransp);
- texture.m_texture = tex;
QRhiTextureUploadDescription uploadDescription;
uploadDescription.setEntries(textureUploads.cbegin(), textureUploads.cend());
auto *rub = rhi->nextResourceUpdateBatch(); // TODO: optimize
- rub->uploadTexture(tex, uploadDescription);
+ rub->uploadTexture(texture.m_texture, uploadDescription);
if (generateMipmaps)
- rub->generateMips(tex);
+ rub->generateMips(texture.m_texture);
context->commandBuffer()->resourceUpdate(rub);
texture.m_mipmapCount = mipmapCount;
-
- context->registerTexture(texture.m_texture); // owned by the QSSGRhiContext from here on
return true;
}
diff --git a/src/runtimerender/resourcemanager/qssgrenderbuffermanager_p.h b/src/runtimerender/resourcemanager/qssgrenderbuffermanager_p.h
index ecf7a352..aee89b9e 100644
--- a/src/runtimerender/resourcemanager/qssgrenderbuffermanager_p.h
+++ b/src/runtimerender/resourcemanager/qssgrenderbuffermanager_p.h
@@ -187,11 +187,12 @@ private:
CubeMap = 0x02
};
Q_DECLARE_FLAGS(CreateRhiTextureFlags, CreateRhiTextureFlag)
- bool createRhiTexture(QSSGRenderImageTexture &texture,
- const QSSGLoadedTexture *inTexture,
- MipMode inMipMode,
- CreateRhiTextureFlags inFlags,
- const QString &debugObjectName);
+ bool setRhiTexture(QSSGRenderImageTexture &texture,
+ const QSSGLoadedTexture *inTexture,
+ MipMode inMipMode,
+ CreateRhiTextureFlags inFlags,
+ const QString &debugObjectName,
+ bool *wasTextureCreated = nullptr);
QSSGRenderMesh *loadRenderMesh(const QSSGRenderPath &inSourcePath, QSSGMeshProcessingOptions options);
QSSGRenderMesh *loadRenderMesh(QSSGRenderGeometry *geometry, QSSGMeshProcessingOptions options);
diff --git a/tests/manual/dynamic3DTest/CMakeLists.txt b/tests/manual/dynamic3DTest/CMakeLists.txt
index cb2f364d..b7fe289a 100644
--- a/tests/manual/dynamic3DTest/CMakeLists.txt
+++ b/tests/manual/dynamic3DTest/CMakeLists.txt
@@ -14,6 +14,7 @@ qt_internal_add_manual_test(manual_test_dynamic3DTest
set(qml_resource_files
"main.qml"
+ "RiggedFigure.qml"
"random1.mesh"
"random2.mesh"
"random3.mesh"
@@ -23,6 +24,7 @@ set(qml_resource_files
"noise3.jpg"
"noise4.jpg"
"noise5.jpg"
+ "riggedfigure.mesh"
)
qt_internal_add_resource(manual_test_dynamic3DTest "qml"
diff --git a/tests/manual/dynamic3DTest/RiggedFigure.qml b/tests/manual/dynamic3DTest/RiggedFigure.qml
new file mode 100644
index 00000000..09d966bd
--- /dev/null
+++ b/tests/manual/dynamic3DTest/RiggedFigure.qml
@@ -0,0 +1,545 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtQuick3D
+
+import QtQuick.Timeline
+
+Node {
+ id: node
+
+ // Resources
+ PrincipledMaterial {
+ id: default_effect_material
+ objectName: "Default-effect"
+ baseColor: "#ffcccccc"
+ roughness: 1
+ alphaMode: PrincipledMaterial.Opaque
+ }
+ Skin {
+ id: skin
+ joints: [
+ torso_joint_1,
+ torso_joint_2,
+ torso_joint_3,
+ neck_joint_1,
+ neck_joint_2,
+ arm_joint_L_1,
+ arm_joint_R_1,
+ arm_joint_L_2,
+ arm_joint_R_2,
+ arm_joint_L_3,
+ arm_joint_R_3,
+ leg_joint_L_1,
+ leg_joint_R_1,
+ leg_joint_L_2,
+ leg_joint_R_2,
+ leg_joint_L_3,
+ leg_joint_R_3,
+ leg_joint_L_5,
+ leg_joint_R_5
+ ]
+ inverseBindPoses: [
+ Qt.matrix4x4(0.999983, 0.000442018, 0.00581419, -0.00398856, 0, 0.997123, -0.0758045, 0.0520021, -0.005831, 0.0758032, 0.997106, -0.684015, 0, 0, 0, 1),
+ Qt.matrix4x4(1, 0, 0, 0, 0, -0.01376, 0.999905, -0.85674, 0, -0.999905, -0.0137601, 0.024791, 0, 0, 0, 1),
+ Qt.matrix4x4(1, 0, 0, 0, 0, 0.979842, 0.199774, -0.224555, 0, -0.199774, 0.979842, -1.05133, 0, 0, 0, 1),
+ Qt.matrix4x4(1, 0, 0, 0, 0, -0.00751853, 0.999972, -1.12647, 0, -0.999972, -0.00751847, 0.00796944, 0, 0, 0, 1),
+ Qt.matrix4x4(-1, -1.50995e-07, 0, 0, 0, 0.00364935, 0.999993, -1.19299, -1.51869e-07, 0.999993, -0.00364941, 0.00535393, 0, 0, 0, 1),
+ Qt.matrix4x4(-0.0623881, 0.998036, -0.00569177, 0.00162297, 0.891518, 0.0531644, -0.449853, 0.404156, -0.448667, -0.0331397, -0.893084, 0.998987, 0, 0, 0, 1),
+ Qt.matrix4x4(0.109672, 0.988876, -0.100484, 0.107683, -0.891521, 0.0531632, -0.449849, 0.404152, -0.439503, 0.13892, 0.887434, -0.993169, 0, 0, 0, 1),
+ Qt.matrix4x4(0.530194, 0.847874, 0.001751, -0.183428, 0.760039, -0.474352, -0.444218, 0.206564, -0.375811, 0.236853, -0.895917, 0.973213, 0, 0, 0, 1),
+ Qt.matrix4x4(-0.0705104, -0.619322, 0.781965, -0.761146, -0.760038, -0.474352, -0.444223, 0.206569, 0.646043, -0.625645, -0.437261, 0.633599, 0, 0, 0, 1),
+ Qt.matrix4x4(0.631434, 0.775418, -0.00419003, -0.228155, 0.649284, -0.53166, -0.543845, 0.154659, -0.423935, 0.340682, -0.839175, 0.951451, 0, 0, 0, 1),
+ Qt.matrix4x4(0.111378, -0.773831, 0.623523, -0.550204, -0.649284, -0.531661, -0.543845, 0.15466, 0.752347, -0.344271, -0.561651, 0.809067, 0, 0, 0, 1),
+ Qt.matrix4x4(-0.830471, -0.549474, 0.091635, -0.00030848, 0.0339727, -0.214148, -0.97621, 0.596867, 0.556025, -0.807601, 0.196511, -0.159297, 0, 0, 0, 1),
+ Qt.matrix4x4(-0.994689, 0.102198, 0.0121981, -0.0750653, -0.0339737, -0.214147, -0.97621, 0.596867, -0.0971548, -0.97144, 0.216482, -0.140501, 0, 0, 0, 1),
+ Qt.matrix4x4(-0.99973, 0.0232223, -7.82996e-05, 0.0784336, 0.0051282, 0.217484, -0.97605, 0.357951, -0.0226493, -0.975788, -0.217544, 0.0222206, 0, 0, 0, 1),
+ Qt.matrix4x4(-0.998171, -0.0599068, -0.00810355, -0.0775425, -0.00512856, 0.217484, -0.97605, 0.357951, 0.0602345, -0.974224, -0.217393, 0.0251548, 0, 0, 0, 1),
+ Qt.matrix4x4(-0.999327, 0.0366897, 0, 0.0783684, 0.0287104, 0.781987, 0.622632, -0.0567413, 0.0228442, 0.622213, -0.782514, 0.0634761, 0, 0, 0, 1),
+ Qt.matrix4x4(-0.999326, 0.00828946, 0.0357652, -0.0814984, 0.0287402, 0.782804, 0.621604, -0.0521458, -0.0228444, 0.622213, -0.782514, 0.0634761, 0, 0, 0, 1),
+ Qt.matrix4x4(0.994013, 0.109264, 0.000418345, -0.0755577, 0.109252, -0.993835, -0.0188101, -0.0405796, -0.00164008, 0.0187438, -0.999822, 0.0227357, 0, 0, 0, 1),
+ Qt.matrix4x4(0.994011, -0.109281, 0.000483894, 0.0755372, -0.109253, -0.993836, -0.018811, -0.0405797, 0.00253636, 0.0186453, -0.999823, 0.0228038, 0, 0, 0, 1)
+ ]
+ }
+
+ // Nodes:
+ Node {
+ id: z_UP
+ objectName: "Z_UP"
+ rotation: Qt.quaternion(0.707107, -0.707107, 0, 0)
+ Node {
+ id: armature
+ objectName: "Armature"
+ Node {
+ id: torso_joint_1
+ objectName: "torso_joint_1"
+ position: Qt.vector3d(2.79397e-09, -1.41566e-07, 0.686)
+ rotation: Qt.quaternion(0.999276, -0.0379294, -0.00291343, 0.000110585)
+ scale: Qt.vector3d(1, 1, 1)
+ Node {
+ id: torso_joint_2
+ objectName: "torso_joint_2"
+ position: Qt.vector3d(0.000999981, -4.84288e-08, 0.171491)
+ rotation: Qt.quaternion(0.674713, 0.738075, 0.00196715, -0.00215189)
+ scale: Qt.vector3d(1, 1, 1)
+ Node {
+ id: torso_joint_3
+ objectName: "torso_joint_3"
+ position: Qt.vector3d(0, 0.218018, 3.72529e-09)
+ rotation: Qt.quaternion(0.770153, -0.637859, 4.25872e-10, 3.52719e-10)
+ scale: Qt.vector3d(1, 1, 1)
+ Node {
+ id: neck_joint_1
+ objectName: "neck_joint_1"
+ position: Qt.vector3d(0, 7.45058e-08, 0.0525597)
+ rotation: Qt.quaternion(0.77214, 0.635452, 1.03679e-15, 8.51267e-16)
+ Node {
+ id: neck_joint_2
+ objectName: "neck_joint_2"
+ position: Qt.vector3d(0, 0.0665059, 0)
+ rotation: Qt.quaternion(-7.54967e-08, 4.21579e-10, 0.999984, -0.00558399)
+ scale: Qt.vector3d(1, 1, 1)
+ }
+ }
+ Node {
+ id: arm_joint_L_1
+ objectName: "arm_joint_L_1"
+ position: Qt.vector3d(0.0880006, -0.000199288, -0.000977397)
+ rotation: Qt.quaternion(-0.0885639, 0.678942, 0.687945, -0.240678)
+ scale: Qt.vector3d(1, 1, 1)
+ Node {
+ id: arm_joint_L_2
+ objectName: "arm_joint_L_2"
+ position: Qt.vector3d(1.86265e-09, 0.244526, -5.96046e-08)
+ rotation: Qt.quaternion(0.952132, -0.00240006, 0.139812, 0.271831)
+ Node {
+ id: arm_joint_L_3
+ objectName: "arm_joint_L_3"
+ position: Qt.vector3d(0, 0.185517, 0)
+ rotation: Qt.quaternion(0.996411, 0.0572906, 0.0282273, 0.0555599)
+ scale: Qt.vector3d(1, 1, 1)
+ }
+ }
+ }
+ Node {
+ id: arm_joint_R_1
+ objectName: "arm_joint_R_1"
+ position: Qt.vector3d(-0.0880006, -0.000199288, -0.000977397)
+ rotation: Qt.quaternion(0.69168, -0.276431, -0.0518638, 0.665187)
+ scale: Qt.vector3d(1, 1, 1)
+ Node {
+ id: arm_joint_R_2
+ objectName: "arm_joint_R_2"
+ position: Qt.vector3d(-7.45058e-09, 0.244526, -5.96046e-08)
+ rotation: Qt.quaternion(-0.314075, -0.228006, 0.909648, -0.148023)
+ scale: Qt.vector3d(1, 0.999999, 1)
+ Node {
+ id: arm_joint_R_3
+ objectName: "arm_joint_R_3"
+ position: Qt.vector3d(-5.96046e-08, 0.185517, 0)
+ rotation: Qt.quaternion(0.986567, 0.0785489, -0.142535, 0.0141023)
+ scale: Qt.vector3d(1, 1, 1)
+ }
+ }
+ }
+ }
+ }
+ Node {
+ id: leg_joint_L_1
+ objectName: "leg_joint_L_1"
+ position: Qt.vector3d(0.0676193, 0.00446109, -0.0722646)
+ rotation: Qt.quaternion(-0.201112, 0.210881, -0.624331, 0.724772)
+ scale: Qt.vector3d(1, 1, 1)
+ Node {
+ id: leg_joint_L_2
+ objectName: "leg_joint_L_2"
+ position: Qt.vector3d(0, 0.266112, 0)
+ rotation: Qt.quaternion(0.929599, -0.211154, 0.298432, 0.046886)
+ scale: Qt.vector3d(1, 1, 1)
+ Node {
+ id: leg_joint_L_3
+ objectName: "leg_joint_L_3"
+ position: Qt.vector3d(0, 0.275824, 0)
+ rotation: Qt.quaternion(0.530323, -0.847769, 0.00228158, 0.00633871)
+ scale: Qt.vector3d(1, 1, 1)
+ Node {
+ id: leg_joint_L_5
+ objectName: "leg_joint_L_5"
+ position: Qt.vector3d(-0.00234649, -0.0661733, 0.0278568)
+ rotation: Qt.quaternion(0.0687815, 0.0245321, -0.319997, 0.9446)
+ scale: Qt.vector3d(1, 1, 1)
+ }
+ }
+ }
+ }
+ Node {
+ id: leg_joint_R_1
+ objectName: "leg_joint_R_1"
+ position: Qt.vector3d(-0.0684572, 0.00446085, -0.0714711)
+ rotation: Qt.quaternion(0.0466302, -0.0233987, -0.654264, 0.754465)
+ scale: Qt.vector3d(1, 1, 1)
+ Node {
+ id: leg_joint_R_2
+ objectName: "leg_joint_R_2"
+ position: Qt.vector3d(0, 0.266112, 1.49012e-08)
+ rotation: Qt.quaternion(0.972955, -0.216061, -0.0810801, 0.01008)
+ Node {
+ id: leg_joint_R_3
+ objectName: "leg_joint_R_3"
+ position: Qt.vector3d(-7.45058e-09, 0.275824, -3.72529e-09)
+ rotation: Qt.quaternion(0.529777, -0.847167, 0.0320483, 0.0248404)
+ scale: Qt.vector3d(1, 1, 1)
+ Node {
+ id: leg_joint_R_5
+ objectName: "leg_joint_R_5"
+ position: Qt.vector3d(-0.00145853, -0.0661987, 0.0278568)
+ rotation: Qt.quaternion(-0.0414683, -0.0341433, -0.319178, 0.946171)
+ scale: Qt.vector3d(0.999999, 0.999999, 0.999999)
+ }
+ }
+ }
+ }
+ }
+ }
+ Model {
+ id: proxy
+ objectName: "Proxy"
+ source: "riggedfigure.mesh"
+ skin: skin
+ materials: [
+ default_effect_material
+ ]
+ }
+ }
+
+ // Animations:
+ Timeline {
+ id: timeline0
+ objectName: "timeline0"
+ property real framesPerSecond: 1000
+ startFrame: 0
+ endFrame: 1250
+ currentFrame: 0
+ enabled: true
+ animations: TimelineAnimation {
+ duration: 1250
+ from: 0
+ to: 1250
+ running: true
+ loops: Animation.Infinite
+ }
+ KeyframeGroup {
+ target: leg_joint_R_5
+ property: "position"
+ Keyframe {
+ frame: 0
+ value: Qt.vector3d(-0.00145852, -0.0661988, 0.0278567)
+ }
+ }
+ KeyframeGroup {
+ target: leg_joint_R_5
+ property: "rotation"
+ Keyframe {
+ frame: 0
+ value: Qt.quaternion(-0.0414678, -0.0341418, -0.319178, 0.946171)
+ }
+ }
+ KeyframeGroup {
+ target: leg_joint_R_3
+ property: "position"
+ Keyframe {
+ frame: 0
+ value: Qt.vector3d(7.45058e-09, 0.275824, -7.45058e-09)
+ }
+ }
+ KeyframeGroup {
+ target: leg_joint_R_3
+ property: "rotation"
+ Keyframe {
+ frame: 0
+ value: Qt.quaternion(-0.529778, 0.847166, -0.0320483, -0.0248404)
+ }
+ }
+ KeyframeGroup {
+ target: leg_joint_R_2
+ property: "position"
+ Keyframe {
+ frame: 0
+ value: Qt.vector3d(7.45058e-09, 0.266112, 0)
+ }
+ }
+ KeyframeGroup {
+ target: leg_joint_R_2
+ property: "rotation"
+ Keyframe {
+ frame: 0
+ value: Qt.quaternion(-0.972956, 0.216062, 0.0810801, -0.01008)
+ }
+ }
+ KeyframeGroup {
+ target: leg_joint_R_1
+ property: "position"
+ Keyframe {
+ frame: 0
+ value: Qt.vector3d(-0.0684572, 0.00446077, -0.0714709)
+ }
+ }
+ KeyframeGroup {
+ target: leg_joint_R_1
+ property: "rotation"
+ Keyframe {
+ frame: 0
+ value: Qt.quaternion(0.0466288, -0.0234008, -0.654263, 0.754465)
+ }
+ }
+ KeyframeGroup {
+ target: leg_joint_L_5
+ property: "position"
+ Keyframe {
+ frame: 0
+ value: Qt.vector3d(-0.00234646, -0.0661734, 0.0278567)
+ }
+ }
+ KeyframeGroup {
+ target: leg_joint_L_5
+ property: "rotation"
+ Keyframe {
+ frame: 0
+ value: Qt.quaternion(0.0687827, 0.0245355, -0.319997, 0.9446)
+ }
+ }
+ KeyframeGroup {
+ target: leg_joint_L_3
+ property: "position"
+ Keyframe {
+ frame: 0
+ value: Qt.vector3d(0, 0.275824, -1.86265e-09)
+ }
+ }
+ KeyframeGroup {
+ target: leg_joint_L_3
+ property: "rotation"
+ Keyframe {
+ frame: 0
+ value: Qt.quaternion(-0.530324, 0.847768, -0.00228158, -0.0063387)
+ }
+ }
+ KeyframeGroup {
+ target: leg_joint_L_2
+ property: "position"
+ Keyframe {
+ frame: 0
+ value: Qt.vector3d(0, 0.266112, 1.49012e-08)
+ }
+ }
+ KeyframeGroup {
+ target: leg_joint_L_2
+ property: "rotation"
+ Keyframe {
+ frame: 0
+ value: Qt.quaternion(-0.929599, 0.211155, -0.298433, -0.046886)
+ }
+ }
+ KeyframeGroup {
+ target: leg_joint_L_1
+ property: "position"
+ Keyframe {
+ frame: 0
+ value: Qt.vector3d(0.067619, 0.00446084, -0.0722642)
+ }
+ }
+ KeyframeGroup {
+ target: arm_joint_R_3
+ property: "position"
+ Keyframe {
+ frame: 0
+ value: Qt.vector3d(0, 0.185517, 0)
+ }
+ }
+ KeyframeGroup {
+ target: arm_joint_R_3
+ property: "rotation"
+ Keyframe {
+ frame: 0
+ value: Qt.quaternion(-0.986567, -0.078549, 0.142535, -0.0141023)
+ }
+ }
+ KeyframeGroup {
+ target: arm_joint_R_2
+ property: "position"
+ Keyframe {
+ frame: 0
+ value: Qt.vector3d(-7.45058e-09, 0.244526, 0)
+ }
+ }
+ KeyframeGroup {
+ target: arm_joint_L_3
+ property: "position"
+ Keyframe {
+ frame: 0
+ value: Qt.vector3d(0, 0.185517, 5.96046e-08)
+ }
+ }
+ KeyframeGroup {
+ target: arm_joint_L_3
+ property: "rotation"
+ Keyframe {
+ frame: 0
+ value: Qt.quaternion(-0.996411, -0.0572907, -0.0282272, -0.0555601)
+ }
+ }
+ KeyframeGroup {
+ target: arm_joint_L_2
+ property: "position"
+ Keyframe {
+ frame: 0
+ value: Qt.vector3d(-2.32831e-09, 0.244526, 0)
+ }
+ }
+ KeyframeGroup {
+ target: arm_joint_L_2
+ property: "rotation"
+ Keyframe {
+ frame: 0
+ value: Qt.quaternion(-0.952132, 0.00239999, -0.139812, -0.271831)
+ }
+ }
+ KeyframeGroup {
+ target: arm_joint_L_1
+ property: "position"
+ Keyframe {
+ frame: 0
+ value: Qt.vector3d(0.0880001, -0.00019978, -0.0009799)
+ }
+ Keyframe {
+ frame: 1250
+ value: Qt.vector3d(0.0879999, -0.000199795, -0.00098002)
+ }
+ }
+ KeyframeGroup {
+ target: arm_joint_L_1
+ property: "rotation"
+ Keyframe {
+ frame: 0
+ value: Qt.quaternion(-0.321235, 0.618298, 0.538041, -0.474371)
+ }
+ Keyframe {
+ frame: 1250
+ value: Qt.quaternion(-0.0885618, 0.678943, 0.687945, -0.240675)
+ }
+ }
+ KeyframeGroup {
+ target: neck_joint_2
+ property: "position"
+ Keyframe {
+ frame: 0
+ value: Qt.vector3d(-5.32907e-15, 0.0665059, 9.31323e-10)
+ }
+ }
+ KeyframeGroup {
+ target: neck_joint_2
+ property: "rotation"
+ Keyframe {
+ frame: 0
+ value: Qt.quaternion(-1.1912e-07, -5.47696e-10, 0.999487, 0.0320266)
+ }
+ Keyframe {
+ frame: 1250
+ value: Qt.quaternion(-1.19207e-07, 6.65661e-10, 0.999984, -0.00558399)
+ }
+ }
+ KeyframeGroup {
+ target: neck_joint_1
+ property: "position"
+ Keyframe {
+ frame: 0
+ value: Qt.vector3d(-8.88178e-15, -1.49012e-08, 0.0525595)
+ }
+ Keyframe {
+ frame: 1250
+ value: Qt.vector3d(-8.88178e-15, -4.47035e-08, 0.0525594)
+ }
+ }
+ KeyframeGroup {
+ target: neck_joint_1
+ property: "rotation"
+ Keyframe {
+ frame: 0
+ value: Qt.quaternion(-0.686502, -0.727128, 6.39277e-11, -1.96486e-11)
+ }
+ Keyframe {
+ frame: 1250
+ value: Qt.quaternion(-0.77214, -0.635453, 1.20456e-13, 1.01944e-13)
+ }
+ }
+ KeyframeGroup {
+ target: torso_joint_2
+ property: "position"
+ Keyframe {
+ frame: 0
+ value: Qt.vector3d(0.000999983, -1.86265e-08, 0.171491)
+ }
+ }
+ KeyframeGroup {
+ target: torso_joint_2
+ property: "rotation"
+ Keyframe {
+ frame: 0
+ value: Qt.quaternion(-0.674713, -0.738074, -0.00196715, 0.00215188)
+ }
+ }
+ KeyframeGroup {
+ target: torso_joint_3
+ property: "position"
+ Keyframe {
+ frame: 0
+ value: Qt.vector3d(-7.10543e-15, 0.218018, -1.86265e-09)
+ }
+ }
+ KeyframeGroup {
+ target: torso_joint_3
+ property: "rotation"
+ Keyframe {
+ frame: 0
+ value: Qt.quaternion(-0.770153, 0.637859, -4.26135e-10, -3.52842e-10)
+ }
+ }
+ KeyframeGroup {
+ target: arm_joint_R_1
+ property: "position"
+ Keyframe {
+ frame: 0
+ value: Qt.vector3d(-0.0880001, -0.000199795, -0.00098002)
+ }
+ }
+ KeyframeGroup {
+ target: arm_joint_R_1
+ property: "rotation"
+ Keyframe {
+ frame: 0
+ value: Qt.quaternion(-0.611424, 0.495758, 0.309245, -0.533621)
+ }
+ Keyframe {
+ frame: 1250
+ value: Qt.quaternion(-0.691681, 0.276426, 0.0518633, -0.665189)
+ }
+ }
+ KeyframeGroup {
+ target: torso_joint_1
+ property: "position"
+ Keyframe {
+ frame: 0
+ value: Qt.vector3d(4.58966e-10, -1.15066e-07, 0.686)
+ }
+ }
+ KeyframeGroup {
+ target: torso_joint_1
+ property: "rotation"
+ Keyframe {
+ frame: 0
+ value: Qt.quaternion(-0.999276, 0.0379299, 0.00291355, -0.000113405)
+ }
+ }
+ }
+}
diff --git a/tests/manual/dynamic3DTest/main.qml b/tests/manual/dynamic3DTest/main.qml
index bd16f590..71c8cd68 100644
--- a/tests/manual/dynamic3DTest/main.qml
+++ b/tests/manual/dynamic3DTest/main.qml
@@ -65,6 +65,7 @@ Window {
property var spotLights: []
property var cameras: []
property var models: []
+ property var riggedModels: []
property var dynamicModels: []
property var dynamicGeometries: []
property var textures: []
@@ -78,6 +79,7 @@ Window {
property int spotLightsCount: 0
property int camerasCount: 0
property int modelsCount: 0
+ property int riggedModelsCount: 0
property int dynamicModelsCount: 0
property int texturesCount: 0
property int dynamicTexturesCount: 0
@@ -126,6 +128,13 @@ Window {
}
Component {
+ id: riggedModel
+ RiggedFigure {
+
+ }
+ }
+
+ Component {
id: dynamicModel
Model {
property alias color: material.baseColor
@@ -253,6 +262,15 @@ Window {
return sources[index]
}
+ function getRiggedMeshSource() {
+ let sources = [
+ "riggedfigure.mesh",
+ "riggedsimple.mesh"
+ ]
+ let index = Math.floor(Math.random() * sources.length);
+ return sources[index]
+ }
+
function getImageSource() {
let sources = [
"noise1.jpg",
@@ -341,6 +359,22 @@ Window {
}
}
+ function addRiggedModel() {
+ let position = getRandomVector3d(objectSpawner.range)
+ let rotation = getRandomVector3d(360)
+ let instance = riggedModel.createObject(objectSpawner, { "position": position, "eulerRotation": rotation})
+ riggedModels.push(instance);
+ riggedModelsCount++
+ }
+
+ function removeRiggedModel() {
+ if (riggedModels.length > 0) {
+ let instance = riggedModels.pop();
+ instance.destroy();
+ riggedModelsCount--
+ }
+ }
+
function addDynamicModel() {
let position = getRandomVector3d(objectSpawner.range)
let rotation = getRandomVector3d(360)
@@ -459,6 +493,7 @@ Window {
// reset the model sources
models.forEach(model => model.source = getMeshSource())
}
+
function changeDynamicModels() {
// reset the dynamic model sources
if (dynamicModels.length == 0)
@@ -712,6 +747,30 @@ Window {
}
RowLayout {
Label {
+ text: "Rigged Model"
+ color: "white"
+ Layout.fillWidth: true
+ }
+ Label {
+ text: objectSpawner.riggedModelsCount
+ color: "white"
+ Layout.fillWidth: true
+ }
+ ToolButton {
+ text: "+"
+ onClicked: {
+ objectSpawner.addRiggedModel()
+ }
+ }
+ ToolButton {
+ text: "-"
+ onClicked: {
+ objectSpawner.removeRiggedModel()
+ }
+ }
+ }
+ RowLayout {
+ Label {
text: "Dynamic Model"
color: "white"
Layout.fillWidth: true
diff --git a/tests/manual/dynamic3DTest/qml.qrc b/tests/manual/dynamic3DTest/qml.qrc
index 8d87394b..fcd11b80 100644
--- a/tests/manual/dynamic3DTest/qml.qrc
+++ b/tests/manual/dynamic3DTest/qml.qrc
@@ -10,5 +10,7 @@
<file>noise3.jpg</file>
<file>noise4.jpg</file>
<file>noise5.jpg</file>
+ <file>RiggedFigure.qml</file>
+ <file>riggedfigure.mesh</file>
</qresource>
</RCC>
diff --git a/tests/manual/dynamic3DTest/riggedfigure.mesh b/tests/manual/dynamic3DTest/riggedfigure.mesh
new file mode 100644
index 00000000..72ddbb61
--- /dev/null
+++ b/tests/manual/dynamic3DTest/riggedfigure.mesh
Binary files differ