1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#pragma once
4
5#include "BsCorePrerequisites.h"
6#include "Particles/BsParticleModule.h"
7#include "Math/BsDegree.h"
8#include "Math/BsVector2.h"
9#include "Math/BsVector3.h"
10#include "Math/BsMatrix4.h"
11#include "BsParticleDistribution.h"
12
13namespace bs
14{
15 class Random;
16 class ParticleSet;
17
18 /** @addtogroup Particles
19 * @{
20 */
21
22 /** Types of emission modes. */
23 enum class BS_SCRIPT_EXPORT(m:Particles) ParticleEmissionModeType
24 {
25 /** Position will be picked randomly on a shape. */
26 Random,
27
28 /** Positions will loop around the shape in a predictable fashion. */
29 Loop,
30
31 /** Similar to Loop, except the order will be reversed when one loop iteration finishes. */
32 PingPong,
33
34 /**
35 * All particles spawned on the shape at some instant (usually a frame) will be spread around the shape equally.
36 */
37 Spread
38 };
39
40 /** Controls how are particle positions on a shape chosen. */
41 struct BS_SCRIPT_EXPORT(m:Particles,pl:true) ParticleEmissionMode
42 {
43 /** Type that determines general behaviour. */
44 ParticleEmissionModeType type = ParticleEmissionModeType::Random;
45
46 /**
47 * Speed along which particle generation should move around the shape, relevant for Loop and PingPing emission
48 * modes.
49 */
50 float speed = 1.0f;
51
52 /**
53 * Determines the minimum interval allowed between the generated particles. 0 specifies the particles can be
54 * generated anywhere on the shape.
55 */
56 float interval = 0.0f;
57 };
58
59 /**
60 * Base class from all emitter shapes. Emitter shapes determine the position and direction of newly created particles.
61 */
62 class BS_CORE_EXPORT BS_SCRIPT_EXPORT(m:Particles) ParticleEmitterShape : public IReflectable
63 {
64 public:
65 virtual ~ParticleEmitterShape() = default;
66
67 /**
68 * @name Internal
69 * @{
70 */
71
72 /**
73 * Spawns a new set of particles using the current shape's distribution.
74 *
75 * @param[in] random Random number generator.
76 * @param[in] particles Particle set in which to insert new particles.
77 * @param[in] count Number of particles to spawn.
78 * @param[in] state Optional state that can contain various per-frame information required for spawning
79 * the particles.
80 * @return Index at which the first of the particles was inserted, with other particles following
81 * sequentially.
82 */
83 virtual UINT32 _spawn(const Random& random, ParticleSet& particles, UINT32 count,
84 const ParticleSystemState& state) const = 0;
85
86 /** @} */
87 protected:
88 friend class ParticleEmitter;
89
90 ParticleEmitterShape() = default;
91
92 /**
93 * Calculates the bounds of the emitter shape.
94 *
95 * @param[in] shape AABB for the emitter shape itself.
96 * @param[in] velocity AABB for the generated normals.
97 */
98 virtual void calcBounds(AABox& shape, AABox& velocity) const = 0;
99
100 /**
101 * Checks has the emitter been initialized properly. If the emitter is not valid then the spawn() method is
102 * not allowed to be called.
103 */
104 bool isValid() const { return mIsValid; }
105
106 bool mIsValid = true;
107 };
108
109 /** Determines the emission type for the cone particle emitter shape. */
110 enum class BS_SCRIPT_EXPORT(m:Particles) ParticleEmitterConeType
111 {
112 /** Emit particles only from the cone base. */
113 Base,
114 /** Emit particles from the entire cone volume. */
115 Volume
116 };
117
118 /** Information describing a ParticleEmitterConeShape. */
119 struct BS_SCRIPT_EXPORT(m:Particles,pl:true,n:ParticleConeShapeOptions) PARTICLE_CONE_SHAPE_DESC
120 {
121 /** Determines where on the cone are the particles emitter from. */
122 ParticleEmitterConeType type = ParticleEmitterConeType::Base;
123
124 /** Radius of the cone base. */
125 float radius = 0.0f;
126
127 /** Angle of the cone. */
128 Degree angle = Degree(45.0f);
129
130 /** Length of the cone. Irrelevant if emission type is Base. */
131 float length = 1.0f;
132
133 /**
134 * Proportion of the volume that can emit particles. Thickness of 0 results in particles being emitted only from the
135 * edge of the cone, while thickness of 1 results in particles being emitted from the entire volume. In-between
136 * values will use a part of the volume.
137 */
138 float thickness = 1.0f;
139
140 /** Angular portion of the cone from which to emit particles from, in degrees. */
141 Degree arc = Degree(360.0f);
142
143 /** Determines how will particle positions on the shape be generated. */
144 ParticleEmissionMode mode;
145 };
146
147 /**
148 * Particle emitter shape that emits particles from a cone. Particles can be created on cone base or volume, while
149 * controling the radial arc of the emitted portion of the volume, as well as thickness of the cone emission volume.
150 * All particles will have random normals within the distribution of the cone.
151 */
152 class BS_CORE_EXPORT BS_SCRIPT_EXPORT(m:Particles) ParticleEmitterConeShape : public ParticleEmitterShape
153 {
154 public:
155 ParticleEmitterConeShape(const PARTICLE_CONE_SHAPE_DESC& desc);
156 ParticleEmitterConeShape() = default;
157 virtual ~ParticleEmitterConeShape() = default;
158
159 /** Options describing the shape. */
160 BS_SCRIPT_EXPORT(pr:setter,n:Options,inline)
161 void setOptions(const PARTICLE_CONE_SHAPE_DESC& options) { mInfo = options; }
162
163 /** @copydoc setOptions */
164 BS_SCRIPT_EXPORT(pr:getter,n:Options)
165 const PARTICLE_CONE_SHAPE_DESC& getOptions() const { return mInfo; }
166
167 /** Creates a new particle emitter cone shape. */
168 BS_SCRIPT_EXPORT(ec:T)
169 static SPtr<ParticleEmitterConeShape> create(const PARTICLE_CONE_SHAPE_DESC& desc);
170
171 /** Creates a new particle emitter cone shape. */
172 BS_SCRIPT_EXPORT(ec:T)
173 static SPtr<ParticleEmitterConeShape> create();
174
175 /**
176 * @name Internal
177 * @{
178 */
179
180 /** @copydoc ParticleEmitterShape::_spawn */
181 UINT32 _spawn(const Random& random, ParticleSet& particles, UINT32 count,
182 const ParticleSystemState& state) const override;
183
184 /** Spawns a single particle randomly, generating its position and normal. */
185 void _spawn(const Random& random, Vector3& position, Vector3& normal) const;
186
187 /** Spawns a single particle on the specified point on the cone, generating its position and normal. */
188 void _spawn(float t, Vector3& position, Vector3& normal) const;
189
190 /** @} */
191 protected:
192 /** @copydoc ParticleEmitterShape::calcBounds */
193 void calcBounds(AABox& shape, AABox& velocity) const override;
194
195 /** Generates a position and normal of a particle based on the input 2D position on the cone circle base. */
196 void getPointInCone(const Vector2& pos2D, float distance, Vector3& position, Vector3& normal) const;
197
198 PARTICLE_CONE_SHAPE_DESC mInfo;
199
200 /************************************************************************/
201 /* RTTI */
202 /************************************************************************/
203 public:
204 friend class ParticleEmitterConeShapeRTTI;
205 static RTTITypeBase* getRTTIStatic();
206 RTTITypeBase* getRTTI() const override;
207 };
208
209 /** Information describing a ParticleEmitterSphereShape. */
210 struct BS_SCRIPT_EXPORT(m:Particles,pl:true,n:ParticleSphereShapeOptions) PARTICLE_SPHERE_SHAPE_DESC
211 {
212 /** Radius of the sphere. */
213 float radius = 1.0f;
214
215 /**
216 * Proportion of the volume that can emit particles. Thickness of 0 results in particles being emitted only from the
217 * edge of the volume, while thickness of 1 results in particles being emitted from the entire volume. In-between
218 * values will use a part of the volume.
219 */
220 float thickness = 0.0f;
221 };
222
223 /**
224 * Particle emitter shape that emits particles from a sphere. Particles can be emitted from sphere surface, the entire
225 * volume or a proportion of the volume depending on the thickness parameter. All particles will have normals pointing
226 * outwards in a spherical direction.
227 */
228 class BS_CORE_EXPORT BS_SCRIPT_EXPORT(m:Particles) ParticleEmitterSphereShape : public ParticleEmitterShape
229 {
230 public:
231 ParticleEmitterSphereShape() = default;
232 ParticleEmitterSphereShape(const PARTICLE_SPHERE_SHAPE_DESC& desc);
233
234 /** Options describing the shape. */
235 BS_SCRIPT_EXPORT(pr:setter,n:Options,inline)
236 void setOptions(const PARTICLE_SPHERE_SHAPE_DESC& options) { mInfo = options; }
237
238 /** @copydoc setOptions */
239 BS_SCRIPT_EXPORT(pr:getter,n:Options)
240 const PARTICLE_SPHERE_SHAPE_DESC& getOptions() const { return mInfo; }
241
242 /** Creates a new particle emitter sphere shape. */
243 BS_SCRIPT_EXPORT(ec:T)
244 static SPtr<ParticleEmitterSphereShape> create(const PARTICLE_SPHERE_SHAPE_DESC& desc);
245
246 /** Creates a new particle emitter sphere shape. */
247 BS_SCRIPT_EXPORT(ec:T)
248 static SPtr<ParticleEmitterSphereShape> create();
249
250 /**
251 * @name Internal
252 * @{
253 */
254
255 /** @copydoc ParticleEmitterShape::_spawn */
256 UINT32 _spawn(const Random& random, ParticleSet& particles, UINT32 count,
257 const ParticleSystemState& state) const override;
258
259 /** Spawns a single particle, generating its position and normal. */
260 void _spawn(const Random& random, Vector3& position, Vector3& normal) const;
261
262 /** @} */
263 protected:
264 /** @copydoc ParticleEmitterShape::calcBounds */
265 void calcBounds(AABox& shape, AABox& velocity) const override;
266
267 PARTICLE_SPHERE_SHAPE_DESC mInfo;
268
269 /************************************************************************/
270 /* RTTI */
271 /************************************************************************/
272 public:
273 friend class ParticleEmitterSphereShapeRTTI;
274 static RTTITypeBase* getRTTIStatic();
275 RTTITypeBase* getRTTI() const override;
276 };
277
278 /** Information describing a ParticleEmitterHemisphereShape. */
279 struct BS_SCRIPT_EXPORT(m:Particles,pl:true,n:ParticleHemisphereShapeOptions) PARTICLE_HEMISPHERE_SHAPE_DESC
280 {
281 /** Radius of the hemisphere. */
282 float radius = 1.0f;
283
284 /**
285 * Proportion of the volume that can emit particles. Thickness of 0 results in particles being emitted only from the
286 * edge of the volume, while thickness of 1 results in particles being emitted from the entire volume. In-between
287 * values will use a part of the volume.
288 */
289 float thickness = 0.0f;
290 };
291
292 /**
293 * Particle emitter shape that emits particles from a hemisphere. Particles can be emitted from the hemisphere surface,
294 * the entire volume or a proportion of the volume depending on the thickness parameter. All particles will have
295 * normals pointing outwards in a spherical direction.
296 */
297 class BS_CORE_EXPORT BS_SCRIPT_EXPORT(m:Particles) ParticleEmitterHemisphereShape : public ParticleEmitterShape
298 {
299 public:
300 ParticleEmitterHemisphereShape() = default;
301 ParticleEmitterHemisphereShape(const PARTICLE_HEMISPHERE_SHAPE_DESC& desc);
302
303 /** Options describing the shape. */
304 BS_SCRIPT_EXPORT(pr:setter,n:Options,inline)
305 void setOptions(const PARTICLE_HEMISPHERE_SHAPE_DESC& options) { mInfo = options; }
306
307 /** @copydoc setOptions */
308 BS_SCRIPT_EXPORT(pr:getter,n:Options)
309 const PARTICLE_HEMISPHERE_SHAPE_DESC& getOptions() const { return mInfo; }
310
311 /** Creates a new particle emitter sphere shape. */
312 BS_SCRIPT_EXPORT(ec:T)
313 static SPtr<ParticleEmitterHemisphereShape> create(const PARTICLE_HEMISPHERE_SHAPE_DESC& desc);
314
315 /** Creates a new particle emitter sphere shape. */
316 BS_SCRIPT_EXPORT(ec:T)
317 static SPtr<ParticleEmitterHemisphereShape> create();
318
319 /**
320 * @name Internal
321 * @{
322 */
323
324 /** @copydoc ParticleEmitterShape::_spawn */
325 UINT32 _spawn(const Random& random, ParticleSet& particles, UINT32 count,
326 const ParticleSystemState& state) const override;
327
328 /** Spawns a single particle, generating its position and normal. */
329 void _spawn(const Random& random, Vector3& position, Vector3& normal) const;
330
331 /** @} */
332 protected:
333 /** @copydoc ParticleEmitterShape::calcBounds */
334 void calcBounds(AABox& shape, AABox& velocity) const override;
335
336 PARTICLE_HEMISPHERE_SHAPE_DESC mInfo;
337
338 /************************************************************************/
339 /* RTTI */
340 /************************************************************************/
341 public:
342 friend class ParticleEmitterHemisphereShapeRTTI;
343 static RTTITypeBase* getRTTIStatic();
344 RTTITypeBase* getRTTI() const override;
345 };
346
347 /** Determines the emission type for the cone particle emitter shape. */
348 enum class BS_SCRIPT_EXPORT(m:Particles) ParticleEmitterBoxType
349 {
350 /** Particles will be emitted from the entire volume. */
351 Volume,
352 /** Particles will be emitted only from box surface. */
353 Surface,
354 /** Particles will be emitted only from box edge. */
355 Edge
356 };
357
358 /** Information describing a ParticleEmitterBoxShape. */
359 struct BS_SCRIPT_EXPORT(m:Particles,pl:true,n:ParticleBoxShapeOptions) PARTICLE_BOX_SHAPE_DESC
360 {
361 /** Determines from which portion of the box should particles be emitted from. */
362 ParticleEmitterBoxType type = ParticleEmitterBoxType::Volume;
363
364 /** Extends of the box. */
365 Vector3 extents = Vector3::ONE;
366 };
367
368 /**
369 * Particle emitter shape that emits particles from an axis aligned box. Particles can be emitted from box volume,
370 * surface or edges. All particles have their normals set to positive Z direction.
371 */
372 class BS_CORE_EXPORT BS_SCRIPT_EXPORT(m:Particles) ParticleEmitterBoxShape : public ParticleEmitterShape
373 {
374 public:
375 ParticleEmitterBoxShape() = default;
376 ParticleEmitterBoxShape(const PARTICLE_BOX_SHAPE_DESC& desc);
377
378 /** Options describing the shape. */
379 BS_SCRIPT_EXPORT(pr:setter,n:Options,inline)
380 void setOptions(const PARTICLE_BOX_SHAPE_DESC& options) { mInfo = options; }
381
382 /** @copydoc setOptions */
383 BS_SCRIPT_EXPORT(pr:getter,n:Options)
384 const PARTICLE_BOX_SHAPE_DESC& getOptions() const { return mInfo; }
385
386 /** Creates a new particle emitter box shape. */
387 BS_SCRIPT_EXPORT(ec:T)
388 static SPtr<ParticleEmitterBoxShape> create(const PARTICLE_BOX_SHAPE_DESC& desc);
389
390 /** Creates a new particle emitter box shape. */
391 BS_SCRIPT_EXPORT(ec:T)
392 static SPtr<ParticleEmitterBoxShape> create();
393
394 /**
395 * @name Internal
396 * @{
397 */
398
399 /** @copydoc ParticleEmitterShape::_spawn */
400 UINT32 _spawn(const Random& random, ParticleSet& particles, UINT32 count,
401 const ParticleSystemState& state) const override;
402
403 /** Spawns a single particle, generating its position and normal. */
404 void _spawn(const Random& random, Vector3& position, Vector3& normal) const;
405
406 /** @} */
407 protected:
408 /** @copydoc ParticleEmitterShape::calcBounds */
409 void calcBounds(AABox& shape, AABox& velocity) const override;
410
411 PARTICLE_BOX_SHAPE_DESC mInfo;
412
413 float mSurfaceArea[3];
414 float mEdgeLengths[3];
415
416 /************************************************************************/
417 /* RTTI */
418 /************************************************************************/
419 public:
420 friend class ParticleEmitterBoxShapeRTTI;
421 static RTTITypeBase* getRTTIStatic();
422 RTTITypeBase* getRTTI() const override;
423 };
424
425 /** Information describing a ParticleEmitterLineShape. */
426 struct BS_SCRIPT_EXPORT(m:Particles,pl:true,n:ParticleLineShapeOptions) PARTICLE_LINE_SHAPE_DESC
427 {
428 /** Length of the line. */
429 float length = 1.0f;
430
431 /** Determines how will particle positions on the shape be generated. */
432 ParticleEmissionMode mode;
433 };
434
435 /** Particle emitter shape that emits particles from a line segment. */
436 class BS_CORE_EXPORT BS_SCRIPT_EXPORT(m:Particles) ParticleEmitterLineShape : public ParticleEmitterShape
437 {
438 public:
439 ParticleEmitterLineShape() = default;
440 ParticleEmitterLineShape(const PARTICLE_LINE_SHAPE_DESC& desc);
441
442 /** Options describing the shape. */
443 BS_SCRIPT_EXPORT(pr:setter,n:Options,inline)
444 void setOptions(const PARTICLE_LINE_SHAPE_DESC& options) { mInfo = options; }
445
446 /** @copydoc setOptions */
447 BS_SCRIPT_EXPORT(pr:getter,n:Options)
448 const PARTICLE_LINE_SHAPE_DESC& getOptions() const { return mInfo; }
449
450 /** Creates a new particle emitter edge shape. */
451 BS_SCRIPT_EXPORT(ec:T)
452 static SPtr<ParticleEmitterLineShape> create(const PARTICLE_LINE_SHAPE_DESC& desc);
453
454 /** Creates a new particle emitter edge shape. */
455 BS_SCRIPT_EXPORT(ec:T)
456 static SPtr<ParticleEmitterLineShape> create();
457
458 /**
459 * @name Internal
460 * @{
461 */
462
463 /** @copydoc ParticleEmitterShape::_spawn */
464 UINT32 _spawn(const Random& random, ParticleSet& particles, UINT32 count,
465 const ParticleSystemState& state) const override;
466
467 /** Spawns a single particle randomly, generating its position and normal. */
468 void _spawn(const Random& random, Vector3& position, Vector3& normal) const;
469
470 /** Spawns a single particle on the specified point on the line, generating its position and normal. */
471 void _spawn(float t, Vector3& position, Vector3& normal) const;
472
473 /** @} */
474 protected:
475 /** @copydoc ParticleEmitterShape::calcBounds */
476 void calcBounds(AABox& shape, AABox& velocity) const override;
477
478 PARTICLE_LINE_SHAPE_DESC mInfo;
479
480 /************************************************************************/
481 /* RTTI */
482 /************************************************************************/
483 public:
484 friend class ParticleEmitterLineShapeRTTI;
485 static RTTITypeBase* getRTTIStatic();
486 RTTITypeBase* getRTTI() const override;
487 };
488
489 /** Information describing a ParticleEmitterCircleShape. */
490 struct BS_SCRIPT_EXPORT(m:Particles,pl:true,n:ParticleCircleShapeOptions) PARTICLE_CIRCLE_SHAPE_DESC
491 {
492 /** Radius of the circle. */
493 float radius = 1.0f;
494
495 /**
496 * Proportion of the surface that can emit particles. Thickness of 0 results in particles being emitted only from
497 * the edge of the circle, while thickness of 1 results in particles being emitted from the entire surface.
498 * In-between values will use a part of the surface.
499 */
500 float thickness = 0.0f;
501
502 /** Angular portion of the cone from which to emit particles from, in degrees. */
503 Degree arc = Degree(360.0f);
504
505 /** Determines how will particle positions on the shape be generated. */
506 ParticleEmissionMode mode;
507 };
508
509 /**
510 * Particle emitter shape that emits particles from a circle. Using the thickness parameter you can control whether to
511 * emit only from circle edge, the entire surface or just a part of the surface. Using the arc parameter you can emit
512 * from a specific angular portion of the circle.
513 */
514 class BS_CORE_EXPORT BS_SCRIPT_EXPORT(m:Particles) ParticleEmitterCircleShape : public ParticleEmitterShape
515 {
516 public:
517 ParticleEmitterCircleShape() = default;
518 ParticleEmitterCircleShape(const PARTICLE_CIRCLE_SHAPE_DESC& desc);
519 virtual ~ParticleEmitterCircleShape() = default;
520
521 /** Options describing the shape. */
522 BS_SCRIPT_EXPORT(pr:setter,n:Options,inline)
523 void setOptions(const PARTICLE_CIRCLE_SHAPE_DESC& options) { mInfo = options; }
524
525 /** @copydoc setOptions */
526 BS_SCRIPT_EXPORT(pr:getter,n:Options)
527 const PARTICLE_CIRCLE_SHAPE_DESC& getOptions() const { return mInfo; }
528
529 /** Creates a new particle emitter circle shape. */
530 BS_SCRIPT_EXPORT(ec:T)
531 static SPtr<ParticleEmitterCircleShape> create(const PARTICLE_CIRCLE_SHAPE_DESC& desc);
532
533 /** Creates a new particle emitter circle shape. */
534 BS_SCRIPT_EXPORT(ec:T)
535 static SPtr<ParticleEmitterCircleShape> create();
536
537 /**
538 * @name Internal
539 * @{
540 */
541
542 /** @copydoc ParticleEmitterShape::_spawn */
543 UINT32 _spawn(const Random& random, ParticleSet& particles, UINT32 count,
544 const ParticleSystemState& state) const override;
545
546 /** Spawns a single particle randomly, generating its position and normal. */
547 void _spawn(const Random& random, Vector3& position, Vector3& normal) const;
548
549 /** Spawns a single particle on the specified point on the circle, generating its position and normal. */
550 void _spawn(float t, Vector3& position, Vector3& normal) const;
551
552 /** @} */
553 protected:
554 /** @copydoc ParticleEmitterShape::calcBounds */
555 void calcBounds(AABox& shape, AABox& velocity) const override;
556
557 PARTICLE_CIRCLE_SHAPE_DESC mInfo;
558
559 /************************************************************************/
560 /* RTTI */
561 /************************************************************************/
562 public:
563 friend class ParticleEmitterCircleShapeRTTI;
564 static RTTITypeBase* getRTTIStatic();
565 RTTITypeBase* getRTTI() const override;
566 };
567
568 /** Information describing a ParticleEmitterRectShape. */
569 struct BS_SCRIPT_EXPORT(m:Particles,pl:true,n:ParticleRectShapeOptions) PARTICLE_RECT_SHAPE_DESC
570 {
571 /** Extents of the rectangle. */
572 Vector2 extents = Vector2::ONE;
573 };
574
575 /** Particle emitter shape that emits particles from the surface of a rectangle. */
576 class BS_CORE_EXPORT BS_SCRIPT_EXPORT(m:Particles) ParticleEmitterRectShape : public ParticleEmitterShape
577 {
578 public:
579 ParticleEmitterRectShape() = default;
580 ParticleEmitterRectShape(const PARTICLE_RECT_SHAPE_DESC& desc);
581
582 /** Options describing the shape. */
583 BS_SCRIPT_EXPORT(pr:setter,n:Options,inline)
584 void setOptions(const PARTICLE_RECT_SHAPE_DESC& options) { mInfo = options; }
585
586 /** @copydoc setOptions */
587 BS_SCRIPT_EXPORT(pr:getter,n:Options)
588 const PARTICLE_RECT_SHAPE_DESC& getOptions() const { return mInfo; }
589
590 /** Creates a new particle emitter rectangle shape. */
591 BS_SCRIPT_EXPORT(ec:T)
592 static SPtr<ParticleEmitterRectShape> create(const PARTICLE_RECT_SHAPE_DESC& desc);
593
594 /** Creates a new particle emitter rectangle shape. */
595 BS_SCRIPT_EXPORT(ec:T)
596 static SPtr<ParticleEmitterRectShape> create();
597
598 /**
599 * @name Internal
600 * @{
601 */
602
603 /** @copydoc ParticleEmitterShape::_spawn */
604 UINT32 _spawn(const Random& random, ParticleSet& particles, UINT32 count,
605 const ParticleSystemState& state) const override;
606
607 /** Spawns a single particle, generating its position and normal. */
608 void _spawn(const Random& random, Vector3& position, Vector3& normal) const;
609
610 /** @} */
611 protected:
612 /** @copydoc ParticleEmitterShape::calcBounds */
613 void calcBounds(AABox& shape, AABox& velocity) const override;
614
615 PARTICLE_RECT_SHAPE_DESC mInfo;
616
617 /************************************************************************/
618 /* RTTI */
619 /************************************************************************/
620 public:
621 friend class ParticleEmitterRectShapeRTTI;
622 static RTTITypeBase* getRTTIStatic();
623 RTTITypeBase* getRTTI() const override;
624 };
625
626 /** Determines the emission type for the mesh particle emitter shape. */
627 enum class BS_SCRIPT_EXPORT(m:Particles) ParticleEmitterMeshType
628 {
629 /** Particles will be emitted from mesh vertices. */
630 Vertex,
631 /** Particles will be emitted from mesh edges. */
632 Edge,
633 /** Particles will be emitted from mesh triangles. */
634 Triangle
635 };
636
637 /** Information describing a ParticleEmitterStaticMeshShape. */
638 struct BS_SCRIPT_EXPORT(m:Particles,pl:true,n:ParticleStaticMeshShapeOptions) PARTICLE_STATIC_MESH_SHAPE_DESC
639 {
640 /** Determines from which portion of the mesh are the particles emitted from. */
641 ParticleEmitterMeshType type = ParticleEmitterMeshType::Triangle;
642
643 /**
644 * When enabled the particles will be emitted sequentially from mesh vertices in the order they are defined.
645 * Only relevant for the Vertex emit mode.
646 */
647 bool sequential = false;
648
649 /**
650 * Mesh to spawn particles on. Must at least contain per-vertex position data encoded as 3D float vectors. Can
651 * optionally contain per-vertex normals encoded as 3D float vectors or as 4-byte unsigned-normalized format.
652 */
653 HMesh mesh;
654 };
655
656 /**
657 * Calculates and stores per-triangle weights that can be used for easily picking a random triangle on a mesh, ensuring
658 * larger triangles are picked more likely.
659 */
660 class MeshWeightedTriangles
661 {
662 /** Contains the cumulative, normalized weight of the triangle and its vertex indices. */
663 struct TriangleWeight
664 {
665 float cumulativeWeight;
666 UINT32 indices[3];
667 };
668
669 public:
670 MeshWeightedTriangles() = default;
671 MeshWeightedTriangles(const MeshData& meshData);
672
673 /** Updates the weights from the provided mesh data. */
674 void calculate(const MeshData& meshData);
675
676 /** Find a random triangle on the mesh and outputs its vertex indices. */
677 void getTriangle(const Random& random, std::array<UINT32, 3>& indices) const;
678
679 private:
680 Vector<TriangleWeight> mWeights;
681 };
682
683 /** Contains common functionality for particle mesh emitters. */
684 class MeshEmissionHelper
685 {
686 public:
687 /**
688 * Initializes the emission helper if the provided mesh contains necessary data for particle emission. Otherwise
689 * reports any issues in the log.
690 *
691 * @param[in] mesh Mesh to validate.
692 * @param[in] perVertex Set to true if particle emission is happening on mesh vertices.
693 * @param[in] skinning Set to true if the mesh will be animated using skinning.
694 * @return True if initialized, or false if issues were detected.
695 */
696 bool initialize(const HMesh& mesh, bool perVertex, bool skinning);
697
698 /**
699 * Returns the next sequential vertex on the mesh and increments the internal counter so the next vertex is
700 * returned on the following call. Loops around if end is reached. Returns vertex position, normal and index.
701 */
702 void getSequentialVertex(Vector3& position, Vector3& normal, UINT32& idx) const;
703
704 /** Randomly picks a vertex on the mesh and returns its position, normal and index. */
705 void getRandomVertex(const Random& random, Vector3& position, Vector3& normal, UINT32& idx) const;
706
707 /** Randomly picks an edge on the mesh and returns the position, normal and indices of its vertices. */
708 void getRandomEdge(const Random& random, std::array<Vector3, 2>& position, std::array<Vector3, 2>& normal,
709 std::array<UINT32, 2>& idx) const;
710
711 /** Randomly picks an triangle on the mesh and returns the position, normal and indices of its vertices. */
712 void getRandomTriangle(const Random& random, std::array<Vector3, 3>& position, std::array<Vector3, 3>& normal,
713 std::array<UINT32, 3>& idx) const;
714
715 /** Evaluates a blend matrix for a vertex at the specified index. */
716 Matrix4 getBlendMatrix(const Matrix4* bones, UINT32 vertexIdx) const;
717
718 private:
719 MeshWeightedTriangles mWeightedTriangles;
720
721 UINT8* mVertices = nullptr;
722 UINT8* mNormals = nullptr;
723 UINT32 mNumVertices = 0;
724 UINT32 mVertexStride = 0;
725 bool m32BitNormals = true;
726
727 UINT8* mBoneIndices = nullptr;
728 UINT8* mBoneWeights = nullptr;
729
730 SPtr<MeshData> mMeshData;
731
732 // Transient
733 mutable UINT32 mNextSequentialIdx = 0;
734 };
735
736 /**
737 * Particle emitter shape that emits particles from a surface of a static (non-animated) mesh. Particles can be
738 * emitted from mesh vertices, edges or triangles. If information about normals exists, particles will also inherit
739 * the normals.
740 */
741 class BS_CORE_EXPORT BS_SCRIPT_EXPORT(m:Particles) ParticleEmitterStaticMeshShape : public ParticleEmitterShape
742 {
743 public:
744 ParticleEmitterStaticMeshShape(const PARTICLE_STATIC_MESH_SHAPE_DESC& desc);
745 ParticleEmitterStaticMeshShape();
746 virtual ~ParticleEmitterStaticMeshShape() = default;
747
748 /** Options describing the shape. */
749 BS_SCRIPT_EXPORT(pr:setter,n:Options,inline)
750 void setOptions(const PARTICLE_STATIC_MESH_SHAPE_DESC& options);
751
752 /** @copydoc setOptions */
753 BS_SCRIPT_EXPORT(pr:getter,n:Options)
754 const PARTICLE_STATIC_MESH_SHAPE_DESC& getOptions() const { return mInfo; }
755
756 /** Creates a new particle emitter static mesh shape. */
757 BS_SCRIPT_EXPORT(ec:T)
758 static SPtr<ParticleEmitterStaticMeshShape> create(const PARTICLE_STATIC_MESH_SHAPE_DESC& desc);
759
760 /** Creates a new particle emitter static mesh shape. */
761 BS_SCRIPT_EXPORT(ec:T)
762 static SPtr<ParticleEmitterStaticMeshShape> create();
763
764 /**
765 * @name Internal
766 * @{
767 */
768
769 /** @copydoc ParticleEmitterShape::_spawn */
770 UINT32 _spawn(const Random& random, ParticleSet& particles, UINT32 count,
771 const ParticleSystemState& state) const override;
772
773 /** @} */
774 protected:
775 /** @copydoc ParticleEmitterShape::calcBounds */
776 void calcBounds(AABox& shape, AABox& velocity) const override;
777
778 PARTICLE_STATIC_MESH_SHAPE_DESC mInfo;
779 MeshEmissionHelper mMeshEmissionHelper;
780
781 /************************************************************************/
782 /* RTTI */
783 /************************************************************************/
784 public:
785 friend class ParticleEmitterStaticMeshShapeRTTI;
786 static RTTITypeBase* getRTTIStatic();
787 RTTITypeBase* getRTTI() const override;
788 };
789
790 /** Information describing a ParticleEmitterSkinnedMeshShape. */
791 struct BS_SCRIPT_EXPORT(m:Particles,pl:true,n:ParticleSkinnedMeshShapeOptions) PARTICLE_SKINNED_MESH_SHAPE_DESC
792 {
793 /** Determines from which portion of the mesh are the particles emitted from. */
794 ParticleEmitterMeshType type = ParticleEmitterMeshType::Triangle;
795
796 /**
797 * When enabled the particles will be emitted sequentially from mesh vertices in the order they are defined.
798 * Only relevant for the Vertex emit mode.
799 */
800 bool sequential = false;
801
802 /**
803 * Renderable object containing a mesh to spawn particles on, as well as the attached Animation object resposible
804 * for performing skinned animation. Mesh must at least contain per-vertex position data encoded as 3D float
805 * vectors, blend indices encoded in 4-byte format, and blend weights encoded a 4D float vectors. Can optionally
806 * contain per-vertex normals encoded as 3D float vectors or as 4-byte unsigned-normalized format.
807 */
808 ComponentOrActor<Renderable> renderable;
809 };
810
811 /**
812 * Particle emitter shape that emits particles from a surface of a skinned (animated) mesh. Particles can be
813 * emitted from mesh vertices, edges or triangles. If information about normals exists, particles will also inherit
814 * the normals.
815 */
816 class BS_CORE_EXPORT BS_SCRIPT_EXPORT(m:Particles) ParticleEmitterSkinnedMeshShape : public ParticleEmitterShape
817 {
818 public:
819 ParticleEmitterSkinnedMeshShape(const PARTICLE_SKINNED_MESH_SHAPE_DESC& desc);
820 ParticleEmitterSkinnedMeshShape();
821 virtual ~ParticleEmitterSkinnedMeshShape() = default;
822
823 /** Options describing the shape. */
824 BS_SCRIPT_EXPORT(pr:setter,n:Options,inline)
825 void setOptions(const PARTICLE_SKINNED_MESH_SHAPE_DESC& options);
826
827 /** @copydoc setOptions */
828 BS_SCRIPT_EXPORT(pr:getter,n:Options)
829 const PARTICLE_SKINNED_MESH_SHAPE_DESC& getOptions() const { return mInfo; }
830
831 /** Creates a new particle emitter skinned mesh shape. */
832 BS_SCRIPT_EXPORT(ec:T)
833 static SPtr<ParticleEmitterSkinnedMeshShape> create(const PARTICLE_SKINNED_MESH_SHAPE_DESC& desc);
834
835 /** Creates a new particle emitter skinned mesh shape. */
836 BS_SCRIPT_EXPORT(ec:T)
837 static SPtr<ParticleEmitterSkinnedMeshShape> create();
838
839 /**
840 * @name Internal
841 * @{
842 */
843
844 /** @copydoc ParticleEmitterShape::_spawn */
845 UINT32 _spawn(const Random& random, ParticleSet& particles, UINT32 count,
846 const ParticleSystemState& state) const override;
847
848 /** @} */
849 protected:
850 /** @copydoc ParticleEmitterShape::calcBounds */
851 void calcBounds(AABox& shape, AABox& velocity) const override;
852
853 PARTICLE_SKINNED_MESH_SHAPE_DESC mInfo;
854 MeshEmissionHelper mMeshEmissionHelper;
855
856 /************************************************************************/
857 /* RTTI */
858 /************************************************************************/
859 public:
860 friend class ParticleEmitterSkinnedMeshShapeRTTI;
861 static RTTITypeBase* getRTTIStatic();
862 RTTITypeBase* getRTTI() const override;
863 };
864
865 /** Specifies a burst of particles that occurs at a certain time point. */
866 struct BS_SCRIPT_EXPORT(m:Particles,pl:true) ParticleBurst
867 {
868 ParticleBurst() = default;
869 ParticleBurst(float time, FloatDistribution count, UINT32 cycles = 1, float interval = 1.0f)
870 :time(time), count(std::move(count)), cycles(cycles), interval(interval)
871 { }
872
873 /** Time at which to trigger the burst, in seconds. */
874 float time = 0.0f;
875
876 /** Number of particles to emit when the burst triggers. */
877 FloatDistribution count = 0;
878
879 /**
880 * Determines how many times to trigger the burst. If 0 the burst will trigger infinitely. Use @p interval to
881 * to control the time between each cycle.
882 */
883 UINT32 cycles = 1;
884
885 /** Controls how much time needs to pass before triggering another burst cycle, in seconds. */
886 float interval = 1.0f;
887 };
888
889 /** Handles spawning of new particles using the specified parameters and shape. */
890 class BS_CORE_EXPORT BS_SCRIPT_EXPORT(m:Particles) ParticleEmitter : public ParticleModule
891 {
892 public:
893 /** Shape over which to emit the particles. */
894 BS_SCRIPT_EXPORT(pr:setter,n:Shape)
895 void setShape(SPtr<ParticleEmitterShape> shape) { mShape = std::move(shape); }
896
897 /** @copydoc setShape */
898 BS_SCRIPT_EXPORT(pr:getter,n:Shape)
899 const SPtr<ParticleEmitterShape>& getShape() const { return mShape; }
900
901 /** Determines the number of particles that are emitted every second. */
902 BS_SCRIPT_EXPORT(pr:setter,n:EmissionRate)
903 void setEmissionRate(FloatDistribution value) { mEmissionRate = std::move(value); }
904
905 /** @copydoc setEmissionRate */
906 BS_SCRIPT_EXPORT(pr:getter,n:EmissionRate)
907 const FloatDistribution& getEmissionRate() const { return mEmissionRate; }
908
909 /** Determines discrete intervals to emit particles. */
910 BS_SCRIPT_EXPORT(pr:setter,n:EmissionBursts)
911 void setEmissionBursts(Vector<ParticleBurst> bursts);
912
913 /** @copydoc setEmissionBursts */
914 BS_SCRIPT_EXPORT(pr:getter,n:EmissionBursts)
915 const Vector<ParticleBurst>& getEmissionBursts() const { return mBursts; }
916
917 /** Determines the lifetime of particles when they are initially spawned, in seconds. */
918 BS_SCRIPT_EXPORT(pr:setter,n:InitialLifetime)
919 void setInitialLifetime(FloatDistribution value) { mInitialLifetime = std::move(value); }
920
921 /** @copydoc setInitialLifetime */
922 BS_SCRIPT_EXPORT(pr:getter,n:InitialLifetime)
923 const FloatDistribution& getInitialLifetime() const { return mInitialLifetime; }
924
925 /**
926 * Sets the initial speed of the particles, in meters/second. The speed is applied along the particle's velocity
927 * direction, which is determined by the emission shape and potentially other properties.
928 */
929 BS_SCRIPT_EXPORT(pr:setter,n:InitialSpeed)
930 void setInitialSpeed(FloatDistribution value) { mInitialSpeed = std::move(value); }
931
932 /** @copydoc setInitialSpeed */
933 BS_SCRIPT_EXPORT(pr:getter,n:InitialSpeed)
934 const FloatDistribution& getInitialSpeed() const { return mInitialSpeed; }
935
936 /**
937 * Determines the size of the particles when initially spawned. The size is applied uniformly in all dimensions.
938 * Only used if 3D size is disabled.
939 */
940 BS_SCRIPT_EXPORT(pr:setter,n:InitialSize)
941 void setInitialSize(FloatDistribution value) { mInitialSize = std::move(value); }
942
943 /** @copydoc setInitialSize */
944 BS_SCRIPT_EXPORT(pr:getter,n:InitialSize)
945 const FloatDistribution& getInitialSize() const { return mInitialSize; }
946
947 /**
948 * Determines the size of the particles when initially spawned. Size can be specified for each dimension separately.
949 * Only used if 3D size is enabled.
950 */
951 BS_SCRIPT_EXPORT(pr:setter,n:InitialSize3D)
952 void setInitialSize3D(Vector3Distribution value) { mInitialSize3D = std::move(value); }
953
954 /** @copydoc setInitialSize3D */
955 BS_SCRIPT_EXPORT(pr:getter,n:InitialSize3D)
956 const Vector3Distribution& getInitialSize3D() const { return mInitialSize3D; }
957
958 /**
959 * Determines should the initial particle size be applied uniformly (if disabled), or evaluated separately for each
960 * dimension (if enabled).
961 */
962 BS_SCRIPT_EXPORT(pr:setter,n:Use3DSize)
963 void setUse3DSize(bool value) { mUse3DSize = value; }
964
965 /** @copydoc setUse3DSize */
966 BS_SCRIPT_EXPORT(pr:getter,n:Use3DSize)
967 bool getUse3DSize() const { return mUse3DSize; }
968
969 /**
970 * Determines the rotation of the particles when initially spawned, in degrees. The rotation is applied around the
971 * particle's local Z axis. Only used if 3D rotation is disabled.
972 */
973 BS_SCRIPT_EXPORT(pr:setter,n:InitialRotation)
974 void setInitialRotation(FloatDistribution value) { mInitialRotation = std::move(value); }
975
976 /** @copydoc setInitialRotation */
977 BS_SCRIPT_EXPORT(pr:getter,n:InitialRotation)
978 const FloatDistribution& getInitialRotation() const { return mInitialRotation; }
979
980 /**
981 * Determines the rotation of the particles when initially spawned, in Euler angles. Only used if 3D rotation is
982 * enabled.
983 */
984 BS_SCRIPT_EXPORT(pr:setter,n:InitialRotation3D)
985 void setInitialRotation3D(Vector3Distribution value) { mInitialRotation3D = std::move(value); }
986
987 /** @copydoc setInitialRotation3D */
988 BS_SCRIPT_EXPORT(pr:getter,n:InitialRotation3D)
989 const Vector3Distribution& getInitialRotation3D() const { return mInitialRotation3D; }
990
991 /**
992 * Determines should the initial particle rotation be a single angle applied around a Z axis (if disabled), or a
993 * set of Euler angles that allow you to rotate around every axis (if enabled).
994 */
995 BS_SCRIPT_EXPORT(pr:setter,n:Use3DRotation)
996 void setUse3DRotation(bool value) { mUse3DRotation = value; }
997
998 /** @copydoc setUse3DRotation */
999 BS_SCRIPT_EXPORT(pr:getter,n:Use3DRotation)
1000 bool getUse3DRotation() const { return mUse3DRotation; }
1001
1002 /** Determines the initial color (in RGB channels) and transparency (in A channel) of particles. */
1003 BS_SCRIPT_EXPORT(pr:setter,n:InitialColor)
1004 void setInitialColor(const ColorDistribution& value) { mInitialColor = value; }
1005
1006 /** @copydoc setInitialColor */
1007 BS_SCRIPT_EXPORT(pr:getter,n:InitialColor)
1008 const ColorDistribution& getInitialColor() const { return mInitialColor; }
1009
1010 /**
1011 * Determines a range of values determining a random offset to apply to particle position after it has been emitted.
1012 * Offset will be randomly selected in all three axes in range [-value, value].
1013 */
1014 BS_SCRIPT_EXPORT(pr:setter,n:RandomOffset)
1015 void setRandomOffset(float value) { mRandomOffset = value; }
1016
1017 /** @copydoc setRandomOffset */
1018 BS_SCRIPT_EXPORT(pr:getter,n:RandomOffset)
1019 float getRandomOffset() const { return mRandomOffset; }
1020
1021 /**
1022 * Determines should particle U texture coordinate be randomly flipped, mirroring the image. The value represents
1023 * a percent of particles that should be flipped, in range [0, 1].
1024 */
1025 BS_SCRIPT_EXPORT(pr:setter,n:FlipU)
1026 void setFlipU(float value) { mFlipU = Math::clamp01(value); }
1027
1028 /** @copydoc setFlipU */
1029 BS_SCRIPT_EXPORT(pr:getter,n:FlipU)
1030 float getFlipU() const { return mFlipU; }
1031
1032 /**
1033 * Determines should particle V texture coordinate be randomly flipped, mirroring the image. The value represents
1034 * a percent of particles that should be flipped, in range [0, 1].
1035 */
1036 BS_SCRIPT_EXPORT(pr:setter,n:FlipV)
1037 void setFlipV(float value) { mFlipV = Math::clamp01(value); }
1038
1039 /** @copydoc setFlipV */
1040 BS_SCRIPT_EXPORT(pr:getter,n:FlipV)
1041 float getFlipV() const { return mFlipV; }
1042
1043 /** Creates a new emitter. */
1044 BS_SCRIPT_EXPORT(ec:T)
1045 static SPtr<ParticleEmitter> create();
1046 private:
1047 friend class ParticleSystem;
1048
1049 /**
1050 * Spawns new particles in the specified time increment (if any).
1051 *
1052 * @param[in] random Random number generator.
1053 * @param[in] state Various per-frame information provided by the parent particle system.
1054 * @param[in] set Set to which to append new particles to.
1055 */
1056 void spawn(Random& random, const ParticleSystemState& state, ParticleSet& set) const;
1057
1058 /**
1059 * Spawns the specified number of particles.
1060 *
1061 * @param[in] count Number of particles to spawn.
1062 * @param[in] random Random number generator.
1063 * @param[in] state Various per-frame information provided by the parent particle system.
1064 * @param[in] set Set to which to append new particles to.
1065 * @param[in] spacing When false all particles will use the current emitter time. When true the particles
1066 * will be assigned a time between current time and time step end time, so they are
1067 * unifomly distributed in this time range.
1068 * @return Actual number of spawned particles.
1069 */
1070 UINT32 spawn(UINT32 count, Random& random, const ParticleSystemState& state, ParticleSet& set, bool spacing) const;
1071
1072 // User-visible properties
1073 SPtr<ParticleEmitterShape> mShape;
1074
1075 FloatDistribution mEmissionRate = 50.0f;
1076 Vector<ParticleBurst> mBursts;
1077
1078 FloatDistribution mInitialLifetime = 10.0f;
1079 FloatDistribution mInitialSpeed = 1.0f;
1080
1081 FloatDistribution mInitialSize = 0.1f;
1082 Vector3Distribution mInitialSize3D = Vector3::ONE;
1083 bool mUse3DSize = false;
1084
1085 FloatDistribution mInitialRotation = 0.0f;
1086 Vector3Distribution mInitialRotation3D = Vector3::ZERO;
1087 bool mUse3DRotation = false;
1088
1089 ColorDistribution mInitialColor = Color::White;
1090
1091 float mFlipU = 0.0f;
1092 float mFlipV = 0.0f;
1093
1094 float mRandomOffset = 0.0f;
1095
1096 // Internal state
1097 mutable float mEmitAccumulator = 0.0f;
1098 mutable Vector<float> mBurstAccumulator;
1099
1100 /************************************************************************/
1101 /* RTTI */
1102 /************************************************************************/
1103 public:
1104 friend class ParticleEmitterRTTI;
1105 static RTTITypeBase* getRTTIStatic();
1106 RTTITypeBase* getRTTI() const override;
1107 };
1108
1109 /** @} */
1110
1111}
1112