particle_system_sw.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. /*************************************************************************/
  2. /* particle_system_sw.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /*************************************************************************/
  30. #include "particle_system_sw.h"
  31. #include "sort.h"
  32. ParticleSystemSW::ParticleSystemSW() {
  33. amount = 8;
  34. emitting = true;
  35. for (int i = 0; i < VS::PARTICLE_VAR_MAX; i++) {
  36. particle_randomness[i] = 0.0;
  37. }
  38. particle_vars[VS::PARTICLE_LIFETIME] = 2.0; //
  39. particle_vars[VS::PARTICLE_SPREAD] = 0.2; //
  40. particle_vars[VS::PARTICLE_GRAVITY] = 9.8; //
  41. particle_vars[VS::PARTICLE_LINEAR_VELOCITY] = 0.2; //
  42. particle_vars[VS::PARTICLE_ANGULAR_VELOCITY] = 0.0; //
  43. particle_vars[VS::PARTICLE_LINEAR_ACCELERATION] = 0.0; //
  44. particle_vars[VS::PARTICLE_RADIAL_ACCELERATION] = 0.0; //
  45. particle_vars[VS::PARTICLE_TANGENTIAL_ACCELERATION] = 1.0; //
  46. particle_vars[VS::PARTICLE_DAMPING] = 0.0; //
  47. particle_vars[VS::PARTICLE_INITIAL_SIZE] = 1.0;
  48. particle_vars[VS::PARTICLE_FINAL_SIZE] = 0.8;
  49. particle_vars[VS::PARTICLE_HEIGHT] = 1;
  50. particle_vars[VS::PARTICLE_HEIGHT_SPEED_SCALE] = 1;
  51. height_from_velocity = false;
  52. local_coordinates = false;
  53. particle_vars[VS::PARTICLE_INITIAL_ANGLE] = 0.0; //
  54. gravity_normal = Vector3(0, -1.0, 0);
  55. //emission_half_extents=Vector3(0.1,0.1,0.1);
  56. emission_half_extents = Vector3(1, 1, 1);
  57. color_phase_count = 0;
  58. color_phases[0].pos = 0.0;
  59. color_phases[0].color = Color(1.0, 0.0, 0.0);
  60. visibility_aabb = AABB(Vector3(-64, -64, -64), Vector3(128, 128, 128));
  61. attractor_count = 0;
  62. }
  63. ParticleSystemSW::~ParticleSystemSW() {
  64. }
  65. #define DEFAULT_SEED 1234567
  66. _FORCE_INLINE_ static float _rand_from_seed(uint32_t *seed) {
  67. uint32_t k;
  68. uint32_t s = (*seed);
  69. if (s == 0)
  70. s = 0x12345987;
  71. k = s / 127773;
  72. s = 16807 * (s - k * 127773) - 2836 * k;
  73. if (s < 0)
  74. s += 2147483647;
  75. (*seed) = s;
  76. float v = ((float)((*seed) & 0xFFFFF)) / (float)0xFFFFF;
  77. v = v * 2.0 - 1.0;
  78. return v;
  79. }
  80. _FORCE_INLINE_ static uint32_t _irand_from_seed(uint32_t *seed) {
  81. uint32_t k;
  82. uint32_t s = (*seed);
  83. if (s == 0)
  84. s = 0x12345987;
  85. k = s / 127773;
  86. s = 16807 * (s - k * 127773) - 2836 * k;
  87. if (s < 0)
  88. s += 2147483647;
  89. (*seed) = s;
  90. return s;
  91. }
  92. void ParticleSystemProcessSW::process(const ParticleSystemSW *p_system, const Transform &p_transform, float p_time) {
  93. valid = false;
  94. if (p_system->amount <= 0) {
  95. ERR_EXPLAIN("Invalid amount of particles: " + itos(p_system->amount));
  96. ERR_FAIL_COND(p_system->amount <= 0);
  97. }
  98. if (p_system->attractor_count < 0 || p_system->attractor_count > VS::MAX_PARTICLE_ATTRACTORS) {
  99. ERR_EXPLAIN("Invalid amount of particle attractors.");
  100. ERR_FAIL_COND(p_system->attractor_count < 0 || p_system->attractor_count > VS::MAX_PARTICLE_ATTRACTORS);
  101. }
  102. float lifetime = p_system->particle_vars[VS::PARTICLE_LIFETIME];
  103. if (lifetime < CMP_EPSILON) {
  104. ERR_EXPLAIN("Particle system lifetime too small.");
  105. ERR_FAIL_COND(lifetime < CMP_EPSILON);
  106. }
  107. valid = true;
  108. int particle_count = MIN(p_system->amount, ParticleSystemSW::MAX_PARTICLES);
  109. ;
  110. int emission_point_count = p_system->emission_points.size();
  111. DVector<Vector3>::Read r;
  112. if (emission_point_count)
  113. r = p_system->emission_points.read();
  114. if (particle_count != particle_data.size()) {
  115. //clear the whole system if particle amount changed
  116. particle_data.clear();
  117. particle_data.resize(p_system->amount);
  118. particle_system_time = 0;
  119. }
  120. float next_time = particle_system_time + p_time;
  121. if (next_time > lifetime)
  122. next_time = Math::fmod(next_time, lifetime);
  123. ParticleData *pdata = &particle_data[0];
  124. Vector3 attractor_positions[VS::MAX_PARTICLE_ATTRACTORS];
  125. for (int i = 0; i < p_system->attractor_count; i++) {
  126. attractor_positions[i] = p_transform.xform(p_system->attractors[i].pos);
  127. }
  128. for (int i = 0; i < particle_count; i++) {
  129. ParticleData &p = pdata[i];
  130. float restart_time = (i * lifetime / p_system->amount);
  131. bool restart = false;
  132. if (next_time < particle_system_time) {
  133. if (restart_time > particle_system_time || restart_time < next_time)
  134. restart = true;
  135. } else if (restart_time > particle_system_time && restart_time < next_time) {
  136. restart = true;
  137. }
  138. if (restart) {
  139. if (p_system->emitting) {
  140. if (emission_point_count == 0) { //use AABB
  141. if (p_system->local_coordinates)
  142. p.pos = p_system->emission_half_extents * Vector3(_rand_from_seed(&rand_seed), _rand_from_seed(&rand_seed), _rand_from_seed(&rand_seed));
  143. else
  144. p.pos = p_transform.xform(p_system->emission_half_extents * Vector3(_rand_from_seed(&rand_seed), _rand_from_seed(&rand_seed), _rand_from_seed(&rand_seed)));
  145. } else {
  146. //use preset positions
  147. if (p_system->local_coordinates)
  148. p.pos = r[_irand_from_seed(&rand_seed) % emission_point_count];
  149. else
  150. p.pos = p_transform.xform(r[_irand_from_seed(&rand_seed) % emission_point_count]);
  151. }
  152. float angle1 = _rand_from_seed(&rand_seed) * p_system->particle_vars[VS::PARTICLE_SPREAD] * Math_PI;
  153. float angle2 = _rand_from_seed(&rand_seed) * 20.0 * Math_PI; // make it more random like
  154. Vector3 rot_xz = Vector3(Math::sin(angle1), 0.0, Math::cos(angle1));
  155. Vector3 rot = Vector3(Math::cos(angle2) * rot_xz.x, Math::sin(angle2) * rot_xz.x, rot_xz.z);
  156. p.vel = (rot * p_system->particle_vars[VS::PARTICLE_LINEAR_VELOCITY] + rot * p_system->particle_randomness[VS::PARTICLE_LINEAR_VELOCITY] * _rand_from_seed(&rand_seed));
  157. if (!p_system->local_coordinates)
  158. p.vel = p_transform.basis.xform(p.vel);
  159. p.vel += p_system->emission_base_velocity;
  160. p.rot = p_system->particle_vars[VS::PARTICLE_INITIAL_ANGLE] + p_system->particle_randomness[VS::PARTICLE_INITIAL_ANGLE] * _rand_from_seed(&rand_seed);
  161. p.active = true;
  162. for (int r = 0; r < PARTICLE_RANDOM_NUMBERS; r++)
  163. p.random[r] = _rand_from_seed(&rand_seed);
  164. } else {
  165. p.pos = Vector3();
  166. p.rot = 0;
  167. p.vel = Vector3();
  168. p.active = false;
  169. }
  170. } else {
  171. if (!p.active)
  172. continue;
  173. Vector3 force;
  174. //apply gravity
  175. force = p_system->gravity_normal * (p_system->particle_vars[VS::PARTICLE_GRAVITY] + (p_system->particle_randomness[VS::PARTICLE_GRAVITY] * p.random[0]));
  176. //apply linear acceleration
  177. force += p.vel.normalized() * (p_system->particle_vars[VS::PARTICLE_LINEAR_ACCELERATION] + p_system->particle_randomness[VS::PARTICLE_LINEAR_ACCELERATION] * p.random[1]);
  178. //apply radial acceleration
  179. Vector3 org;
  180. if (!p_system->local_coordinates)
  181. org = p_transform.origin;
  182. force += (p.pos - org).normalized() * (p_system->particle_vars[VS::PARTICLE_RADIAL_ACCELERATION] + p_system->particle_randomness[VS::PARTICLE_RADIAL_ACCELERATION] * p.random[2]);
  183. //apply tangential acceleration
  184. force += (p.pos - org).cross(p_system->gravity_normal).normalized() * (p_system->particle_vars[VS::PARTICLE_TANGENTIAL_ACCELERATION] + p_system->particle_randomness[VS::PARTICLE_TANGENTIAL_ACCELERATION] * p.random[3]);
  185. //apply attractor forces
  186. for (int a = 0; a < p_system->attractor_count; a++) {
  187. force += (p.pos - attractor_positions[a]).normalized() * p_system->attractors[a].force;
  188. }
  189. p.vel += force * p_time;
  190. if (p_system->particle_vars[VS::PARTICLE_DAMPING]) {
  191. float v = p.vel.length();
  192. float damp = p_system->particle_vars[VS::PARTICLE_DAMPING] + p_system->particle_vars[VS::PARTICLE_DAMPING] * p_system->particle_randomness[VS::PARTICLE_DAMPING];
  193. v -= damp * p_time;
  194. if (v < 0) {
  195. p.vel = Vector3();
  196. } else {
  197. p.vel = p.vel.normalized() * v;
  198. }
  199. }
  200. p.rot += (p_system->particle_vars[VS::PARTICLE_ANGULAR_VELOCITY] + p_system->particle_randomness[VS::PARTICLE_ANGULAR_VELOCITY] * p.random[4]) * p_time;
  201. p.pos += p.vel * p_time;
  202. }
  203. }
  204. particle_system_time = Math::fmod(particle_system_time + p_time, lifetime);
  205. }
  206. ParticleSystemProcessSW::ParticleSystemProcessSW() {
  207. particle_system_time = 0;
  208. rand_seed = 1234567;
  209. valid = false;
  210. }
  211. struct _ParticleSorterSW {
  212. _FORCE_INLINE_ bool operator()(const ParticleSystemDrawInfoSW::ParticleDrawInfo *p_a, const ParticleSystemDrawInfoSW::ParticleDrawInfo *p_b) const {
  213. return p_a->d > p_b->d; // draw from further away to closest
  214. }
  215. };
  216. void ParticleSystemDrawInfoSW::prepare(const ParticleSystemSW *p_system, const ParticleSystemProcessSW *p_process, const Transform &p_system_transform, const Transform &p_camera_transform) {
  217. ERR_FAIL_COND(p_process->particle_data.size() != p_system->amount);
  218. ERR_FAIL_COND(p_system->amount <= 0 || p_system->amount >= ParticleSystemSW::MAX_PARTICLES);
  219. const ParticleSystemProcessSW::ParticleData *pdata = &p_process->particle_data[0];
  220. float time_pos = p_process->particle_system_time / p_system->particle_vars[VS::PARTICLE_LIFETIME];
  221. ParticleSystemSW::ColorPhase cphase[VS::MAX_PARTICLE_COLOR_PHASES];
  222. float last = -1;
  223. int col_count = 0;
  224. for (int i = 0; i < p_system->color_phase_count; i++) {
  225. if (p_system->color_phases[i].pos <= last)
  226. break;
  227. cphase[i] = p_system->color_phases[i];
  228. col_count++;
  229. }
  230. Vector3 camera_z_axis = p_camera_transform.basis.get_axis(2);
  231. for (int i = 0; i < p_system->amount; i++) {
  232. ParticleDrawInfo &pdi = draw_info[i];
  233. pdi.data = &pdata[i];
  234. pdi.transform.origin = pdi.data->pos;
  235. if (p_system->local_coordinates)
  236. pdi.transform.origin = p_system_transform.xform(pdi.transform.origin);
  237. pdi.d = -camera_z_axis.dot(pdi.transform.origin);
  238. // adjust particle size, color and rotation
  239. float time = ((float)i / p_system->amount);
  240. if (time < time_pos)
  241. time = time_pos - time;
  242. else
  243. time = (1.0 - time) + time_pos;
  244. Vector3 up = p_camera_transform.basis.get_axis(1); // up determines the rotation
  245. float up_scale = 1.0;
  246. if (p_system->height_from_velocity) {
  247. Vector3 veld = pdi.data->vel;
  248. Vector3 cam_z = camera_z_axis.normalized();
  249. float vc = Math::abs(veld.normalized().dot(cam_z));
  250. if (vc < (1.0 - CMP_EPSILON)) {
  251. up = Plane(cam_z, 0).project(veld).normalized();
  252. float h = p_system->particle_vars[VS::PARTICLE_HEIGHT] + p_system->particle_randomness[VS::PARTICLE_HEIGHT] * pdi.data->random[7];
  253. float velh = veld.length();
  254. h += velh * (p_system->particle_vars[VS::PARTICLE_HEIGHT_SPEED_SCALE] + p_system->particle_randomness[VS::PARTICLE_HEIGHT_SPEED_SCALE] * pdi.data->random[7]);
  255. up_scale = Math::lerp(1.0, h, (1.0 - vc));
  256. }
  257. } else if (pdi.data->rot) {
  258. up.rotate(camera_z_axis, pdi.data->rot);
  259. }
  260. {
  261. // matrix
  262. Vector3 v_z = (p_camera_transform.origin - pdi.transform.origin).normalized();
  263. // Vector3 v_z = (p_camera_transform.origin-pdi.data->pos).normalized();
  264. Vector3 v_y = up;
  265. Vector3 v_x = v_y.cross(v_z);
  266. v_y = v_z.cross(v_x);
  267. v_x.normalize();
  268. v_y.normalize();
  269. float initial_scale, final_scale;
  270. initial_scale = p_system->particle_vars[VS::PARTICLE_INITIAL_SIZE] + p_system->particle_randomness[VS::PARTICLE_INITIAL_SIZE] * pdi.data->random[5];
  271. final_scale = p_system->particle_vars[VS::PARTICLE_FINAL_SIZE] + p_system->particle_randomness[VS::PARTICLE_FINAL_SIZE] * pdi.data->random[6];
  272. float scale = initial_scale + time * (final_scale - initial_scale);
  273. pdi.transform.basis.set_axis(0, v_x * scale);
  274. pdi.transform.basis.set_axis(1, v_y * scale * up_scale);
  275. pdi.transform.basis.set_axis(2, v_z * scale);
  276. }
  277. int cpos = 0;
  278. while (cpos < col_count) {
  279. if (cphase[cpos].pos > time)
  280. break;
  281. cpos++;
  282. }
  283. cpos--;
  284. if (cpos == -1)
  285. pdi.color = Color(1, 1, 1, 1);
  286. else {
  287. if (cpos == col_count - 1)
  288. pdi.color = cphase[cpos].color;
  289. else {
  290. float diff = (cphase[cpos + 1].pos - cphase[cpos].pos);
  291. if (diff > 0)
  292. pdi.color = cphase[cpos].color.linear_interpolate(cphase[cpos + 1].color, (time - cphase[cpos].pos) / diff);
  293. else
  294. pdi.color = cphase[cpos + 1].color;
  295. }
  296. }
  297. draw_info_order[i] = &pdi;
  298. }
  299. SortArray<ParticleDrawInfo *, _ParticleSorterSW> particle_sort;
  300. particle_sort.sort(&draw_info_order[0], p_system->amount);
  301. }