particle_system_sw.cpp 13 KB

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