SLProject  4.2.000
A platform independent 3D computer graphics framework for desktop OS, Android, iOS and online in web browsers
SLParticleSystem.cpp
Go to the documentation of this file.
1 /**
2  * \file SLParticleSystem.cpp
3  * \date February 2022
4  * \remarks Please use clangformat to format the code. See more code style on
5  * https://github.com/cpvrlab/SLProject4/wiki/SLProject-Coding-Style
6  * \authors Affolter Marc in his bachelor thesis in spring 2022
7  * \copyright http://opensource.org/licenses/GPL-3.0
8 */
9 
10 #include <climits>
11 #include <SLParticleSystem.h>
12 #include <SLMaterial.h>
13 #include <SLGLProgram.h>
14 #include <SLGLTexture.h>
15 #include <SLSceneView.h>
16 #include <GlobalTimer.h>
17 #include <Utils.h>
18 
19 //-----------------------------------------------------------------------------
20 //! SLParticleSystem ctor with some initial values. The number of particles
21 /*! The particle emitter position, the start and end random value range
22  * The time to live of the particle (lifetime). A texture, a name
23  * and a flipbook texture.
24  */
26  const SLint amount,
27  const SLVec3f& velocityRandomStart,
28  const SLVec3f& velocityRandomEnd,
29  const SLfloat& timeToLive,
30  SLGLTexture* texC,
31  const SLstring& name,
32  SLGLTexture* texFlipbook,
33  SLTexColorLUT* texGradient,
34  const bool doInstancedDrawing) : SLMesh(assetMgr, name)
35 {
36  assert(!name.empty());
37 
38  _assetManager = assetMgr;
41 
42  // Trick SL project because it wants the mesh to have vertex
43  P.push_back(SLVec3f(0, 0, 0));
44  I32.push_back(0);
45 
46  if (amount > UINT_MAX) // Need to change for number of floats
47  SL_EXIT_MSG("SLParticleSystem supports max. 2^32 vertices.");
48 
50  _amount = amount;
51  _velocityRndMin = velocityRandomStart;
52  _velocityRndMax = velocityRandomEnd;
53 
54  _texParticle = texC;
56  if (texGradient)
58  else
59  _texGradient = new SLTexColorLUT(assetMgr, CLUT_WYR, 256);
60 
61  _updateTime.init(60, 0.0f);
62  _drawTime.init(60, 0.0f);
63 }
64 //-----------------------------------------------------------------------------
65 //! Function which return a position in a sphere
67 {
68  float u = Utils::random(0.0f, radius);
69  float x1 = randomXs.x;
70  float x2 = randomXs.y;
71  float x3 = randomXs.z;
72 
73  float mag = sqrt(x1 * x1 + x2 * x2 + x3 * x3);
74  x1 /= mag;
75  x2 /= mag;
76  x3 /= mag;
77 
78  float c = cbrt(u);
79 
80  return SLVec3f(x1 * c, x2 * c, x3 * c);
81 }
82 //-----------------------------------------------------------------------------
83 //! Function which return a position on a sphere
85 {
86  float x1 = randomXs.x;
87  float x2 = randomXs.y;
88  float x3 = randomXs.z;
89 
90  float mag = sqrt(x1 * x1 + x2 * x2 + x3 * x3);
91  x1 /= mag;
92  x2 /= mag;
93  x3 /= mag;
94 
95  float c = cbrt(radius);
96 
97  return SLVec3f(x1 * c, x2 * c, x3 * c);
98 }
99 //-----------------------------------------------------------------------------
100 //! Function which return the direction towards the exterior of a sphere
102 {
103  // return a unit vector from center to position
104  return (position - SLVec3f(0.0f, 0.0f, 0.0f)).normalized();
105 }
106 //-----------------------------------------------------------------------------
107 //! Function which return a position in a box
109 {
110  float x = Utils::random(-boxScale.x, boxScale.x);
111  float y = Utils::random(-boxScale.y, boxScale.y);
112  float z = Utils::random(-boxScale.z, boxScale.z);
113 
114  return SLVec3f(x, y, z);
115 }
116 //-----------------------------------------------------------------------------
117 //! Function which return a position on a box
119 {
120  int temp = Utils::random(0, 5);
121  float x = 0.0f;
122  float y = 0.0f;
123  float z = 0.0f;
124  if (temp == 0)
125  { // LEFT side
126  x = -boxScale.x;
127  y = Utils::random(-boxScale.y, boxScale.y);
128  z = Utils::random(-boxScale.z, boxScale.z);
129  }
130  else if (temp == 1) // RIGHT side
131  {
132  x = boxScale.x;
133  y = Utils::random(-boxScale.y, boxScale.y);
134  z = Utils::random(-boxScale.z, boxScale.z);
135  }
136  else if (temp == 2) // FRONT side
137  {
138  x = Utils::random(-boxScale.x, boxScale.x);
139  y = Utils::random(-boxScale.y, boxScale.y);
140  z = boxScale.z;
141  }
142  else if (temp == 3) // BACK side
143  {
144  x = Utils::random(-boxScale.x, boxScale.x);
145  y = Utils::random(-boxScale.y, boxScale.y);
146  z = -boxScale.z;
147  }
148  else if (temp == 4) // TOP side
149  {
150  x = Utils::random(-boxScale.x, boxScale.x);
151  y = boxScale.y;
152  z = Utils::random(-boxScale.z, boxScale.z);
153  }
154  else if (temp == 5) // BOTTOM side
155  {
156  x = Utils::random(-boxScale.x, boxScale.x);
157  y = -boxScale.y;
158  z = Utils::random(-boxScale.z, boxScale.z);
159  }
160 
161  return SLVec3f(x, y, z);
162 }
163 //-----------------------------------------------------------------------------
164 //! Function which return the direction towards the exterior of a box
166 {
167  // return a unit vector from center to position
168  return (position - SLVec3f(0.0f, 0.0f, 0.0f)).normalized();
169 }
170 //-----------------------------------------------------------------------------
171 //! Function which return a position in the cone define in the particle system
173 {
174  float y = 0.0f;
175  float radius = _shapeRadius;
176  if (!_doShapeSpawnBase) // Spawn inside volume
177  {
178  // NEED TO HAVE MORE value near 1 when we have smaller base that top
179  y = Utils::random(0.0f, _shapeHeight);
180  radius = _shapeRadius + tan(_shapeAngle * DEG2RAD) * y;
181  }
182  float r = radius * sqrt(random(0.0f, 1.0f));
183  float theta = Utils::random(0.0f, 1.0f) * 2 * PI;
184  float x = r * cos(theta);
185  float z = r * sin(theta);
186 
187  return SLVec3f(x, y, z);
188 }
189 //-----------------------------------------------------------------------------
190 //! Function which return a position on the cone define in the particle system
192 {
193  float y = 0.0f;
194  float radius = _shapeRadius;
195  if (!_doShapeSpawnBase) // Spawn inside volume
196  {
197  // NEED TO HAVE MORE value near 1 when we have smaller base that top
198  y = Utils::random(0.0f, _shapeHeight);
199  radius = _shapeRadius + tan(_shapeAngle * DEG2RAD) * y;
200  }
201  float r = radius;
202  float theta = Utils::random(0.0f, 1.0f) * 2 * PI;
203  float x = r * cos(theta);
204  float z = r * sin(theta);
205 
206  return SLVec3f(x, y, z);
207 }
208 //-----------------------------------------------------------------------------
209 //! Function which return a direction following the cone shape
211 {
212  float maxRadius = _shapeRadius + tan(_shapeAngle * DEG2RAD) * _shapeHeight;
213 
214  // Calculate at which percent our x is, to know how much we need to adapt our angle
215  float percentX = position.x / maxRadius;
216  // Calculate at which percent our z is, to know how much we need to adapt our angle
217  float percentZ = position.z / maxRadius;
218  float newX = position.x + tan(_shapeAngle * percentX * DEG2RAD) * _shapeHeight;
219  float newZ = position.z + tan(_shapeAngle * percentZ * DEG2RAD) * _shapeHeight;
220  return SLVec3f(newX, _shapeHeight, newZ).normalize();
221 }
222 //-----------------------------------------------------------------------------
223 //! Function which returns a position in the pyramid that define the PS
225 {
226  float y = 0.0f;
227  float radius = _shapeWidth;
228  if (!_doShapeSpawnBase) // Spawn inside volume
229  {
230  y = Utils::random(0.0f, _shapeHeight);
231  radius = _shapeWidth + tan(_shapeAngle * DEG2RAD) * y;
232  }
233  float x = Utils::random(-radius, radius);
234  float z = Utils::random(-radius, radius);
235 
236  return SLVec3f(x, y, z);
237 }
238 //-----------------------------------------------------------------------------
239 //! Function which return a position on the pyramid that defines the PS
241 {
242  float y = 0.0f;
243  float radius = _shapeWidth;
244  if (!_doShapeSpawnBase) // Spawn inside volume
245  {
246  y = Utils::random(0.0f, _shapeHeight);
247  radius = _shapeWidth + tan(_shapeAngle * DEG2RAD) * y;
248  }
249 
250  int temp = Utils::random(0, 3);
251  float x = 0.0f, z = 0.0f;
252 
253  if (temp == 0) // LEFT
254  {
255  x = -radius;
256  z = Utils::random(-radius, radius);
257  }
258  else if (temp == 1) // RIGHT
259  {
260  x = radius;
261  z = Utils::random(-radius, radius);
262  }
263  else if (temp == 2) // FRONT
264  {
265  x = Utils::random(-radius, radius);
266  z = radius;
267  }
268  else if (temp == 3) // BACK
269  {
270  x = Utils::random(-radius, radius);
271  z = -radius;
272  }
273 
274  return SLVec3f(x, y, z);
275 }
276 // ----------------------------------------------------------------------------
277 //! Function which return a direction following the pyramid shape
279 {
280  float maxRadius = _shapeWidth +
282 
283  // Calculate at which percent our x & z is to know how much we need to adapt our angle
284  float percentX = position.x / maxRadius;
285  float percentZ = position.z / maxRadius;
286  float newX = position.x + tan(_shapeAngle * percentX * DEG2RAD) * _shapeHeight;
287  float newZ = position.z + tan(_shapeAngle * percentZ * DEG2RAD) * _shapeHeight;
288  return SLVec3f(newX, _shapeHeight, newZ).normalize();
289 }
290 //-----------------------------------------------------------------------------
291 //! Function which will generate the particles and attributes them to the VAO
293 {
294  SLuint seed = (SLuint)chrono::system_clock::now().time_since_epoch().count();
295  default_random_engine generator(seed);
296  normal_distribution<float> distribution(0.0f, 1.0f);
297 
298  SLVVec3f tempP, tempV, tempInitV;
299  SLVfloat tempR, tempST, tempAngulareVelo;
300  SLVuint tempTexNum;
301  SLVVec3f tempInitP;
302 
305  else
307 
309 
310  // Initialize the drawing:
311  if (_doFlipBookTexture)
312  {
313  SLMaterial* mDraw = new SLMaterial(_assetManager,
314  "Drawing-Material",
315  this,
316  _texFlipbook);
317  mDraw->addTexture(_texGradient);
318  mat(mDraw);
319  }
320  else
321  {
322  SLMaterial* mDraw = new SLMaterial(_assetManager,
323  "Drawing-Material",
324  this,
325  _texParticle);
326  mDraw->addTexture(_texGradient);
327  mat(mDraw);
328  }
329 
330  tempP.resize(_amount);
331  tempV.resize(_amount);
332  tempST.resize(_amount);
333 
335  tempInitV.resize(_amount);
336  if (_doRotation)
337  tempR.resize(_amount);
338  if (_doRotation && _doRotRange)
339  tempAngulareVelo.resize(_amount);
340  if (_doFlipBookTexture)
341  tempTexNum.resize(_amount);
342  if (_doShape)
343  tempInitP.resize(_amount);
344 
345  // Normal generation
346  for (SLint i = 0; i < _amount; i++)
347  {
348  if (_doShape && _shapeType == ST_Sphere) // Position in or on sphere
349  {
350  if (!_doShapeSurface) // In volume
351  tempP[i] = getPointInSphere(_shapeRadius,
352  SLVec3f(distribution(generator),
353  distribution(generator),
354  distribution(generator)));
355  else // On surface
356  tempP[i] = getPointOnSphere(_shapeRadius,
357  SLVec3f(distribution(generator),
358  distribution(generator),
359  distribution(generator)));
360  }
361  else if (_doShape && _shapeType == ST_Box) // Position in or on box
362  if (!_doShapeSurface)
363  tempP[i] = getPointInBox(_shapeScale);
364  else
365  tempP[i] = getPointOnBox(_shapeScale);
366  else if (_doShape && _shapeType == ST_Cone) // Position in or on cone
367  if (!_doShapeSurface)
368  tempP[i] = getPointInCone();
369  else
370  tempP[i] = getPointOnCone();
371  else if (_doShape && _shapeType == ST_Pyramid) // Position in or on pyramid
372  if (!_doShapeSurface)
373  tempP[i] = getPointInPyramid();
374  else
375  tempP[i] = getPointOnPyramid();
376  else // Position is not a volume, spawn from start point (particle emitter position)
377  tempP[i] = SLVec3f(0, 0, 0);
378 
379  if (!_doDirectionSpeed) // Use normal velocity
380  {
381  if (_velocityType == 0) // Random value
382  {
383  tempV[i].x = Utils::random(_velocityRndMin.x, _velocityRndMax.x); // Random value for x velocity
384  tempV[i].y = Utils::random(_velocityRndMin.y, _velocityRndMax.y); // Random value for y velocity
385  tempV[i].z = Utils::random(_velocityRndMin.z, _velocityRndMax.z); // Random value for z velocity
386  }
387  else if (_velocityType == 1) // Constant
388  {
389  tempV[i].x = _velocityConst.x; // Constant value for x velocity
390  tempV[i].y = _velocityConst.y; // Constant value for y velocity
391  tempV[i].z = _velocityConst.z; // Constant value for z velocity
392  }
393  }
394  else // DO direction and speed
395  {
396  SLVec3f tempDirection;
397  if (_doShapeOverride) // Direction for shape
398  {
399  if (_doShape && _shapeType == ST_Sphere)
400  tempDirection = getDirectionSphere(tempP[i]);
401  else if (_doShape && _shapeType == ST_Box)
402  tempDirection = getDirectionBox(tempP[i]);
403  else if (_doShape && _shapeType == ST_Cone)
404  tempDirection = getDirectionCone(tempP[i]);
405  else if (_doShape && _shapeType == ST_Pyramid)
406  tempDirection = getDirectionPyramid(tempP[i]);
407  }
408  else // Normal direction
409  tempDirection = _direction;
410 
411  if (_doSpeedRange) // Apply speed
412  tempV[i] = tempDirection * Utils::random(_speedRange.x, _speedRange.y);
413  else
414  tempV[i] = tempDirection * _speed;
415  }
416 
417  // When the first particle dies the last one begin to live
418  tempST[i] = GlobalTimer::timeS() + ((float)i * (_timeToLive / (float)_amount)); // Time to start
419 
420  if (_doAcceleration || _doGravity) // Acceleration
421  tempInitV[i] = tempV[i];
422  if (_doRotation) // Rotation (constant angular velocity)
423  tempR[i] = Utils::random(0.0f * DEG2RAD, 360.0f * DEG2RAD); // Start rotation of the particle
424  if (_doRotation && _doRotRange) // Random angular velocity for each particle
425  tempAngulareVelo[i] = Utils::random(_angularVelocityRange.x * DEG2RAD,
426  _angularVelocityRange.y * DEG2RAD); // Start rotation of the particle
427  if (_doFlipBookTexture) // Flipbook texture
428  tempTexNum[i] = Utils::random(0,
430  if (_doShape) // Shape feature
431  tempInitP[i] = tempP[i];
432  }
433 
434  // Need to have two VAO for transform feedback swapping
435  // Configure first VAO
436  _vao1.deleteGL();
440 
444  &tempInitV);
445  if (_doRotation)
447  AT_rotation,
448  &tempR);
449  if (_doRotation && _doRotRange)
452  &tempAngulareVelo);
453  if (_doFlipBookTexture)
455  AT_texNum,
456  &tempTexNum);
457  if (_doShape)
460  &tempInitP);
461  _vao1.generateTF((SLuint)tempP.size());
462 
463  // Configure second VAO
464  _vao2.deleteGL();
468 
472  &tempInitV);
473  if (_doRotation)
475  AT_rotation,
476  &tempR);
477  if (_doRotation && _doRotRange)
480  &tempAngulareVelo);
481  if (_doFlipBookTexture)
483  AT_texNum,
484  &tempTexNum);
485  if (_doShape)
488  &tempInitP);
489  _vao2.generateTF((SLuint)tempP.size());
490 
492  {
493  P.clear();
494  I32.clear();
495 
496  // Generate for billboard (for drawing instanced without geometry shader)
497  P.push_back(SLVec3f(-1, -1, 0));
498  P.push_back(SLVec3f(1, -1, 0));
499  P.push_back(SLVec3f(1, 1, 0));
500  P.push_back(SLVec3f(-1, 1, 0));
501 
502  I32.push_back(0);
503  I32.push_back(1);
504  I32.push_back(2);
505  I32.push_back(2);
506  I32.push_back(3);
507  I32.push_back(0);
508 
513  _instanceVao1.generate((SLuint)P.size());
514 
519  _instanceVao2.generate((SLuint)P.size());
520  }
521 
522  _isGenerated = true;
523 }
524 //-----------------------------------------------------------------------------
525 /*!
526 Generate Bernstein Polynomial with 4 controls points for alpha over life.
527 ContP contains 2 and 3 controls points
528 StatEnd contains 1 and 4 controls points
529 */
531 {
532  float* ContP = _bezierControlPointAlpha;
533  float* StaEnd = _bezierStartEndPointAlpha;
534  // For Y bezier curve
535  // T^3
536  _bernsteinPYAlpha.x = -StaEnd[1] + ContP[1] * 3 - ContP[3] * 3 + StaEnd[3];
537  // T^2
538  _bernsteinPYAlpha.y = StaEnd[1] * 3 - ContP[1] * 6 + ContP[3] * 3;
539  // T
540  _bernsteinPYAlpha.z = -StaEnd[1] * 3 + ContP[1] * 3;
541  // 1
542  _bernsteinPYAlpha.w = StaEnd[1];
543 }
544 //-----------------------------------------------------------------------------
545 /*!
546 Generate Bernstein Polynomial with 4 controls points for size over life.
547 ContP contains 2 and 3 controls points
548 StatEnd contains 1 and 4 controls points
549 */
551 {
552  // For Y bezier curve
553  // T^3
554  float* ContP = _bezierControlPointSize;
555  float* StaEnd = _bezierStartEndPointSize;
556  _bernsteinPYSize.x = -StaEnd[1] + ContP[1] * 3 - ContP[3] * 3 + StaEnd[3];
557  // T^2
558  _bernsteinPYSize.y = StaEnd[1] * 3 - ContP[1] * 6 + ContP[3] * 3;
559  // T
560  _bernsteinPYSize.z = -StaEnd[1] * 3 + ContP[1] * 3;
561  // 1
562  _bernsteinPYSize.w = StaEnd[1];
563 }
564 //-----------------------------------------------------------------------------
565 /*! Function called inside SLNode cull3DRec(..) which flags the particle system
566  to be not visible in the view frustum. This is needed to correct later the
567  start time of the PS when it reappears again.
568 */
570 {
572  {
573  _isVisibleInFrustum = false;
575  }
576 }
577 //-----------------------------------------------------------------------------
578 /*!
579 Function called by the user to pause or resume the particle system. This will
580 freeze the particle system there won't be any updating, only the drawing
581 */
583 {
584  if (!_isPaused)
585  {
586  _isPaused = true;
588  }
589  else
590  _isPaused = false;
591 }
592 //-----------------------------------------------------------------------------
593 /*! Draw function override from SLMesh. In this function I start by generate
594  * the particle and programs if they are not, then I check if the particle
595  * have been culled by the frustum culling or if they have been resumed by the
596  * user. After I update the particle in the update pass, then and finally I
597  * draw them.
598  @todo The assignment of TF buffer to a rendering buffer causes most probably
599  a warning on Emscripten-WebGL
600  */
602 {
603  ////////////////////////////////////////
604  // Init particles vector and init VAO //
605  ////////////////////////////////////////
606 
607  if (!_isGenerated)
608  generate();
609 
610  ///////////////////////
611  // Generate programs //
612  ///////////////////////
613 
614  if (!_mat->program() || !_mat->programTF())
616 
617  ///////////////////////////////////////////////////
618  // Calculate time and paused and frustum culling //
619  ///////////////////////////////////////////////////
620 
621  float difTime = 0.0f;
622  float deltaTime = GlobalTimer::timeS() - _startUpdateTimeS; // Actual delta time
623 
624  // Calculate time difference for frustum culling and paused
625  // If particle system was not visible, and was resumed when it was not visible
627  {
628  _isVisibleInFrustum = true;
629 
630  // Paused was set before not visible (will take _lastTimeBeforePauseS),
631  // if set after (will take _notVisibleTimeS)
633 
634  // maybe add later average delta time
635  // (because maybe bug when fast not visible long time, visible, not visible, visible
636  // Last delta time, because when culled draw is not called therefore
637  // the actual delta time will be too big
638  deltaTime = _deltaTimeUpdateS;
639 
640  // No more culling, the difference time has been applied, no further need
641  _notVisibleTimeS = 0.0f;
642 
643  // No more paused, the difference time has been applied, no further need
644  _lastTimeBeforePauseS = 0.0f;
645  }
646 
647  // If particle system was not visible, this one is called just once when the
648  // particle is draw again (Do nothing if paused, because update call is not done)
649  else if (!_isVisibleInFrustum)
650  {
651  _isVisibleInFrustum = true;
652 
653  // Use time since the particle system was not visible
654  difTime = GlobalTimer::timeS() - _notVisibleTimeS;
655 
656  // maybe add later average delta time (because maybe bug when
657  // fast not visible long time, visible, not visible, visible
658  // Last delta time, because when culled draw is not called
659  // therefore the actual delta time will be too big
660  deltaTime = _deltaTimeUpdateS;
661 
662  // If was paused when not visible. Need to take _notVisibleTimeS because
663  // it's since this value that the particle system is not drew.
665  // Get the value of since the particle system is not drew
667 
668  // No more culling, the difference time has been applied, no further need
669  _notVisibleTimeS = 0.0f;
670  }
671 
672  // If particle system was resumed
673  else if (!_isPaused && _lastTimeBeforePauseS != 0.0f)
674  {
675  // Use time since the particle system was paused
677 
678  // No more paused, the difference time has been applied, no further need
679  _lastTimeBeforePauseS = 0.0f;
680 
681  // Take default delta time, because when just paused no need to
682  // take last delta time, the draw call continue to be called
683  }
684 
685  // Calculate the elapsed time for the updating, need to change to
686  // use a real profiler (can't measure time like this on the GPU)
688 
689  // MS above, S below
692 
693  if (!_isPaused) // The updating is paused, therefore no need to send uniforms
694  {
695  ///////////
696  // UPDATING
697  ///////////
698 
699  // Now use the updating program
700  SLGLProgram* spTF = _mat->programTF();
701  spTF->useProgram();
702 
703  //////////////////////////
704  // Apply Uniform Variables
705  //////////////////////////
706 
707  // Time difference, between when the particle system was culled or paused or both
708  spTF->uniform1f("u_difTime", difTime);
709 
710  // Time between each draw call, take delta time from last draw called after frustum culling
711  spTF->uniform1f("u_deltaTime", deltaTime);
712 
713  // Time since process start
714  spTF->uniform1f("u_time", _startUpdateTimeS);
715 
716  if (_doAcceleration)
717  {
718  if (_doAccDiffDir)
719  spTF->uniform3f("u_acceleration",
722  _acceleration.z);
723  else
724  spTF->uniform1f("u_accConst",
726  }
727 
728  if (_doGravity)
729  spTF->uniform3f("u_gravity",
730  _gravity.x,
731  _gravity.y,
732  _gravity.z);
733 
734  spTF->uniform1f("u_tTL", _timeToLive);
735 
736  emitterPos(node->translationWS());
737 
738  // Worldspace
739  if (_doWorldSpace)
740  spTF->uniform3f("u_pGPosition",
741  _emitterPos.x,
742  _emitterPos.y,
743  _emitterPos.z);
744  else
745  spTF->uniform3f("u_pGPosition",
746  0.0f,
747  0.0f,
748  0.0f);
749 
750  // Flipbook
751  if (_doFlipBookTexture)
752  {
753  spTF->uniform1i("u_col", _flipbookColumns);
754  spTF->uniform1i("u_row", _flipbookRows);
756 
757  if (_flipboookLastUpdate > (1.0f / (float)_flipbookFPS))
758  {
759  // Last time FB was updated is bigger than the time needed for each update
760  spTF->uniform1i("u_condFB", 1);
761  _flipboookLastUpdate = 0.0f;
762  }
763  else
764  spTF->uniform1i("u_condFB", 0);
765  }
766 
767  // Rotation
768  if (_doRotation && !_doRotRange)
769  spTF->uniform1f("u_angularVelo",
771 
772  /////////////////////////
773  // Draw call to update //
774  /////////////////////////
775 
776  if (_drawBuf == 0)
777  {
780  _vao1.endTF();
781 
782  // @todo The assignment of TF buffer to a rendering buffer causes most probably a warning on Emscripten-WebGL
784  }
785  else
786  {
789  _vao2.endTF();
790 
791  // @todo The assignment of TF buffer to a rendering buffer causes most probably a warning on Emscripten-WebGL
793  }
795  }
796 
797  /////////////
798  // DRAWING //
799  /////////////
800 
801  // Give uniform for drawing and find for linking vao vbo
802  SLGLProgram* spD = _mat->program();
803  spD->useProgram();
804 
805  SLGLState* stateGL = SLGLState::instance();
806 
807  // Start calculation of the elapsed time for the drawing, need to change
808  // to use a real profiler (can't measure time like this on the GPU)
810 
811  // Billboard type
812  // World space
813  if (_doWorldSpace)
814  {
816  {
817  // Just view matrix because world space is enabled
818  SLMat4f vMat = stateGL->viewMatrix;
819 
820  vMat.m(0, 1.0f);
821  vMat.m(1, 0.0f);
822  vMat.m(2, 0.0f);
823 
824  vMat.m(8, 0.0f);
825  vMat.m(9, 0.0f);
826  vMat.m(10, 1.0f);
827 
828  spD->uniformMatrix4fv("u_vYawPMatrix",
829  1,
830  (SLfloat*)&vMat);
831  }
832  else
833  {
834  // Just view matrix because world space is enabled
835  SLMat4f vMat = stateGL->viewMatrix;
836  std::cout << "vMat" << std::endl;
837  vMat.m(0, 1.0f);
838  vMat.m(1, 0.0f);
839  vMat.m(2, 0.0f);
840 
841  vMat.m(3, 1.0f);
842  vMat.m(4, 0.0f);
843  vMat.m(5, 0.0f);
844 
845  vMat.m(6, 0.0f);
846  vMat.m(7, 0.0f);
847  vMat.m(8, 1.0f);
848 
849  spD->uniformMatrix4fv("u_vOmvMatrix",
850  1,
851  (SLfloat*)&vMat);
852  }
853  }
854  else
855  {
856  // Build Model-View Matrix
857  SLMat4f mvMat = stateGL->viewMatrix * stateGL->modelMatrix;
858 
860  {
861  mvMat.m(0, 1.0f);
862  mvMat.m(1, 0.0f);
863  mvMat.m(2, 0.0f);
864 
865  mvMat.m(8, 0.0f);
866  mvMat.m(9, 0.0f);
867  mvMat.m(10, 1.0f);
868 
869  spD->uniformMatrix4fv("u_vYawPMatrix",
870  1,
871  (SLfloat*)&mvMat);
872  }
873  else
874  {
875  spD->uniformMatrix4fv("u_vOmvMatrix",
876  1,
877  (SLfloat*)&mvMat);
878  }
879  }
880 
881  // Alpha over life Bézier curve
883  {
884  spD->uniform4f("u_al_bernstein",
889  }
890 
891  // Size over life Bézier curve
892  if (_doSizeOverLTCurve)
893  {
894  spD->uniform4f("u_si_bernstein",
899  }
900 
901  // Color over life by gradient color editor
902  if (_doColorOverLT)
903  {
904  spD->uniform1fv("u_colorArr",
905  _texGradient->length() * 3,
906  (float*)&_texGradient->allColors()[0]);
907  /*
908  spD->uniform1fv("u_colorArr",
909  256 * 3,
910  _colorArr);
911  */
912  }
913  else
914  {
915  spD->uniform4f("u_color",
916  _color.x,
917  _color.y,
918  _color.z,
919  _color.w);
920  }
921 
922  // Flipbook
923  if (_doFlipBookTexture)
924  {
925  spD->uniform1i("u_col", _flipbookColumns);
926  spD->uniform1i("u_row", _flipbookRows);
927  }
928 
929  if (_isPaused) // Take time when pause was enable
930  spD->uniform1f("u_time", _lastTimeBeforePauseS);
931  else
932  spD->uniform1f("u_time", GlobalTimer::timeS());
933 
934  spD->uniform1f("u_tTL", _timeToLive);
935  spD->uniform1f("u_scale", _scale);
936  spD->uniform1f("u_radiusW", _radiusW);
937  spD->uniform1f("u_radiusH", _radiusH);
938  spD->uniform1f("u_oneOverGamma", 1.0f);
939 
940  // Check wireframe
941  if (sv->drawBits()->get(SL_DB_MESHWIRED) ||
942  node->drawBits()->get(SL_DB_MESHWIRED))
943  spD->uniform1i("u_doWireFrame", 1);
944  else
945  spD->uniform1i("u_doWireFrame", 0);
946 
948  stateGL->blendFunc(GL_SRC_ALPHA, GL_ONE);
949 
950  ///////////////////////////
952  SLMesh::draw(sv, node, 2 * _amount); // 2 triangles per particle
953  else
954  SLMesh::draw(sv, node);
955  ///////////////////////////
956 
958  stateGL->blendFunc(GL_SRC_ALPHA,
959  GL_ONE_MINUS_SRC_ALPHA);
960 
961  // End calculation of the elapsed time for the drawing
963 
964  // Swap buffer
965  _drawBuf = 1 - _drawBuf;
966 }
967 //-----------------------------------------------------------------------------
968 /*!
969 Change the current use texture, this will switch between the normal texture and
970 the flipbook texture (and vice versa)
971 */
973 {
974  if (_doFlipBookTexture)
975  {
978  }
979  else
980  {
983  }
984 }
985 //-----------------------------------------------------------------------------
986 /*! SLParticleSystem::buildAABB builds the passed axis-aligned bounding box in
987  OS and updates the min & max points in WS with the passed WM of the node.
988  Take into account features like acceleration, gravity, shape, velocity.
989  SLMesh::buildAABB builds the passed axis-aligned bounding box in OS and updates
990  the min& max points in WS with the passed WM of the node.
991  Todo: Can ben enhance furthermore the acceleration doesn't work well for the moment.
992  The negative value for the acceleration are not take into account and also
993  acceleration which goes against the velocity. To adapt the acceleration to
994  exactly the same as the gravity not enough time to do it. Need to adapt more
995  accurately when direction speed is negative (for shape override example with Cone)
996 */
997 void SLParticleSystem::buildAABB(SLAABBox& aabb, const SLMat4f& wmNode)
998 {
999  // Radius of particle
1000  float rW = _radiusW * _scale;
1001  float rH = _radiusH * _scale;
1002 
1003  // Speed for direction if used
1004  float tempSpeed = _doSpeedRange ? max(_speedRange.x, _speedRange.y) : _speed;
1005 
1006  // Empty point
1007  minP = SLVec3f();
1008  maxP = SLVec3f();
1009 
1010  // Empty velocity
1011  SLVec3f minV = SLVec3f();
1012  SLVec3f maxV = SLVec3f();
1013 
1014  // Shape
1015  if (_doShape)
1016  {
1017  if (_shapeType == ST_Sphere)
1018  {
1019  float radius = cbrt(_shapeRadius);
1020  minP = SLVec3f(-radius, -radius, -radius);
1021  maxP = SLVec3f(radius, radius, radius);
1022  // Override direction
1024  {
1025  minV += SLVec3f(-radius, -radius, -radius) * tempSpeed;
1026  maxV += SLVec3f(radius, radius, radius) * tempSpeed;
1027  }
1028  }
1029  else if (_shapeType == ST_Box)
1030  {
1032  maxP = _shapeScale;
1034  {
1035  minV += SLVec3f(-_shapeScale.x, -_shapeScale.y, -_shapeScale.z) * tempSpeed;
1036  maxV += _shapeScale * tempSpeed;
1037  }
1038  }
1039  else if (_shapeType == ST_Cone)
1040  {
1041  float radius = _shapeRadius + tan(_shapeAngle * DEG2RAD) * _shapeHeight;
1042  minP = SLVec3f(-radius, -0.0, -radius);
1043  if (!_doShapeSpawnBase) // Spawn inside volume
1044  maxP = SLVec3f(radius, _shapeHeight, radius);
1045  else // Spawn base volume
1046  maxP = SLVec3f(radius, 0.0f, radius);
1048  {
1049  SLVec3f temp = getDirectionCone(SLVec3f(-radius, -0.0, -radius)) * tempSpeed;
1050  temp.y = 0.0;
1051  minV += temp;
1052  maxV += getDirectionCone(SLVec3f(radius, _shapeHeight, radius)) * tempSpeed;
1053  }
1054  }
1055  else if (_shapeType == ST_Pyramid)
1056  {
1057  float radius = _shapeWidth + tan(_shapeAngle * DEG2RAD) * _shapeHeight;
1058  minP = SLVec3f(-radius, -0.0, -radius);
1059  if (!_doShapeSpawnBase) // Spawn inside volume
1060  maxP = SLVec3f(radius, _shapeHeight, radius);
1061  else // Spawn base volume
1062  maxP = SLVec3f(radius, 0.0f, radius);
1063 
1065  {
1066  SLVec3f temp = getDirectionPyramid(SLVec3f(-radius, -0.0, -radius)) * tempSpeed;
1067  temp.y = 0.0;
1068  minV += temp;
1069  maxV += getDirectionPyramid(SLVec3f(radius, _shapeHeight, radius)) * tempSpeed;
1070  }
1071  }
1072  }
1073 
1074  if (_doAcceleration || _doGravity) // If acceleration or gravity is enabled
1075  {
1076  if (!_doDirectionSpeed) // If direction is not enable
1077  {
1078  if (_velocityType == 0)
1079  {
1080  SLVec3f minVTemp = SLVec3f(min(_velocityRndMax.x, _velocityRndMin.x),
1082  min(_velocityRndMax.z, _velocityRndMin.z)); // Apply velocity distance after time
1083  SLVec3f maxVTemp = SLVec3f(max(_velocityRndMax.x, _velocityRndMin.x),
1085  max(_velocityRndMax.z, _velocityRndMin.z)); // Apply velocity distance after time
1086 
1087  if (minVTemp.x > 0 && maxVTemp.x > 0) minVTemp.x = 0.0;
1088  if (minVTemp.y > 0 && maxVTemp.y > 0) minVTemp.y = 0.0;
1089  if (minVTemp.z > 0 && maxVTemp.z > 0) minVTemp.z = 0.0;
1090 
1091  if (minVTemp.x < 0 && maxVTemp.x < 0) maxVTemp.x = 0.0;
1092  if (minVTemp.y < 0 && maxVTemp.y < 0) maxVTemp.y = 0.0;
1093  if (minVTemp.z < 0 && maxVTemp.z < 0) maxVTemp.z = 0.0;
1094 
1095  minV += minVTemp;
1096  maxV += maxVTemp;
1097  }
1098  else // Constant acceleration
1099  {
1100  minV = SLVec3f(_velocityConst.x, 0.0, 0.0);
1101  maxV = SLVec3f(0.0, _velocityConst.y, _velocityConst.z);
1102  }
1103  }
1104  // Direction and speed, but no shape override, because I want a constant direction in one way I don't want the direction to be overridden
1105  else if (_doDirectionSpeed && !_doShapeOverride)
1106  {
1107  if (_doSpeedRange)
1108  tempSpeed = max(_speedRange.x, _speedRange.y);
1109  else
1110  tempSpeed = _speed;
1111 
1112  minV = SLVec3f(_direction.x, 0.0, 0.0) * tempSpeed;
1113  maxV = SLVec3f(0.0, _direction.y, _direction.z) * tempSpeed;
1114  if (_direction.x > 0.0)
1115  {
1116  maxV.x = minV.x;
1117  minV.x = 0.0;
1118  }
1119  if (_direction.y < 0.0)
1120  {
1121  minV.y = maxV.y;
1122  maxV.y = 0.0;
1123  }
1124  if (_direction.z < 0.0)
1125  {
1126  minV.z = maxV.z;
1127  maxV.z = 0.0;
1128  }
1129  }
1130 
1131  // Apply time to velocity
1132  minP += minV * _timeToLive;
1133  maxP += maxV * _timeToLive;
1134 
1135  // GRAVITY
1136  if (_doGravity)
1137  {
1138  float timeForXGrav = 0.0f;
1139  float timeForYGrav = 0.0f;
1140  float timeForZGrav = 0.0f;
1141  // Time to have a velocity of 0
1142  if (_gravity.x != 0.0f) timeForXGrav = maxV.x / _gravity.x;
1143  if (_gravity.y != 0.0f) timeForYGrav = maxV.y / _gravity.y;
1144  if (_gravity.z != 0.0f) timeForZGrav = maxV.z / _gravity.z;
1145 
1146  if (timeForXGrav < 0.0f) // If the gravity go against the velocity
1147  maxP.x -= maxV.x * (_timeToLive + timeForXGrav); // I remove the position with the velocity that it will not do because it go against the velocity (becareful! here timeForXGrav is negative)
1148  else if (timeForXGrav > 0.0f) // If the gravity go with the velocity
1149  maxP.x += 0.5f * _gravity.x * (_timeToLive * _timeToLive);
1150  if (timeForYGrav < 0.0f) // If the gravity go against the velocity
1151  maxP.y -= maxV.y * (_timeToLive + timeForYGrav);
1152  else if (timeForYGrav > 0.0f) // If the gravity go with the velocity
1153  maxP.y += 0.5f * _gravity.y * (_timeToLive * _timeToLive);
1154  if (timeForZGrav < 0.0f) // If the gravity go against the velocity
1155  maxP.z -= maxV.z * (_timeToLive + timeForZGrav);
1156  else if (timeForZGrav > 0.0f) // If the gravity go with the velocity
1157  maxP.z += 0.5f * _gravity.z * (_timeToLive * _timeToLive);
1158 
1159  // Time remaining after the gravity has nullified the velocity for the particle to die (for each axes)
1160  float xTimeRemaining = _timeToLive - abs(timeForXGrav);
1161  float yTimeRemaining = _timeToLive - abs(timeForYGrav);
1162  float zTimeRemaining = _timeToLive - abs(timeForZGrav);
1163 
1164  if (timeForXGrav < 0.0f) // If the gravity go against the velocity
1165  minP.x += 0.5f * _gravity.x * (xTimeRemaining * xTimeRemaining); // We move down pour min point (becareful! here gravity is negative)
1166  if (timeForYGrav < 0.0f)
1167  minP.y += 0.5f * _gravity.y * (yTimeRemaining * yTimeRemaining);
1168  if (timeForZGrav < 0.0f)
1169  minP.z += 0.5f * _gravity.z * (zTimeRemaining * zTimeRemaining);
1170  }
1171 
1172  // ACCELERATION (Need to rework to work like gravity)
1173  if (_doAcceleration && _doAccDiffDir) // Need to be rework ( for negative value)
1174  {
1175  maxP += 0.5f * _acceleration * (_timeToLive * _timeToLive); // Apply acceleration after time
1176  }
1177  else if (_doAcceleration && !_doAccDiffDir) // Need to be rework
1178  {
1179  // minP += 0.5f * _accelerationConst * (_timeToLive * _timeToLive); //Apply constant acceleration
1180  maxP += 0.5f * _accelerationConst * maxV * (_timeToLive * _timeToLive); // Apply constant acceleration //Not good
1181  }
1182  }
1183  else // If acceleration and gravity is not enable
1184  {
1185  if (!_doDirectionSpeed)
1186  {
1187  if (_velocityType == 0)
1188  {
1189  SLVec3f minVTemp = SLVec3f(min(_velocityRndMax.x, _velocityRndMin.x), min(_velocityRndMax.y, _velocityRndMin.y), min(_velocityRndMax.z, _velocityRndMin.z)); // Apply velocity distance after time
1190  SLVec3f maxVTemp = SLVec3f(max(_velocityRndMax.x, _velocityRndMin.x), max(_velocityRndMax.y, _velocityRndMin.y), max(_velocityRndMax.z, _velocityRndMin.z)); // Apply velocity distance after time
1191 
1192  if (minVTemp.x > 0 && maxVTemp.x > 0) minVTemp.x = 0.0;
1193  if (minVTemp.y > 0 && maxVTemp.y > 0) minVTemp.y = 0.0;
1194  if (minVTemp.z > 0 && maxVTemp.z > 0) minVTemp.z = 0.0;
1195 
1196  if (minVTemp.x < 0 && maxVTemp.x < 0) maxVTemp.x = 0.0;
1197  if (minVTemp.y < 0 && maxVTemp.y < 0) maxVTemp.y = 0.0;
1198  if (minVTemp.z < 0 && maxVTemp.z < 0) maxVTemp.z = 0.0;
1199 
1200  minV += minVTemp;
1201  maxV += maxVTemp;
1202  }
1203  else
1204  {
1205  minV += SLVec3f(_velocityConst.x, 0.0, _velocityConst.z); // Apply velocity distance after time
1206  maxV += SLVec3f(0.0, _velocityConst.y, 0.0); // Apply velocity distance after time
1207  }
1208  }
1209  else if (_doDirectionSpeed && !_doShapeOverride)
1210  {
1211  tempSpeed = 0.0f;
1212  if (_doSpeedRange)
1213  tempSpeed = Utils::random(_speedRange.x, _speedRange.y);
1214  else
1215  tempSpeed = _speed;
1216 
1217  minV += SLVec3f(_direction.x, 0.0, 0.0) * tempSpeed;
1218  maxV += SLVec3f(0.0, _direction.y, _direction.z) * tempSpeed;
1219 
1220  if (_direction.x > 0.0)
1221  {
1222  maxV.x = minV.x;
1223  minV.x = 0.0;
1224  }
1225  if (_direction.y < 0.0)
1226  {
1227  minV.y = maxV.y;
1228  maxV.y = 0.0;
1229  }
1230  if (_direction.z < 0.0)
1231  {
1232  minV.z = maxV.z;
1233  maxV.z = 0.0;
1234  }
1235  }
1236  // Apply time to velocity
1237  minP += minV * _timeToLive;
1238  maxP += maxV * _timeToLive;
1239  }
1240 
1241  // Add size particle
1242  minP.x += minP.x < maxP.x ? -rW : rW; // Add size of particle
1243  minP.y += minP.y < maxP.y ? -rH : rH; // Add size of particle if we don't have size over life
1244  minP.z += minP.z < maxP.z ? -rW : rW; // Add size of particle
1245 
1246  maxP.x += maxP.x > minP.x ? rW : -rW; // Add size of particle
1247  maxP.y += maxP.y > minP.y ? rH : -rH; // Add size of particle
1248  maxP.z += maxP.z > minP.z ? rW : -rW; // Add size of particle
1249 
1250  // Apply world matrix
1251  aabb.fromOStoWS(minP, maxP, wmNode);
1252 }
1253 //-----------------------------------------------------------------------------
float SLfloat
Definition: SL.h:173
unsigned int SLuint
Definition: SL.h:171
vector< SLfloat > SLVfloat
Definition: SL.h:200
#define SL_EXIT_MSG(message)
Definition: SL.h:240
vector< SLuint > SLVuint
Definition: SL.h:197
string SLstring
Definition: SL.h:158
int SLint
Definition: SL.h:170
#define SL_DB_MESHWIRED
Draw polygons as wired mesh.
Definition: SLDrawBits.h:22
@ ST_Sphere
Definition: SLEnums.h:280
@ ST_Pyramid
Definition: SLEnums.h:283
@ ST_Box
Definition: SLEnums.h:281
@ ST_Cone
Definition: SLEnums.h:282
@ BT_Vertical
Definition: SLEnums.h:273
@ AT_instancePosition
Vertex instance position for instanced particle drawing.
Definition: SLGLEnums.h:85
@ AT_angularVelo
Vertex angular velocity for rotation float.
Definition: SLGLEnums.h:82
@ AT_texNum
Vertex texture number int.
Definition: SLGLEnums.h:83
@ AT_custom0
Custom vertex attribute 0.
Definition: SLGLEnums.h:67
@ AT_position
Vertex position as a 2, 3 or 4 component vectors.
Definition: SLGLEnums.h:58
@ AT_rotation
Vertex rotation float.
Definition: SLGLEnums.h:81
@ AT_startTime
Vertex start time float.
Definition: SLGLEnums.h:79
@ AT_initialPosition
Vertex initial position 3 component vectors.
Definition: SLGLEnums.h:84
@ AT_velocity
Vertex velocity 3 component vectors.
Definition: SLGLEnums.h:78
@ AT_initialVelocity
Vertex initial velocity 3 component vectors.
Definition: SLGLEnums.h:80
@ PT_points
Definition: SLGLEnums.h:31
@ PT_triangles
Definition: SLGLEnums.h:35
@ TT_diffuse
Definition: SLGLTexture.h:78
@ CLUT_WYR
white to black
Definition: SLTexColorLUT.h:28
vector< SLVec3f > SLVVec3f
Definition: SLVec3.h:325
SLVec3< SLfloat > SLVec3f
Definition: SLVec3.h:318
static float timeS()
Definition: GlobalTimer.cpp:20
static float timeMS()
Definition: GlobalTimer.cpp:25
Defines an axis aligned bounding box.
Definition: SLAABBox.h:34
void fromOStoWS(const SLVec3f &minOS, const SLVec3f &maxOS, const SLMat4f &wm)
Recalculate min and max after transformation in world coords.
Definition: SLAABBox.cpp:46
Toplevel holder of the assets meshes, materials, textures and shaders.
SLbool get(SLuint bit)
Returns the specified bit.
Definition: SLDrawBits.h:69
Encapsulation of an OpenGL shader program object.
Definition: SLGLProgram.h:56
SLint uniformMatrix4fv(const SLchar *name, SLsizei count, const SLfloat *value, GLboolean transpose=false) const
Passes a 4x4 float matrix values py pointer to the uniform variable "name".
SLint uniform4f(const SLchar *name, SLfloat v0, SLfloat v1, SLfloat v2, SLfloat v3) const
Passes the float values v0,v1,v2 & v3 to the uniform variable "name".
SLint uniform1f(const SLchar *name, SLfloat v0) const
Passes the float value v0 to the uniform variable "name".
SLint uniform1fv(const SLchar *name, SLsizei count, const SLfloat *value) const
Passes 1 float value py pointer to the uniform variable "name".
SLint uniform3f(const SLchar *name, SLfloat v0, SLfloat v1, SLfloat v2) const
Passes the float values v0, v1 & v2 to the uniform variable "name".
void useProgram()
SLint uniform1i(const SLchar *name, SLint v0) const
Passes the int values v0 to the uniform variable "name".
Singleton class holding all OpenGL states.
Definition: SLGLState.h:71
SLMat4f modelMatrix
Init all states.
Definition: SLGLState.h:89
static SLGLState * instance()
Public static instance getter for singleton pattern.
Definition: SLGLState.h:74
SLMat4f viewMatrix
matrix for the active cameras view transform
Definition: SLGLState.h:91
void blendFunc(SLenum blendFuncSFactor, SLenum blendFuncDFactor)
Sets new blend function source and destination factors.
Definition: SLGLState.cpp:250
SLbool glHasGeometryShaders() const
Definition: SLGLState.h:139
Texture object for OpenGL texturing.
Definition: SLGLTexture.h:110
void beginTF(SLuint tfoID)
Begin transform feedback.
void setInstanceVBO(SLGLVertexBuffer *vbo, SLuint divisor=0)
Attach a VBO that has been created outside of this VAO.
void endTF()
End transform feedback.
SLuint tfoID() const
Returns the TFO id.
void setAttrib(SLGLAttributeType type, SLint elementSize, SLint location, void *dataPointer, SLGLBufferType dataType=BT_float)
Adds a vertex attribute with data pointer and an element size.
void generateTF(SLuint numVertices, SLGLBufferUsage usage=BU_static, SLbool outputInterleaved=true, SLuint divisor=0)
Generates the VA & VB & TF objects.
void drawArrayAs(SLGLPrimitiveType primitiveType, SLint firstVertex=0, SLsizei countVertices=0)
Draws the VAO as an array with a primitive type.
void setIndices(SLuint numIndicesElements, SLGLBufferType indexDataType, void *indexDataElements, SLuint numIndicesEdges=0, void *indexDataEdges=nullptr)
Adds the index array for indexed element drawing.
SLGLVertexBuffer * vbo()
void generate(SLuint numVertices, SLGLBufferUsage usage=BU_static, SLbool outputInterleaved=true, SLuint divisor=0)
Generates the VA & VB objects for a NO. of vertices.
void deleteGL()
Deletes all vertex array & vertex buffer objects.
void m(int i, T val)
Definition: SLMat4.h:93
Defines a standard CG material with textures and a shader program.
Definition: SLMaterial.h:56
void programTF(SLGLProgram *sp)
Definition: SLMaterial.h:206
void removeTextureType(SLTextureType tt)
Definition: SLMaterial.h:159
void generateProgramPS(bool drawInstanced=false)
Definition: SLMaterial.cpp:391
void addTexture(SLGLTexture *texture)
Adds the passed texture to the equivalent texture type vector.
Definition: SLMaterial.cpp:348
void program(SLGLProgram *sp)
Definition: SLMaterial.h:205
An SLMesh object is a triangulated mesh, drawn with one draw call.
Definition: SLMesh.h:134
SLVec3f maxP
max. vertex in OS
Definition: SLMesh.h:221
SLVuint I32
Vector of vertex indices 32 bit.
Definition: SLMesh.h:215
virtual void draw(SLSceneView *sv, SLNode *node, SLuint intances=0)
Definition: SLMesh.cpp:389
virtual void deleteDataGpu()
Definition: SLMesh.cpp:128
SLGLPrimitiveType _primitive
Primitive type (default triangles)
Definition: SLMesh.h:231
SLVec3f minP
min. vertex in OS
Definition: SLMesh.h:220
SLGLVertexArray _vao
Main OpenGL Vertex Array Object for drawing.
Definition: SLMesh.h:234
SLVVec3f P
Vector for vertex positions layout (location = 0)
Definition: SLMesh.h:203
SLMaterial * mat() const
Definition: SLMesh.h:177
SLMaterial * _mat
Pointer to the inside material.
Definition: SLMesh.h:232
SLNode represents a node in a hierarchical scene graph.
Definition: SLNode.h:147
SLVec3f translationWS() const
Definition: SLNode.h:531
SLDrawBits * drawBits()
Definition: SLNode.h:299
const SLstring & name() const
Definition: SLObject.h:38
SLbool _isPaused
Boolean to stop updating.
SLfloat _shapeAngle
Angle of cone and pyramid shapes.
SLbool _doWorldSpace
Boolean for world space position.
SLint _velocityType
Velocity type.
SLbool _doAcceleration
Boolean for acceleration.
SLVec2f _speedRange
Speed random between two value.
void generate()
Function which will generate the particles and attributes them to the VAO.
SLGLVertexArray _vao2
SLVec3f getDirectionCone(SLVec3f position)
Function which return a direction following the cone shape.
void buildAABB(SLAABBox &aabb, const SLMat4f &wmNode)
SLVec3f _emitterPos
Position of the particle emitter.
SLGLTexture * _texFlipbook
Flipbook texture with e.g. multiple flames at subsequent frames.
int _flipbookFPS
Number of update of flipbook by second.
SLbool _isGenerated
Boolean to generate particle system and load it on the GPU.
AvgFloat _drawTime
Averaged time for drawing in MS.
SLfloat _lastTimeBeforePauseS
Time since the particle system is paused.
SLGLTexture * texFlipbook()
SLfloat _notVisibleTimeS
Time since start when node not visible in S.
SLbool _doShapeSurface
Boolean for shape surface (particle will be spawned on surface)
SLVec2f _angularVelocityRange
Rotation rate range (change in angular rotation divide by change in time)
SLfloat _timeToLive
Time to live of a particle.
SLbool _doSpeedRange
Boolean for speed range.
SLbool _doInstancedDrawing
Boolean for instanced rendering.
SLVec3f getDirectionBox(SLVec3f position)
Function which return the direction towards the exterior of a box.
SLbool _doGravity
Boolean for gravity.
SLfloat _scale
Scale of a particle (Scale the radius)
SLVec3f getPointInSphere(float radius, SLVec3f randomX)
Function which return a position in a sphere.
SLint _amount
Amount of a particle.
SLGLVertexArray _instanceVao2
float _bezierStartEndPointSize[4]
Floats for bezier curve end start points (Start: 01 ; End: 23)
SLfloat _deltaTimeUpdateS
Delta time in between two frames S.
SLVec3f getPointOnCone()
Function which return a position on the cone define in the particle system.
SLTexColorLUT * texGradient()
SLVec3f emitterPos() const
SLfloat _radiusW
width radius of a particle
SLVec4f _bernsteinPYAlpha
Vector for bezier curve (default linear function)
SLbool _doRotation
Boolean for rotation.
SLBillboardType _billboardType
Billboard type (BT_Camera, BT_Vertical, BT_Horizontal.
SLbool _doDirectionSpeed
Boolean for direction and speed (override velocity)
SLfloat _angularVelocityConst
Rotation rate const (change in angular rotation divide by change in time)
SLGLVertexArray _instanceVao1
SLbool _doRotRange
Boolean for rotation range (random value between range)
SLbool _isVisibleInFrustum
Boolean to set time since node not visible.
SLfloat _shapeRadius
Radius of sphere and cone shape.
int _drawBuf
Boolean to switch buffer.
SLfloat _accelerationConst
Acceleration constant (same direction as the velocity)
float _bezierStartEndPointAlpha[4]
Floats for bezier curve end start points (Start: 01 ; End: 23)
SLVec3f getDirectionSphere(SLVec3f position)
Function which return the direction towards the exterior of a sphere.
SLVec3f getPointOnSphere(float radius, SLVec3f randomX)
Function which return a position on a sphere.
SLbool _doColorOverLT
Boolean for color over life time.
SLfloat _shapeWidth
Width of pyramid shape.
SLVec3f getPointInCone()
Function which return a position in the cone define in the particle system.
float _bezierControlPointSize[4]
Floats for bezier curve control points (P1: 01 ; P2: 23)
SLfloat _startUpdateTimeS
Time since start for updating in S.
SLfloat _startUpdateTimeMS
Time since start for updating in MS.
SLbool _doFlipBookTexture
Boolean for flipbook texture.
SLVec4f _bernsteinPYSize
Vector for bezier curve (default linear function)
SLVec3f _direction
Direction of particle.
SLCol4f _color
Color for particle.
SLbool _doShapeOverride
Boolean for override direction for shape direction.
SLVec3f _velocityConst
Velocity constant (go in xyz direction)
AvgFloat _updateTime
Averaged time for updating in MS.
SLParticleSystem(SLAssetManager *assetMgr, const SLint amount, const SLVec3f &velocityRandomStart, const SLVec3f &velocityRandomEnd, const SLfloat &timeToLive, SLGLTexture *texC, const SLstring &name="Particle System", SLGLTexture *texFlipbook=nullptr, SLTexColorLUT *texGradient=nullptr, const bool doInstancedDrawing=false)
SLParticleSystem ctor with some initial values. The number of particles.
SLGLTexture * _texParticle
Main texture of PS (non flipbook)
SLbool _doAccDiffDir
Boolean for acceleration (different direction)
SLVec3f getPointInPyramid()
Function which returns a position in the pyramid that define the PS.
SLint _flipbookColumns
Number of flipbook sub-textures by column.
SLbool _doAlphaOverLTCurve
Boolean for alpha over life time curve.
SLfloat _startDrawTimeMS
Time since start of draw in MS.
float _flipboookLastUpdate
Last time flipbook was updated.
SLint _flipbookRows
Number of flipbook sub-textures by row.
SLbool _doShape
Boolean for shape feature.
SLbool _doBlendBrightness
Boolean for glow/brightness on pixel with many particle.
float _bezierControlPointAlpha[4]
Floats for bezier curve control points (P1: 01 ; P2: 23)
SLfloat _shapeHeight
Height of cone and pyramid shapes.
SLVec3f _gravity
Vector for gravity (2nd. acceleration vector)
SLfloat _radiusH
height radius of a particle
SLbool _doShapeSpawnBase
Boolean for spawn at base of shape (for cone and pyramid)
SLVec3f _shapeScale
Scale of box shape.
SLVec3f getDirectionPyramid(SLVec3f position)
Function which return a direction following the pyramid shape.
SLVec3f getPointOnBox(SLVec3f boxScale)
Function which return a position on a box.
SLGLVertexArray _vao1
SLVec3f _velocityRndMax
Max. random velocity.
SLTexColorLUT * _texGradient
Color gradient texture.
void draw(SLSceneView *sv, SLNode *node, SLuint instances=1)
SLbool _doSizeOverLTCurve
Boolean for size over life time curve.
SLVec3f _acceleration
Vector for acceleration (different direction as the velocity)
SLbool doInstancedDrawing()
SLVec3f getPointInBox(SLVec3f boxScale)
Function which return a position in a box.
SLShapeType _shapeType
Shape type (ST_)
SLAssetManager * _assetManager
pointer to the asset manager (the owner) if available
SLbool _doColor
Boolean for color.
SLVec3f getPointOnPyramid()
Function which return a position on the pyramid that defines the PS.
SLfloat _speed
Speed of particle.
SLVec3f _velocityRndMin
Min. random velocity.
SceneView class represents a dynamic real time 3D view onto the scene.
Definition: SLSceneView.h:69
SLDrawBits * drawBits()
Definition: SLSceneView.h:198
SLTexColorLUT defines a lookup table as an 1D texture of (256) RGBA values.
Definition: SLTexColorLUT.h:70
SLVCol3f allColors()
Returns all alpha values of the transfer function as a float vector.
SLuint length()
Definition: SLTexColorLUT.h:93
T y
Definition: SLVec2.h:30
T x
Definition: SLVec2.h:30
T y
Definition: SLVec3.h:43
SLVec3 normalized() const
Definition: SLVec3.h:127
T x
Definition: SLVec3.h:43
SLVec3 & normalize()
Definition: SLVec3.h:124
T z
Definition: SLVec3.h:43
T w
Definition: SLVec4.h:32
T z
Definition: SLVec4.h:32
T y
Definition: SLVec4.h:32
T x
Definition: SLVec4.h:32
void init(int numValues, T initValue)
Initializes the average value array to a given value.
Definition: Averaged.h:41
void set(T value)
Sets the current value in the value array and builds the average.
Definition: Averaged.h:53
static const float DEG2RAD
Definition: Utils.h:239
T abs(T a)
Definition: Utils.h:249
static const float PI
Definition: Utils.h:237
float random(float min, float max)
Returns a uniform distributed random float number between min and max.
Definition: Utils.h:265