7#include <QtCore/qdir.h>
8#include <QtQml/qqmlfile.h>
9#include <QtQuick3D/private/qquick3dmodel_p.h>
10#include <QtQuick3DRuntimeRender/private/qssgrenderbuffermanager_p.h>
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
45QQuick3DParticleModelShape::QQuick3DParticleModelShape(QObject *parent)
46 : QQuick3DParticleAbstractShape(parent)
51QQuick3DParticleModelShape::~QQuick3DParticleModelShape()
57
58
59
60
61
62
63bool QQuick3DParticleModelShape::fill()
const
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86QQmlComponent *QQuick3DParticleModelShape::delegate()
const
91void QQuick3DParticleModelShape::setFill(
bool fill)
100QVector3D QQuick3DParticleModelShape::getPosition(
int particleIndex)
102 return randomPositionModel(particleIndex);
105QVector3D QQuick3DParticleModelShape::getSurfaceNormal(
int particleIndex)
107 if (m_cachedIndex != particleIndex)
108 getPosition(particleIndex);
109 return m_cachedNormal;
114 QString src = source;
115 if (source.startsWith(QLatin1Char(
'#'))) {
116 src = QSSGBufferManager::primitivePath(source);
117 src.prepend(QLatin1String(
":/"));
119 src = QDir::cleanPath(src);
120 if (src.startsWith(QLatin1String(
"qrc:/")))
123 QFileInfo fileInfo = QFileInfo(src);
124 if (fileInfo.exists()) {
125 QFile file(fileInfo.absoluteFilePath());
126 if (!file.open(QFile::ReadOnly))
128 mesh = QSSGMesh::Mesh::loadMesh(&file);
133void QQuick3DParticleModelShape::setDelegate(QQmlComponent *delegate)
135 if (delegate == m_delegate)
137 m_delegate = delegate;
138 clearModelVertexPositions();
140 Q_EMIT delegateChanged();
143void QQuick3DParticleModelShape::createModel()
149 auto *obj = m_delegate->create(m_delegate->creationContext());
150 m_model = qobject_cast<QQuick3DModel *>(obj);
155QVector3D QQuick3DParticleModelShape::randomPositionModel(
int particleIndex)
158 calculateModelVertexPositions();
160 const QVector<QVector3D> &positions = m_vertexPositions;
161 if (positions.size() > 0) {
162 auto rand = m_system->rand();
166 if (m_modelTriangleAreas.size() == 0) {
167 m_modelTriangleAreas.reserve(positions.size() / 3);
168 for (
int i = 0; i + 2 < positions.size(); i += 3) {
169 const QVector3D &v1 = positions[i];
170 const QVector3D &v2 = positions[i + 1];
171 const QVector3D &v3 = positions[i + 2];
172 const float area = QVector3D::crossProduct(v1 - v2, v1 - v3).length() * 0.5f;
173 m_modelTriangleAreasSum += area;
174 m_modelTriangleAreas.append(m_modelTriangleAreasSum);
175 m_modelTriangleCenter += v1 + v2 + v3;
177 m_modelTriangleCenter /= positions.size();
180 const float rndWeight = rand->get(particleIndex, QPRand::Shape1) * m_modelTriangleAreasSum;
183 int index = std::lower_bound(m_modelTriangleAreas.begin(), m_modelTriangleAreas.end(), rndWeight) - m_modelTriangleAreas.begin();
185 const QVector3D &v1 = positions[index * 3];
186 const QVector3D &v2 = positions[index * 3 + 1];
187 const QVector3D &v3 = positions[index * 3 + 2];
188 const float a = rand->get(particleIndex, QPRand::Shape2);
189 const float b = rand->get(particleIndex, QPRand::Shape3);
190 const float aSqrt = qSqrt(a);
193 QVector3D pos = (1.0 - aSqrt) * v1 + (aSqrt * (1.0 - b)) * v2 + (b * aSqrt) * v3;
199 const float uniform = rand->get(particleIndex, QPRand::Shape4);
200 const float lambda = 5.0f;
201 const float alpha = -qLn(1 - (1 - qExp(-lambda)) * uniform) / lambda;
202 pos += (m_modelTriangleCenter - pos) * alpha;
204 m_cachedIndex = particleIndex;
205 m_cachedNormal = QVector3D::crossProduct(v2 - v1, v3 - v2).normalized();
208 auto *parent = parentNode();
211 mat.rotate(parent->rotation() * m_model->rotation());
213 m_cachedNormal = mat.mapVector(m_cachedNormal);
214 return mat.mapVector(pos * parent->sceneScale() * m_model->scale());
218 return QVector3D(0, 0, 0);
221void QQuick3DParticleModelShape::clearModelVertexPositions()
223 m_vertexPositions.clear();
224 m_modelTriangleAreas.clear();
225 m_modelTriangleAreasSum = 0;
228void QQuick3DParticleModelShape::calculateModelVertexPositions()
230 if (m_vertexPositions.empty()) {
231 QVector<QVector3D> indicedPositions;
232 QVector<QVector3D> positions;
234 if (m_model->geometry()) {
235 QQuick3DGeometry *geometry = m_model->geometry();
236 bool hasIndexBuffer =
false;
237 QQuick3DGeometry::Attribute::ComponentType indexBufferFormat;
239 QQuick3DGeometry::Attribute::ComponentType posType = QQuick3DGeometry::Attribute::U16Type;
240 for (
int i = 0; i < geometry->attributeCount(); ++i) {
241 auto attribute = geometry->attribute(i);
242 if (attribute.semantic == QQuick3DGeometry::Attribute::PositionSemantic) {
243 posOffset = attribute.offset;
244 posType = attribute.componentType;
245 }
else if (attribute.semantic == QQuick3DGeometry::Attribute::IndexSemantic) {
246 hasIndexBuffer =
true;
247 indexBufferFormat = attribute.componentType;
250 if (posType == QQuick3DGeometry::Attribute::F32Type) {
251 const auto &data = geometry->vertexData();
252 int stride = geometry->stride();
253 for (
int i = 0; i < data.size(); i += stride) {
255 memcpy(v, data + posOffset + i,
sizeof(v));
256 positions.append(QVector3D(v[0], v[1], v[2]));
258 if (hasIndexBuffer) {
259 const auto &data = geometry->vertexData();
261 if (indexBufferFormat == QQuick3DGeometry::Attribute::U16Type)
263 for (
int i = 0; i < data.size(); i += indexSize) {
265 memcpy(&index, data + i, indexSize);
266 if (positions.size() > index)
267 indicedPositions.append(positions[index]);
272 const QQmlContext *context = qmlContext(
this);
273 QString src = m_model->source().toString();
274 if (context && !src.startsWith(QLatin1Char(
'#')))
275 src = QQmlFile::urlToLocalFileOrQrc(context->resolvedUrl(m_model->source()));
276 QSSGMesh::Mesh mesh = loadModelShapeMesh(src);
279 if (mesh.drawMode() != QSSGMesh::Mesh::DrawMode::Triangles)
282 auto entries = mesh.vertexBuffer().entries;
286 QSSGMesh::Mesh::ComponentType posType = QSSGMesh::Mesh::ComponentType::UnsignedInt8;
287 for (
int i = 0; i < entries.size(); ++i) {
288 const char *nameStr = entries[i].name.constData();
289 if (!strcmp(nameStr, QSSGMesh::MeshInternal::getPositionAttrName())) {
290 posOffset = entries[i].offset;
291 posCount = entries[i].componentCount;
292 posType = entries[i].componentType;
296 if (posCount == 3 && posType == QSSGMesh::Mesh::ComponentType::Float32) {
297 const auto &data = mesh.vertexBuffer().data;
298 int stride = mesh.vertexBuffer().stride;
299 for (
int i = 0; i < data.size(); i += stride) {
301 memcpy(v, data + posOffset + i,
sizeof(v));
302 positions.append(QVector3D(v[0], v[1], v[2]));
304 const auto &indexData = mesh.indexBuffer().data;
305 int indexSize = QSSGMesh::MeshInternal::byteSizeForComponentType(mesh.indexBuffer().componentType);
306 for (
int i = 0; i < indexData.size(); i += indexSize) {
308 memcpy(&index, indexData + i, indexSize);
309 if (positions.size() > index)
310 indicedPositions.append(positions[index]);
314 if (!indicedPositions.empty())
315 m_vertexPositions = indicedPositions;
317 m_vertexPositions = positions;
static QSSGMesh::Mesh loadModelShapeMesh(const QString &source)