10#include <QtCore/qdir.h>
11#include <QtQml/qqmlfile.h>
13#include <QtQuick3D/private/qquick3dobject_p.h>
14#include <QtQuick3D/private/qquick3dgeometry_p.h>
16#include <QtQuick3DUtils/private/qssgutils_p.h>
17#include <QtQuick3DRuntimeRender/private/qssgrenderparticles_p.h>
18#include <QtQuick3DRuntimeRender/private/qssgrendergeometry_p.h>
19#include <QtQuick3DRuntimeRender/private/qssgrendermodel_p.h>
20#include <QtQuick3DUtils/private/qssgmesh_p.h>
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
59QQuick3DParticleModelBlendParticle::QQuick3DParticleModelBlendParticle(QQuick3DNode *parent)
60 : QQuick3DParticle(*
new QQuick3DObjectPrivate(QQuick3DObjectPrivate::Type::ModelBlendParticle), parent)
62 setFadeInEffect(QQuick3DParticle::FadeNone);
63 setFadeOutEffect(QQuick3DParticle::FadeNone);
64 QQuick3DParticle::doSetMaxAmount(0);
67QQuick3DParticleModelBlendParticle::~QQuick3DParticleModelBlendParticle()
70 delete m_modelGeometry;
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101QQmlComponent *QQuick3DParticleModelBlendParticle::delegate()
const
106void QQuick3DParticleModelBlendParticle::setDelegate(QQmlComponent *delegate)
108 if (delegate == m_delegate)
110 m_delegate = delegate;
114 Q_EMIT delegateChanged();
118
119
120
121
122
123
124QQuick3DNode *QQuick3DParticleModelBlendParticle::endNode()
const
130
131
132
133
134
135
136
137
138
139
140
142
143
144
145
146QQuick3DParticleModelBlendParticle::ModelBlendMode QQuick3DParticleModelBlendParticle::modelBlendMode()
const
148 return m_modelBlendMode;
152
153
154
155
156
157
158
159
160int QQuick3DParticleModelBlendParticle::endTime()
const
166
167
168
169
170
171
172
173
174
175QQuick3DNode *QQuick3DParticleModelBlendParticle::activationNode()
const
177 return m_activationNode;
181
182
183
184
185
186
187
188
189
190
191
193
194
195
196
197QQuick3DParticleModelBlendParticle::ModelBlendEmitMode QQuick3DParticleModelBlendParticle::emitMode()
const
202void QQuick3DParticleModelBlendParticle::setEndNode(QQuick3DNode *node)
204 if (m_endNode == node)
207 QObject::disconnect(
this);
212 QObject::connect(m_endNode, &QQuick3DNode::positionChanged,
this, &QQuick3DParticleModelBlendParticle::handleEndNodeChanged);
213 QObject::connect(m_endNode, &QQuick3DNode::rotationChanged,
this, &QQuick3DParticleModelBlendParticle::handleEndNodeChanged);
214 QObject::connect(m_endNode, &QQuick3DNode::scaleChanged,
this, &QQuick3DParticleModelBlendParticle::handleEndNodeChanged);
216 handleEndNodeChanged();
217 Q_EMIT endNodeChanged();
220void QQuick3DParticleModelBlendParticle::setModelBlendMode(ModelBlendMode mode)
222 if (m_modelBlendMode == mode)
224 m_modelBlendMode = mode;
226 Q_EMIT modelBlendModeChanged();
229void QQuick3DParticleModelBlendParticle::setEndTime(
int endTime)
231 if (endTime == m_endTime)
234 Q_EMIT endTimeChanged();
237void QQuick3DParticleModelBlendParticle::setActivationNode(QQuick3DNode *activationNode)
239 if (m_activationNode == activationNode)
242 m_activationNode = activationNode;
243 Q_EMIT activationNodeChanged();
246void QQuick3DParticleModelBlendParticle::setEmitMode(ModelBlendEmitMode emitMode)
248 if (m_emitMode == emitMode)
251 m_emitMode = emitMode;
252 Q_EMIT emitModeChanged();
255void QQuick3DParticleModelBlendParticle::regenerate()
260 if (!isComponentComplete())
266 if (QQuick3DParticleSystem::isGloballyDisabled())
269 auto *obj = m_delegate->create(m_delegate->creationContext());
271 m_model = qobject_cast<QQuick3DModel *>(obj);
274 auto *psystem = QQuick3DParticle::system();
275 m_model->setParent(psystem);
276 m_model->setParentItem(psystem);
280 handleEndNodeChanged();
285 QString src = source;
286 if (source.startsWith(QLatin1Char(
'#'))) {
287 src = QSSGBufferManager::primitivePath(source);
288 src.prepend(QLatin1String(
":/"));
290 src = QDir::cleanPath(src);
291 if (src.startsWith(QLatin1String(
"qrc:/")))
295 if (!file.open(QFile::ReadOnly))
297 return QSSGMesh::Mesh::loadMesh(&file);
302 const quint8 *vertex = srcVertices + idx * vertexStride;
303 return *
reinterpret_cast<
const QVector3D *>(vertex + posOffset);
306static float calcTriangleRadius(
const QVector3D ¢er,
const QVector3D &p0,
const QVector3D &p1,
const QVector3D &p2)
308 return qMax(center.distanceToPoint(p1), qMax(center.distanceToPoint(p2), center.distanceToPoint(p0)));
312 QVector<QVector3D> ¢erData,
313 float &maxTriangleRadius,
314 const QByteArray &vertexBufferData,
315 quint32 vertexStride,
317 const QByteArray &indexBufferData,
319 quint32 primitiveCount)
321 const quint8 *srcVertices =
reinterpret_cast<
const quint8 *>(vertexBufferData.data());
322 quint8 *dst =
reinterpret_cast<quint8 *>(unindexedVertexData.data());
323 const quint16 *indexData16 =
reinterpret_cast<
const quint16 *>(indexBufferData.begin());
324 const quint32 *indexData32 =
reinterpret_cast<
const quint32 *>(indexBufferData.begin());
325 const float c_div3 = 1.0f / 3.0f;
326 for (quint32 i = 0; i < primitiveCount; i++) {
329 i0 = indexData16[3 * i];
330 i1 = indexData16[3 * i + 1];
331 i2 = indexData16[3 * i + 2];
333 i0 = indexData32[3 * i];
334 i1 = indexData32[3 * i + 1];
335 i2 = indexData32[3 * i + 2];
337 QVector3D p0 = getPosition(srcVertices, i0, vertexStride, posOffset);
338 QVector3D p1 = getPosition(srcVertices, i1, vertexStride, posOffset);
339 QVector3D p2 = getPosition(srcVertices, i2, vertexStride, posOffset);
340 QVector3D center = (p0 + p1 + p2) * c_div3;
341 centerData[i] = center;
342 maxTriangleRadius = qMax(maxTriangleRadius, calcTriangleRadius(center, p0, p1, p2));
343 memcpy(dst, srcVertices + i0 * vertexStride, vertexStride);
345 memcpy(dst, srcVertices + i1 * vertexStride, vertexStride);
347 memcpy(dst, srcVertices + i2 * vertexStride, vertexStride);
353 float &maxTriangleRadius,
354 const QByteArray &vertexBufferData,
355 quint32 vertexStride,
357 quint32 primitiveCount)
359 const quint8 *srcVertices =
reinterpret_cast<
const quint8 *>(vertexBufferData.data());
360 const float c_div3 = 1.0f / 3.0f;
361 for (quint32 i = 0; i < primitiveCount; i++) {
362 QVector3D p0 = getPosition(srcVertices, 3 * i, vertexStride, posOffset);
363 QVector3D p1 = getPosition(srcVertices, 3 * i + 1, vertexStride, posOffset);
364 QVector3D p2 = getPosition(srcVertices, 3 * i + 2, vertexStride, posOffset);
365 QVector3D center = (p0 + p1 + p2) * c_div3;
366 centerData[i] = center;
367 maxTriangleRadius = qMax(maxTriangleRadius, calcTriangleRadius(center, p0, p1, p2));
371void QQuick3DParticleModelBlendParticle::updateParticles()
373 m_maxTriangleRadius = 0.f;
378 if (m_model->geometry()) {
379 QQuick3DGeometry *geometry = m_model->geometry();
380 if (geometry->primitiveType() != QQuick3DGeometry::PrimitiveType::Triangles) {
381 qWarning () <<
"ModelBlendParticle3D: Invalid geometry primitive type, must be Triangles. ";
384 auto vertexBuffer = geometry->vertexData();
385 auto indexBuffer = geometry->indexData();
387 if (!vertexBuffer.size()) {
388 qWarning () <<
"ModelBlendParticle3D: Invalid geometry, vertexData is empty. ";
392 const auto attributeBySemantic = [&](
const QQuick3DGeometry *geometry, QQuick3DGeometry::Attribute::Semantic semantic) {
393 for (
int i = 0; i < geometry->attributeCount(); i++) {
394 const auto attr = geometry->attribute(i);
395 if (attr.semantic == semantic)
399 return QQuick3DGeometry::Attribute();
402 if (indexBuffer.size()) {
403 m_modelGeometry =
new QQuick3DGeometry;
405 m_modelGeometry->setBounds(geometry->boundsMin(), geometry->boundsMax());
406 m_modelGeometry->setPrimitiveType(QQuick3DGeometry::PrimitiveType::Triangles);
407 m_modelGeometry->setStride(geometry->stride());
409 for (
int i = 0; i < geometry->attributeCount(); i++) {
410 auto attr = geometry->attribute(i);
411 if (attr.semantic != QQuick3DGeometry::Attribute::IndexSemantic)
412 m_modelGeometry->addAttribute(attr);
416 QByteArray unindexedVertexData;
417 quint32 primitiveCount = indexBuffer.size();
418 auto indexAttribute = attributeBySemantic(geometry, QQuick3DGeometry::Attribute::IndexSemantic);
419 bool u16IndexType = indexAttribute.componentType == QQuick3DGeometry::Attribute::U16Type;
423 primitiveCount /= 12;
425 unindexedVertexData.resize(geometry->stride() * primitiveCount * 3);
426 m_centerData.resize(primitiveCount);
427 m_particleCount = primitiveCount;
428 copyToUnindexedVertices(unindexedVertexData,
433 attributeBySemantic(geometry, QQuick3DGeometry::Attribute::PositionSemantic).offset,
438 m_modelGeometry->setVertexData(unindexedVertexData);
439 m_model->setGeometry(m_modelGeometry);
442 quint32 primitiveCount = vertexBuffer.size() / geometry->stride() / 3;
443 m_centerData.resize(primitiveCount);
444 m_particleCount = primitiveCount;
445 getVertexCenterData(m_centerData,
449 attributeBySemantic(geometry, QQuick3DGeometry::Attribute::PositionSemantic).offset,
453 const QQmlContext *context = qmlContext(
this);
454 QString src = m_model->source().toString();
455 if (context && !src.startsWith(QLatin1Char(
'#')))
456 src = QQmlFile::urlToLocalFileOrQrc(context->resolvedUrl(m_model->source()));
457 QSSGMesh::Mesh mesh = loadModelBlendParticleMesh(src);
458 if (!mesh.isValid()) {
459 qWarning () <<
"ModelBlendParticle3D: Unable to load mesh: " << src;
462 if (mesh.drawMode() != QSSGMesh::Mesh::DrawMode::Triangles) {
463 qWarning () <<
"ModelBlendParticle3D: Invalid mesh primitive type, must be Triangles. ";
467 m_modelGeometry =
new QQuick3DGeometry;
469 const auto vertexBuffer = mesh.vertexBuffer();
470 const auto indexBuffer = mesh.indexBuffer();
472 const auto entryOffset = [&](
const QSSGMesh::Mesh::VertexBuffer &vb,
const QByteArray &name) ->
int {
473 for (
const auto &e : vb.entries) {
474 if (e.name == name) {
475 Q_ASSERT(e.componentType == QSSGMesh::Mesh::ComponentType::Float32);
482 const auto toAttribute = [&](
const QSSGMesh::Mesh::VertexBufferEntry &e) -> QQuick3DGeometry::Attribute {
483 QQuick3DGeometry::Attribute a;
484 a.componentType = QQuick3DGeometryPrivate::toComponentType(e.componentType);
486 a.semantic = QQuick3DGeometryPrivate::semanticFromName(e.name);
490 const auto indexedPrimitiveCount = [&](
const QSSGMesh::Mesh::IndexBuffer &indexBuffer) -> quint32 {
491 if (indexBuffer.componentType == QSSGMesh::Mesh::ComponentType::UnsignedInt16)
492 return quint32(indexBuffer.data.size() /
sizeof(quint16) / 3);
493 return quint32(indexBuffer.data.size() /
sizeof(quint32) / 3);
496 if (indexBuffer.data.size()) {
498 QByteArray unindexedVertexData;
499 quint32 primitiveCount = indexedPrimitiveCount(indexBuffer);
500 bool u16IndexType = indexBuffer.componentType == QSSGMesh::Mesh::ComponentType::UnsignedInt16;
501 unindexedVertexData.resize(vertexBuffer.stride * primitiveCount * 3);
502 m_centerData.resize(primitiveCount);
503 m_particleCount = primitiveCount;
505 copyToUnindexedVertices(unindexedVertexData,
510 entryOffset(vertexBuffer, QByteArray(QSSGMesh::MeshInternal::getPositionAttrName())),
514 const auto meshSubsets = mesh.subsets();
515 m_modelGeometry->setBounds(meshSubsets.constFirst().bounds.min, meshSubsets.constFirst().bounds.max);
516 m_modelGeometry->setStride(vertexBuffer.stride);
517 m_modelGeometry->setVertexData(unindexedVertexData);
518 m_modelGeometry->setPrimitiveType(QQuick3DGeometry::PrimitiveType::Triangles);
521 quint32 primitiveCount = vertexBuffer.data.size() / vertexBuffer.stride / 3;
522 m_centerData.resize(primitiveCount);
523 m_particleCount = primitiveCount;
524 getVertexCenterData(m_centerData,
528 entryOffset(vertexBuffer, QByteArray(QSSGMesh::MeshInternal::getPositionAttrName())),
530 const auto meshSubsets = mesh.subsets();
531 m_modelGeometry->setBounds(meshSubsets.constFirst().bounds.min, meshSubsets.constFirst().bounds.max);
532 m_modelGeometry->setStride(vertexBuffer.stride);
533 m_modelGeometry->setVertexData(vertexBuffer.data);
534 m_modelGeometry->setPrimitiveType(QQuick3DGeometry::PrimitiveType::Triangles);
536 for (
auto &e : vertexBuffer.entries)
537 m_modelGeometry->addAttribute(toAttribute(e));
538 for (
auto &s : mesh.subsets())
539 m_modelGeometry->addSubset(s.offset, s.count, s.bounds.min, s.bounds.max, s.name);
541 m_model->setSource({});
542 m_model->setGeometry(m_modelGeometry);
545 QMatrix4x4 transform = m_model->sceneTransform();
546 if (m_model->parentNode())
547 transform = m_model->parentNode()->sceneTransform().inverted() * transform;
548 const QVector3D scale = QSSGUtils::mat44::getScale(transform);
550 const float scaleMax = qMax(scale.x(), qMax(scale.y(), scale.z()));
551 m_maxTriangleRadius *= scaleMax;
553 m_triangleParticleData.resize(m_particleCount);
554 m_particleData.resize(m_particleCount);
555 m_particleData.fill({});
556 for (
int i = 0; i < m_particleCount; i++) {
557 m_triangleParticleData[i].center = m_centerData[i];
558 m_centerData[i] = transform.map(m_centerData[i]);
559 if (m_modelBlendMode == Construct) {
560 m_triangleParticleData[i].size = 0.0f;
562 m_triangleParticleData[i].size = 1.0f;
563 m_triangleParticleData[i].position = m_centerData[i];
566 QQuick3DParticle::doSetMaxAmount(m_particleCount);
569QSSGRenderGraphObject *QQuick3DParticleModelBlendParticle::updateSpatialNode(QSSGRenderGraphObject *node)
573 auto *spatialNode = QQuick3DObjectPrivate::get(m_model)->spatialNode;
575 spatialNode = QQuick3DObjectPrivate::updateSpatialNode(m_model,
nullptr);
576 QQuick3DObjectPrivate::get(m_model)->spatialNode = spatialNode;
577 Q_QUICK3D_PROFILE_ASSIGN_ID_SG(
this, spatialNode);
579#if QT_CONFIG(qml_debug)
580 if (m_modelGeometry) {
581 auto *geometrySpatialNode = QQuick3DObjectPrivate::get(m_modelGeometry)->spatialNode;
582 if (geometrySpatialNode)
583 Q_QUICK3D_PROFILE_ASSIGN_ID_SG(
this, geometrySpatialNode);
587 QSSGRenderModel *model =
static_cast<QSSGRenderModel *>(spatialNode);
589 if (!model->particleBuffer) {
590 QSSGParticleBuffer *buffer = model->particleBuffer =
new QSSGParticleBuffer;
591 buffer->resize(m_particleCount,
sizeof(QSSGTriangleParticle));
593 QQuick3DParticleSystem *psystem = QQuick3DParticle::system();
594 QMatrix4x4 particleMatrix = psystem->sceneTransform().inverted() * m_model->sceneTransform();
595 model->particleMatrix = particleMatrix.inverted();
596 model->hasTransparency = fadeInEffect() == QQuick3DParticle::FadeOpacity || fadeOutEffect() == QQuick3DParticle::FadeOpacity;
597 updateParticleBuffer(model->particleBuffer, psystem->sceneTransform());
602void QQuick3DParticleModelBlendParticle::componentComplete()
604 if (!system() && qobject_cast<QQuick3DParticleSystem *>(parentItem()))
605 setSystem(qobject_cast<QQuick3DParticleSystem *>(parentItem()));
608 QQuick3DObject::componentComplete();
612void QQuick3DParticleModelBlendParticle::doSetMaxAmount(
int)
614 qWarning() <<
"ModelBlendParticle3D.maxAmount: Unable to set maximum amount, because it is set from the model.";
618int QQuick3DParticleModelBlendParticle::nextCurrentIndex(
const QQuick3DParticleEmitter *emitter)
620 if (!m_perEmitterData.contains(emitter)) {
621 m_perEmitterData.insert(emitter, PerEmitterData());
622 auto &perEmitter = m_perEmitterData[emitter];
623 perEmitter.emitter = emitter;
624 perEmitter.emitterIndex = m_nextEmitterIndex++;
626 auto &perEmitter = m_perEmitterData[emitter];
627 int index = QQuick3DParticle::nextCurrentIndex(emitter);
628 if (m_triangleParticleData[index].emitterIndex != perEmitter.emitterIndex) {
629 if (m_triangleParticleData[index].emitterIndex >= 0)
630 perEmitterData(m_triangleParticleData[index].emitterIndex).particleCount--;
631 perEmitter.particleCount++;
633 m_triangleParticleData[index].emitterIndex = perEmitter.emitterIndex;
638void QQuick3DParticleModelBlendParticle::setParticleData(
int particleIndex,
639 const QVector3D &position,
640 const QVector3D &rotation,
641 const QVector4D &color,
642 float size,
float age)
644 auto &dst = m_triangleParticleData[particleIndex];
645 dst = {position, rotation, dst.center, color, age, size, dst.emitterIndex};
646 m_dataChanged =
true;
649QQuick3DParticleModelBlendParticle::PerEmitterData &QQuick3DParticleModelBlendParticle::perEmitterData(
int emitterIndex)
651 for (
auto &perEmitter : m_perEmitterData) {
652 if (perEmitter.emitterIndex == emitterIndex)
655 return n_noPerEmitterData;
658void QQuick3DParticleModelBlendParticle::updateParticleBuffer(QSSGParticleBuffer *buffer,
const QMatrix4x4 &sceneTransform)
660 const auto &particles = m_triangleParticleData;
662 if (!buffer || !m_dataChanged)
665 const int particleCount = m_particleCount;
667 char *dest = buffer->pointer();
668 const TriangleParticleData *src = particles.data();
669 const int pps = buffer->particlesPerSlice();
670 const int ss = buffer->sliceStride();
671 const int slices = buffer->sliceCount();
672 const float c_degToRad =
float(M_PI / 180.0f);
675 for (
int s = 0; s < slices; s++) {
676 QSSGTriangleParticle *dp =
reinterpret_cast<QSSGTriangleParticle *>(dest);
677 for (
int p = 0; p < pps && i < particleCount; ) {
678 if (src->size > 0.0f)
679 bounds.include(src->position);
680 dp->position = src->position;
681 dp->rotation = src->rotation * c_degToRad;
682 dp->color = src->color;
684 dp->center = src->center;
685 dp->size = src->size;
694 bounds.fatten(m_maxTriangleRadius);
695 bounds.transform(sceneTransform);
696 buffer->setBounds(bounds);
697 m_dataChanged =
false;
700void QQuick3DParticleModelBlendParticle::itemChange(QQuick3DObject::ItemChange change,
701 const QQuick3DObject::ItemChangeData &value)
703 QQuick3DObject::itemChange(change, value);
704 if (change == ItemParentHasChanged && value.sceneManager)
708void QQuick3DParticleModelBlendParticle::reset()
710 QQuick3DParticle::reset();
711 if (m_particleCount) {
712 for (
int i = 0; i < m_particleCount; i++) {
713 if (m_modelBlendMode == Construct) {
714 m_triangleParticleData[i].size = 0.0f;
716 m_triangleParticleData[i].size = 1.0f;
717 m_triangleParticleData[i].position = m_triangleParticleData[i].center;
723QVector3D QQuick3DParticleModelBlendParticle::particleCenter(
int particleIndex)
const
725 return m_centerData[particleIndex];
728bool QQuick3DParticleModelBlendParticle::lastParticle()
const
730 return m_currentIndex >= m_maxAmount - 1;
735 float x = qDegreesToRadians(eulerRotation.x());
736 float y = qDegreesToRadians(eulerRotation.y());
737 float z = qDegreesToRadians(eulerRotation.z());
750 ret(1,0) = bd * e + a * f;
751 ret(1,1) = a * e - bd * f;
753 ret(2,0) = b * f - ad * e;
754 ret(2,1) = ad * f + b * e;
759void QQuick3DParticleModelBlendParticle::handleEndNodeChanged()
761 if (m_endNode && m_model) {
762 if (!m_model->rotation().isIdentity()) {
764 QMatrix3x3 r1 = qt_fromEulerRotation(m_endNode->eulerRotation());
765 QMatrix3x3 r2 = m_model->rotation().toRotationMatrix();
766 QMatrix3x3 r = r2 * r1.transposed() * r2.transposed();
767 m_endNodeRotation = m_endNode->eulerRotation();
768 m_endRotationMatrix = QMatrix4x4(r);
770 m_endNodeRotation = m_endNode->eulerRotation();
771 m_endRotationMatrix = QMatrix4x4(m_endNode->rotation().toRotationMatrix().transposed());
773 m_endNodePosition = m_endNode->position();
774 m_endNodeScale = m_endNode->scale();
776 m_endNodePosition = QVector3D();
777 m_endNodeRotation = QVector3D();
778 m_endNodeScale = QVector3D(1.0f, 1.0f, 1.0f);
779 m_endRotationMatrix.setToIdentity();
783QVector3D QQuick3DParticleModelBlendParticle::particleEndPosition(
int idx)
const
785 return m_endRotationMatrix.map(QVector3D(m_endNodeScale * m_centerData[idx])) + m_endNodePosition;
788QVector3D QQuick3DParticleModelBlendParticle::particleEndRotation(
int)
const
790 return m_endNodeRotation;
793int QQuick3DParticleModelBlendParticle::randomIndex(
int particleIndex)
795 if (m_randomParticles.isEmpty()) {
796 m_randomParticles.resize(m_maxAmount);
797 for (
int i = 0; i < m_maxAmount; i++)
798 m_randomParticles[i] = i;
801 QRandomGenerator rand(system()->rand()->generator());
802 for (
int i = 0; i < m_maxAmount; i++) {
803 int ridx = rand.generate() % m_maxAmount;
805 qSwap(m_randomParticles[i], m_randomParticles[ridx]);
808 return m_randomParticles[particleIndex];
Combined button and popup list for selecting options.
static float calcTriangleRadius(const QVector3D ¢er, const QVector3D &p0, const QVector3D &p1, const QVector3D &p2)
static QVector3D getPosition(const quint8 *srcVertices, quint32 idx, quint32 vertexStride, quint32 posOffset)
static void getVertexCenterData(QVector< QVector3D > ¢erData, float &maxTriangleRadius, const QByteArray &vertexBufferData, quint32 vertexStride, quint32 posOffset, quint32 primitiveCount)
static void copyToUnindexedVertices(QByteArray &unindexedVertexData, QVector< QVector3D > ¢erData, float &maxTriangleRadius, const QByteArray &vertexBufferData, quint32 vertexStride, quint32 posOffset, const QByteArray &indexBufferData, bool u16Indices, quint32 primitiveCount)
static QMatrix3x3 qt_fromEulerRotation(const QVector3D &eulerRotation)
static QSSGMesh::Mesh loadModelBlendParticleMesh(const QString &source)