Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquick3dparticleshape.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
8#include <QtCore/qdir.h>
9#include <QtQml/qqmlfile.h>
10#include <QtQuick3D/private/qquick3dobject_p.h>
11#include <QtQuick3D/private/qquick3dmodel_p.h>
12#include <QtQuick3DRuntimeRender/private/qssgrenderbuffermanager_p.h>
13#include <algorithm>
14
15QT_BEGIN_NAMESPACE
16
17/*!
18 \qmltype ParticleShape3D
19 \inherits ParticleAbstractShape3D
20 \inqmlmodule QtQuick3D.Particles3D
21 \brief Offers 3D shapes for emitters and affectors.
22 \since 6.2
23
24 The ParticleShape3D element supports shapes like \c Cube, \c Sphere and \c Cylinder for particles needs.
25 For example, emitter can use \l {ParticleEmitter3D::shape}{shape} property to emit particles from the
26 shape area.
27
28 Shapes don't have position, scale or rotation. Instead, they use parent node for these properties.
29*/
30
31QQuick3DParticleShape::QQuick3DParticleShape(QObject *parent)
32 : QQuick3DParticleAbstractShape(parent)
33{
34}
35
36/*!
37 \qmlproperty bool ParticleShape3D::fill
38
39 This property defines if the shape should be filled or just use the shape outlines.
40
41 The default value is \c true.
42*/
43bool QQuick3DParticleShape::fill() const
44{
45 return m_fill;
46}
47
48void QQuick3DParticleShape::setFill(bool fill)
49{
50 if (m_fill == fill)
51 return;
52
53 m_fill = fill;
54 Q_EMIT fillChanged();
55}
56
57/*!
58 \qmlproperty ShapeType ParticleShape3D::type
59
60 This property defines the type of the shape.
61
62 The default value is \c ParticleShape3D.Cube.
63*/
64
65/*!
66 \qmlproperty enumeration ParticleShape3D::ShapeType
67
68 Defines the type of the shape.
69
70 \value ParticleShape3D.Cube
71 Cube shape.
72 \value ParticleShape3D.Sphere
73 Sphere shape.
74 \value ParticleShape3D.Cylinder
75 Cylinder shape.
76*/
77
78QQuick3DParticleShape::ShapeType QQuick3DParticleShape::type() const
79{
80 return m_type;
81}
82
83/*!
84 \qmlproperty vector3d ParticleShape3D::extents
85
86 This property defines the extents of the shape.
87
88 The default value for each axis is \c 50.
89*/
90QVector3D QQuick3DParticleShape::extents() const
91{
92 return m_extents;
93}
94
95void QQuick3DParticleShape::setType(QQuick3DParticleShape::ShapeType type)
96{
97 if (m_type == type)
98 return;
99
100 m_type = type;
101 Q_EMIT typeChanged();
102}
103
104void QQuick3DParticleShape::setExtents(QVector3D extents)
105{
106 if (m_extents == extents)
107 return;
108
109 m_extents = extents;
110 Q_EMIT extentsChanged();
111}
112
113QVector3D QQuick3DParticleShape::getPosition(int particleIndex)
114{
115 if (!parentNode() || !m_system)
116 return QVector3D();
117 if (m_cachedIndex == particleIndex)
118 return m_cachedPosition;
119
120 switch (m_type) {
121 case QQuick3DParticleShape::ShapeType::Cube:
122 m_cachedPosition = randomPositionCube(particleIndex);
123 break;
124 case QQuick3DParticleShape::ShapeType::Sphere:
125 m_cachedPosition = randomPositionSphere(particleIndex);
126 break;
127 case QQuick3DParticleShape::ShapeType::Cylinder:
128 m_cachedPosition = randomPositionCylinder(particleIndex);
129 break;
130 }
131 m_cachedIndex = particleIndex;
132 return m_cachedPosition;
133}
134
135QVector3D QQuick3DParticleShape::getSurfaceNormal(int particleIndex)
136{
137 if (m_fill)
138 return QVector3D();
139
140 auto rand = m_system->rand();
141 QVector3D n;
142 switch (m_type) {
143 case QQuick3DParticleShape::ShapeType::Cube: {
144 int side = int(rand->get(particleIndex, QPRand::Shape4) * 6);
145 if (side == 0)
146 n.setX(-1.0f);
147 else if (side == 1)
148 n.setX(1.0f);
149 else if (side == 2)
150 n.setY(-1.0f);
151 else if (side == 3)
152 n.setY(1.0f);
153 else if (side == 4)
154 n.setZ(-1.0f);
155 else
156 n.setZ(1.0f);
157 QMatrix4x4 mat;
158 mat.rotate(m_parentNode->rotation());
159 n = mat.mapVector(n);
160 } break;
161 case QQuick3DParticleShape::ShapeType::Sphere:
162 if (particleIndex != m_cachedIndex)
163 getPosition(particleIndex);
164 n = m_cachedPosition.normalized();
165 break;
166 case QQuick3DParticleShape::ShapeType::Cylinder:
167 QVector3D scale = m_parentNode->scale();
168 float theta = rand->get(particleIndex, QPRand::Shape3) * float(M_PI) * 2.0f;
169 float x = QPCOS(theta);
170 float z = QPSIN(theta);
171 x = x * scale.x();
172 z = z * scale.z();
173 QVector3D normal(x, 0.0, z);
174 QMatrix4x4 mat;
175 mat.rotate(m_parentNode->rotation());
176 n = mat.mapVector(normal.normalized());
177 break;
178 }
179 return n;
180}
181
182QVector3D QQuick3DParticleShape::randomPositionCube(int particleIndex) const
183{
184 auto rand = m_system->rand();
185 QVector3D s = m_parentNode->scale() * m_extents;
186 float x = s.x() - (rand->get(particleIndex, QPRand::Shape1) * s.x() * 2.0f);
187 float y = s.y() - (rand->get(particleIndex, QPRand::Shape2) * s.y() * 2.0f);
188 float z = s.z() - (rand->get(particleIndex, QPRand::Shape3) * s.z() * 2.0f);
189 if (!m_fill) {
190 // Random 0..5 for cube sides
191 int side = int(rand->get(particleIndex, QPRand::Shape4) * 6);
192 if (side == 0)
193 x = -s.x();
194 else if (side == 1)
195 x = s.x();
196 else if (side == 2)
197 y = -s.y();
198 else if (side == 3)
199 y = s.y();
200 else if (side == 4)
201 z = -s.z();
202 else
203 z = s.z();
204 }
205 QMatrix4x4 mat;
206 mat.rotate(m_parentNode->rotation());
207 return mat.mapVector(QVector3D(x, y, z));
208}
209
210QVector3D QQuick3DParticleShape::randomPositionSphere(int particleIndex) const
211{
212 auto rand = m_system->rand();
213 QVector3D scale = m_parentNode->scale() * m_extents;
214 float theta = rand->get(particleIndex, QPRand::Shape1) * float(M_PI) * 2.0f;
215 float v = rand->get(particleIndex, QPRand::Shape2);
216 float phi = acos((2.0f * v) - 1.0f);
217 float r = m_fill ? pow(rand->get(particleIndex, QPRand::Shape3), 1.0f / 3.0f) : 1.0f;
218 float x = r * QPSIN(phi) * QPCOS(theta);
219 float y = r * QPSIN(phi) * QPSIN(theta);
220 float z = r * QPCOS(phi);
221 QVector3D pos(x, y, z);
222 pos *= scale;
223 QMatrix4x4 mat;
224 mat.rotate(m_parentNode->rotation());
225 return mat.mapVector(pos);
226}
227
228QVector3D QQuick3DParticleShape::randomPositionCylinder(int particleIndex) const
229{
230 auto rand = m_system->rand();
231 QVector3D scale = m_parentNode->scale() * m_extents;
232 float y = scale.y() - (rand->get(particleIndex, QPRand::Shape1) * scale.y() * 2.0f);
233 float r = 1.0f;
234 if (m_fill)
235 r = sqrt(rand->get(particleIndex, QPRand::Shape2));
236 float theta = rand->get(particleIndex, QPRand::Shape3) * float(M_PI) * 2.0f;
237 float x = r * QPCOS(theta);
238 float z = r * QPSIN(theta);
239 x = x * scale.x();
240 z = z * scale.z();
241 QVector3D pos(x, y, z);
242 QMatrix4x4 mat;
243 mat.rotate(m_parentNode->rotation());
244 return mat.mapVector(pos);
245}
246
247QT_END_NAMESPACE
#define M_PI
Definition qmath.h:200
#define QPSIN
#define QPCOS