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