ParticleSystem.h 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. // David Eberly, Geometric Tools, Redmond WA 98052
  2. // Copyright (c) 1998-2020
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // https://www.boost.org/LICENSE_1_0.txt
  5. // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
  6. // Version: 4.0.2019.08.13
  7. #pragma once
  8. #include <Mathematics/Vector.h>
  9. #include <vector>
  10. namespace WwiseGTE
  11. {
  12. template <int N, typename Real>
  13. class ParticleSystem
  14. {
  15. public:
  16. // Construction and destruction. If a particle is to be immovable,
  17. // set its mass to std::numeric_limits<Real>::max().
  18. virtual ~ParticleSystem() = default;
  19. ParticleSystem(int numParticles, Real step)
  20. :
  21. mNumParticles(numParticles),
  22. mMass(numParticles),
  23. mInvMass(numParticles),
  24. mPosition(numParticles),
  25. mVelocity(numParticles),
  26. mStep(step),
  27. mHalfStep(step / (Real)2),
  28. mSixthStep(step / (Real)6),
  29. mPTmp(numParticles),
  30. mVTmp(numParticles),
  31. mPAllTmp(numParticles),
  32. mVAllTmp(numParticles)
  33. {
  34. std::fill(mMass.begin(), mMass.end(), (Real)0);
  35. std::fill(mInvMass.begin(), mInvMass.end(), (Real)0);
  36. std::fill(mPosition.begin(), mPosition.end(), Vector<N, Real>::Zero());
  37. std::fill(mVelocity.begin(), mVelocity.end(), Vector<N, Real>::Zero());
  38. }
  39. // Member access.
  40. inline int GetNumParticles() const
  41. {
  42. return mNumParticles;
  43. }
  44. void SetMass(int i, Real mass)
  45. {
  46. if ((Real)0 < mass && mass < std::numeric_limits<Real>::max())
  47. {
  48. mMass[i] = mass;
  49. mInvMass[i] = (Real)1 / mass;
  50. }
  51. else
  52. {
  53. mMass[i] = std::numeric_limits<Real>::max();
  54. mInvMass[i] = (Real)0;
  55. }
  56. }
  57. inline void SetPosition(int i, Vector<N, Real> const& position)
  58. {
  59. mPosition[i] = position;
  60. }
  61. inline void SetVelocity(int i, Vector<N, Real> const& velocity)
  62. {
  63. mVelocity[i] = velocity;
  64. }
  65. void SetStep(Real step)
  66. {
  67. mStep = step;
  68. mHalfStep = mStep / (Real)2;
  69. mSixthStep = mStep / (Real)6;
  70. }
  71. inline Real const& GetMass(int i) const
  72. {
  73. return mMass[i];
  74. }
  75. inline Vector<N, Real> const& GetPosition(int i) const
  76. {
  77. return mPosition[i];
  78. }
  79. inline Vector<N, Real> const& GetVelocity(int i) const
  80. {
  81. return mVelocity[i];
  82. }
  83. inline Real GetStep() const
  84. {
  85. return mStep;
  86. }
  87. // Update the particle positions based on current time and particle
  88. // state. The Acceleration(...) function is called in this update
  89. // for each particle. This function is virtual so that derived
  90. // classes can perform pre-update and/or post-update semantics.
  91. virtual void Update(Real time)
  92. {
  93. // Runge-Kutta fourth-order solver.
  94. Real halfTime = time + mHalfStep;
  95. Real fullTime = time + mStep;
  96. // Compute the first step.
  97. int i;
  98. for (i = 0; i < mNumParticles; ++i)
  99. {
  100. if (mInvMass[i] > (Real)0)
  101. {
  102. mPAllTmp[i].d1 = mVelocity[i];
  103. mVAllTmp[i].d1 = Acceleration(i, time, mPosition, mVelocity);
  104. }
  105. }
  106. for (i = 0; i < mNumParticles; ++i)
  107. {
  108. if (mInvMass[i] > (Real)0)
  109. {
  110. mPTmp[i] = mPosition[i] + mHalfStep * mPAllTmp[i].d1;
  111. mVTmp[i] = mVelocity[i] + mHalfStep * mVAllTmp[i].d1;
  112. }
  113. else
  114. {
  115. mPTmp[i] = mPosition[i];
  116. mVTmp[i].MakeZero();
  117. }
  118. }
  119. // Compute the second step.
  120. for (i = 0; i < mNumParticles; ++i)
  121. {
  122. if (mInvMass[i] > (Real)0)
  123. {
  124. mPAllTmp[i].d2 = mVTmp[i];
  125. mVAllTmp[i].d2 = Acceleration(i, halfTime, mPTmp, mVTmp);
  126. }
  127. }
  128. for (i = 0; i < mNumParticles; ++i)
  129. {
  130. if (mInvMass[i] > (Real)0)
  131. {
  132. mPTmp[i] = mPosition[i] + mHalfStep * mPAllTmp[i].d2;
  133. mVTmp[i] = mVelocity[i] + mHalfStep * mVAllTmp[i].d2;
  134. }
  135. else
  136. {
  137. mPTmp[i] = mPosition[i];
  138. mVTmp[i].MakeZero();
  139. }
  140. }
  141. // Compute the third step.
  142. for (i = 0; i < mNumParticles; ++i)
  143. {
  144. if (mInvMass[i] > (Real)0)
  145. {
  146. mPAllTmp[i].d3 = mVTmp[i];
  147. mVAllTmp[i].d3 = Acceleration(i, halfTime, mPTmp, mVTmp);
  148. }
  149. }
  150. for (i = 0; i < mNumParticles; ++i)
  151. {
  152. if (mInvMass[i] > (Real)0)
  153. {
  154. mPTmp[i] = mPosition[i] + mStep * mPAllTmp[i].d3;
  155. mVTmp[i] = mVelocity[i] + mStep * mVAllTmp[i].d3;
  156. }
  157. else
  158. {
  159. mPTmp[i] = mPosition[i];
  160. mVTmp[i].MakeZero();
  161. }
  162. }
  163. // Compute the fourth step.
  164. for (i = 0; i < mNumParticles; ++i)
  165. {
  166. if (mInvMass[i] > (Real)0)
  167. {
  168. mPAllTmp[i].d4 = mVTmp[i];
  169. mVAllTmp[i].d4 = Acceleration(i, fullTime, mPTmp, mVTmp);
  170. }
  171. }
  172. for (i = 0; i < mNumParticles; ++i)
  173. {
  174. if (mInvMass[i] > (Real)0)
  175. {
  176. mPosition[i] += mSixthStep * (mPAllTmp[i].d1 +
  177. (Real)2 * (mPAllTmp[i].d2 + mPAllTmp[i].d3) + mPAllTmp[i].d4);
  178. mVelocity[i] += mSixthStep * (mVAllTmp[i].d1 +
  179. (Real)2 * (mVAllTmp[i].d2 + mVAllTmp[i].d3) + mVAllTmp[i].d4);
  180. }
  181. }
  182. }
  183. protected:
  184. // Callback for acceleration (ODE solver uses x" = F/m) applied to
  185. // particle i. The positions and velocities are not necessarily
  186. // mPosition and mVelocity, because the ODE solver evaluates the
  187. // impulse function at intermediate positions.
  188. virtual Vector<N, Real> Acceleration(int i, Real time,
  189. std::vector<Vector<N, Real>> const& position,
  190. std::vector<Vector<N, Real>> const& velocity) = 0;
  191. int mNumParticles;
  192. std::vector<Real> mMass, mInvMass;
  193. std::vector<Vector<N, Real>> mPosition, mVelocity;
  194. Real mStep, mHalfStep, mSixthStep;
  195. // Temporary storage for the Runge-Kutta differential equation solver.
  196. struct Temporary
  197. {
  198. Vector<N, Real> d1, d2, d3, d4;
  199. };
  200. std::vector<Vector<N, Real>> mPTmp, mVTmp;
  201. std::vector<Temporary> mPAllTmp, mVAllTmp;
  202. };
  203. }