particles.glsl 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. /* clang-format off */
  2. #[modes]
  3. mode_default =
  4. #[specializations]
  5. MODE_3D = false
  6. USERDATA1_USED = false
  7. USERDATA2_USED = false
  8. USERDATA3_USED = false
  9. USERDATA4_USED = false
  10. USERDATA5_USED = false
  11. USERDATA6_USED = false
  12. #[vertex]
  13. #define SDF_MAX_LENGTH 16384.0
  14. layout(std140) uniform GlobalShaderUniformData { //ubo:1
  15. vec4 global_shader_uniforms[MAX_GLOBAL_SHADER_UNIFORMS];
  16. };
  17. // This needs to be outside clang-format so the ubo comment is in the right place
  18. #ifdef MATERIAL_UNIFORMS_USED
  19. layout(std140) uniform MaterialUniforms{ //ubo:2
  20. #MATERIAL_UNIFORMS
  21. };
  22. #endif
  23. /* clang-format on */
  24. #define MAX_ATTRACTORS 32
  25. #define ATTRACTOR_TYPE_SPHERE uint(0)
  26. #define ATTRACTOR_TYPE_BOX uint(1)
  27. #define ATTRACTOR_TYPE_VECTOR_FIELD uint(2)
  28. struct Attractor {
  29. mat4 transform;
  30. vec4 extents; // Extents or radius. w-channel is padding.
  31. uint type;
  32. float strength;
  33. float attenuation;
  34. float directionality;
  35. };
  36. #define MAX_COLLIDERS 32
  37. #define COLLIDER_TYPE_SPHERE uint(0)
  38. #define COLLIDER_TYPE_BOX uint(1)
  39. #define COLLIDER_TYPE_SDF uint(2)
  40. #define COLLIDER_TYPE_HEIGHT_FIELD uint(3)
  41. #define COLLIDER_TYPE_2D_SDF uint(4)
  42. struct Collider {
  43. mat4 transform;
  44. vec4 extents; // Extents or radius. w-channel is padding.
  45. uint type;
  46. float scale;
  47. float pad0;
  48. float pad1;
  49. };
  50. layout(std140) uniform FrameData { //ubo:0
  51. bool emitting;
  52. uint cycle;
  53. float system_phase;
  54. float prev_system_phase;
  55. float explosiveness;
  56. float randomness;
  57. float time;
  58. float delta;
  59. float particle_size;
  60. float amount_ratio;
  61. float pad1;
  62. float pad2;
  63. uint random_seed;
  64. uint attractor_count;
  65. uint collider_count;
  66. uint frame;
  67. mat4 emission_transform;
  68. vec3 emitter_velocity;
  69. float interp_to_end;
  70. Attractor attractors[MAX_ATTRACTORS];
  71. Collider colliders[MAX_COLLIDERS];
  72. };
  73. #define PARTICLE_FLAG_ACTIVE uint(1)
  74. #define PARTICLE_FLAG_STARTED uint(2)
  75. #define PARTICLE_FLAG_TRAILED uint(4)
  76. #define PARTICLE_FRAME_MASK uint(0xFFFF)
  77. #define PARTICLE_FRAME_SHIFT uint(16)
  78. // ParticleData
  79. layout(location = 0) in highp vec4 color;
  80. layout(location = 1) in highp vec4 velocity_flags;
  81. layout(location = 2) in highp vec4 custom;
  82. layout(location = 3) in highp vec4 xform_1;
  83. layout(location = 4) in highp vec4 xform_2;
  84. #ifdef MODE_3D
  85. layout(location = 5) in highp vec4 xform_3;
  86. #endif
  87. #ifdef USERDATA1_USED
  88. layout(location = 6) in highp vec4 userdata1;
  89. #endif
  90. #ifdef USERDATA2_USED
  91. layout(location = 7) in highp vec4 userdata2;
  92. #endif
  93. #ifdef USERDATA3_USED
  94. layout(location = 8) in highp vec4 userdata3;
  95. #endif
  96. #ifdef USERDATA4_USED
  97. layout(location = 9) in highp vec4 userdata4;
  98. #endif
  99. #ifdef USERDATA5_USED
  100. layout(location = 10) in highp vec4 userdata5;
  101. #endif
  102. #ifdef USERDATA6_USED
  103. layout(location = 11) in highp vec4 userdata6;
  104. #endif
  105. out highp vec4 out_color; //tfb:
  106. out highp vec4 out_velocity_flags; //tfb:
  107. out highp vec4 out_custom; //tfb:
  108. out highp vec4 out_xform_1; //tfb:
  109. out highp vec4 out_xform_2; //tfb:
  110. #ifdef MODE_3D
  111. out highp vec4 out_xform_3; //tfb:MODE_3D
  112. #endif
  113. #ifdef USERDATA1_USED
  114. out highp vec4 out_userdata1; //tfb:USERDATA1_USED
  115. #endif
  116. #ifdef USERDATA2_USED
  117. out highp vec4 out_userdata2; //tfb:USERDATA2_USED
  118. #endif
  119. #ifdef USERDATA3_USED
  120. out highp vec4 out_userdata3; //tfb:USERDATA3_USED
  121. #endif
  122. #ifdef USERDATA4_USED
  123. out highp vec4 out_userdata4; //tfb:USERDATA4_USED
  124. #endif
  125. #ifdef USERDATA5_USED
  126. out highp vec4 out_userdata5; //tfb:USERDATA5_USED
  127. #endif
  128. #ifdef USERDATA6_USED
  129. out highp vec4 out_userdata6; //tfb:USERDATA6_USED
  130. #endif
  131. uniform sampler2D height_field_texture; //texunit:0
  132. uniform float lifetime;
  133. uniform bool clear;
  134. uniform uint total_particles;
  135. uniform bool use_fractional_delta;
  136. uint hash(uint x) {
  137. x = ((x >> uint(16)) ^ x) * uint(0x45d9f3b);
  138. x = ((x >> uint(16)) ^ x) * uint(0x45d9f3b);
  139. x = (x >> uint(16)) ^ x;
  140. return x;
  141. }
  142. vec3 safe_normalize(vec3 direction) {
  143. const float EPSILON = 0.001;
  144. if (length(direction) < EPSILON) {
  145. return vec3(0.0);
  146. }
  147. return normalize(direction);
  148. }
  149. // Needed whenever 2D sdf texture is read from as it is packed in RGBA8.
  150. float vec4_to_float(vec4 p_vec) {
  151. return dot(p_vec, vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0)) * 2.0 - 1.0;
  152. }
  153. #GLOBALS
  154. void main() {
  155. bool apply_forces = true;
  156. bool apply_velocity = true;
  157. float local_delta = delta;
  158. float mass = 1.0;
  159. bool restart = false;
  160. bool restart_position = false;
  161. bool restart_rotation_scale = false;
  162. bool restart_velocity = false;
  163. bool restart_color = false;
  164. bool restart_custom = false;
  165. mat4 xform = mat4(1.0);
  166. uint flags = 0u;
  167. if (clear) {
  168. out_color = vec4(1.0);
  169. out_custom = vec4(0.0);
  170. out_velocity_flags = vec4(0.0);
  171. } else {
  172. out_color = color;
  173. out_velocity_flags = velocity_flags;
  174. out_custom = custom;
  175. xform[0] = xform_1;
  176. xform[1] = xform_2;
  177. #ifdef MODE_3D
  178. xform[2] = xform_3;
  179. #endif
  180. xform = transpose(xform);
  181. flags = floatBitsToUint(velocity_flags.w);
  182. }
  183. //clear started flag if set
  184. flags &= ~PARTICLE_FLAG_STARTED;
  185. bool collided = false;
  186. vec3 collision_normal = vec3(0.0);
  187. float collision_depth = 0.0;
  188. vec3 attractor_force = vec3(0.0);
  189. #if !defined(DISABLE_VELOCITY)
  190. if (bool(flags & PARTICLE_FLAG_ACTIVE)) {
  191. xform[3].xyz += out_velocity_flags.xyz * local_delta;
  192. }
  193. #endif
  194. uint index = uint(gl_VertexID);
  195. if (emitting) {
  196. float restart_phase = float(index) / float(total_particles);
  197. if (randomness > 0.0) {
  198. uint seed = cycle;
  199. if (restart_phase >= system_phase) {
  200. seed -= uint(1);
  201. }
  202. seed *= uint(total_particles);
  203. seed += index;
  204. float random = float(hash(seed) % uint(65536)) / 65536.0;
  205. restart_phase += randomness * random * 1.0 / float(total_particles);
  206. }
  207. restart_phase *= (1.0 - explosiveness);
  208. if (system_phase > prev_system_phase) {
  209. // restart_phase >= prev_system_phase is used so particles emit in the first frame they are processed
  210. if (restart_phase >= prev_system_phase && restart_phase < system_phase) {
  211. restart = true;
  212. if (use_fractional_delta) {
  213. local_delta = (system_phase - restart_phase) * lifetime;
  214. }
  215. }
  216. } else if (delta > 0.0) {
  217. if (restart_phase >= prev_system_phase) {
  218. restart = true;
  219. if (use_fractional_delta) {
  220. local_delta = (1.0 - restart_phase + system_phase) * lifetime;
  221. }
  222. } else if (restart_phase < system_phase) {
  223. restart = true;
  224. if (use_fractional_delta) {
  225. local_delta = (system_phase - restart_phase) * lifetime;
  226. }
  227. }
  228. }
  229. if (restart) {
  230. flags = emitting ? (PARTICLE_FLAG_ACTIVE | PARTICLE_FLAG_STARTED | (cycle << PARTICLE_FRAME_SHIFT)) : 0u;
  231. restart_position = true;
  232. restart_rotation_scale = true;
  233. restart_velocity = true;
  234. restart_color = true;
  235. restart_custom = true;
  236. }
  237. }
  238. bool particle_active = bool(flags & PARTICLE_FLAG_ACTIVE);
  239. uint particle_number = (flags >> PARTICLE_FRAME_SHIFT) * uint(total_particles) + index;
  240. if (restart && particle_active) {
  241. #CODE : START
  242. }
  243. if (particle_active) {
  244. for (uint i = 0u; i < attractor_count; i++) {
  245. vec3 dir;
  246. float amount;
  247. vec3 rel_vec = xform[3].xyz - attractors[i].transform[3].xyz;
  248. vec3 local_pos = rel_vec * mat3(attractors[i].transform);
  249. if (attractors[i].type == ATTRACTOR_TYPE_SPHERE) {
  250. dir = safe_normalize(rel_vec);
  251. float d = length(local_pos) / attractors[i].extents.x;
  252. if (d > 1.0) {
  253. continue;
  254. }
  255. amount = max(0.0, 1.0 - d);
  256. } else if (attractors[i].type == ATTRACTOR_TYPE_BOX) {
  257. dir = safe_normalize(rel_vec);
  258. vec3 abs_pos = abs(local_pos / attractors[i].extents.xyz);
  259. float d = max(abs_pos.x, max(abs_pos.y, abs_pos.z));
  260. if (d > 1.0) {
  261. continue;
  262. }
  263. amount = max(0.0, 1.0 - d);
  264. } else if (attractors[i].type == ATTRACTOR_TYPE_VECTOR_FIELD) {
  265. }
  266. amount = pow(amount, attractors[i].attenuation);
  267. dir = safe_normalize(mix(dir, attractors[i].transform[2].xyz, attractors[i].directionality));
  268. attractor_force -= amount * dir * attractors[i].strength;
  269. }
  270. float particle_size = particle_size;
  271. #ifdef USE_COLLISION_SCALE
  272. particle_size *= dot(vec3(length(xform[0].xyz), length(xform[1].xyz), length(xform[2].xyz)), vec3(0.33333333333));
  273. #endif
  274. if (collider_count == 1u && colliders[0].type == COLLIDER_TYPE_2D_SDF) {
  275. //2D collision
  276. vec2 pos = xform[3].xy;
  277. vec4 to_sdf_x = colliders[0].transform[0];
  278. vec4 to_sdf_y = colliders[0].transform[1];
  279. vec2 sdf_pos = vec2(dot(vec4(pos, 0, 1), to_sdf_x), dot(vec4(pos, 0, 1), to_sdf_y));
  280. vec4 sdf_to_screen = vec4(colliders[0].extents.xyz, colliders[0].scale);
  281. vec2 uv_pos = sdf_pos * sdf_to_screen.xy + sdf_to_screen.zw;
  282. if (all(greaterThan(uv_pos, vec2(0.0))) && all(lessThan(uv_pos, vec2(1.0)))) {
  283. vec2 pos2 = pos + vec2(0, particle_size);
  284. vec2 sdf_pos2 = vec2(dot(vec4(pos2, 0, 1), to_sdf_x), dot(vec4(pos2, 0, 1), to_sdf_y));
  285. float sdf_particle_size = distance(sdf_pos, sdf_pos2);
  286. float d = vec4_to_float(texture(height_field_texture, uv_pos)) * SDF_MAX_LENGTH;
  287. d -= sdf_particle_size;
  288. if (d < 0.0) {
  289. const float EPSILON = 0.001;
  290. vec2 n = normalize(vec2(
  291. vec4_to_float(texture(height_field_texture, uv_pos + vec2(EPSILON, 0.0))) - vec4_to_float(texture(height_field_texture, uv_pos - vec2(EPSILON, 0.0))),
  292. vec4_to_float(texture(height_field_texture, uv_pos + vec2(0.0, EPSILON))) - vec4_to_float(texture(height_field_texture, uv_pos - vec2(0.0, EPSILON)))));
  293. collided = true;
  294. sdf_pos2 = sdf_pos + n * d;
  295. pos2 = vec2(dot(vec4(sdf_pos2, 0, 1), colliders[0].transform[2]), dot(vec4(sdf_pos2, 0, 1), colliders[0].transform[3]));
  296. n = pos - pos2;
  297. collision_normal = normalize(vec3(n, 0.0));
  298. collision_depth = length(n);
  299. }
  300. }
  301. } else {
  302. for (uint i = 0u; i < collider_count; i++) {
  303. vec3 normal;
  304. float depth;
  305. bool col = false;
  306. vec3 rel_vec = xform[3].xyz - colliders[i].transform[3].xyz;
  307. vec3 local_pos = rel_vec * mat3(colliders[i].transform);
  308. if (colliders[i].type == COLLIDER_TYPE_SPHERE) {
  309. float d = length(rel_vec) - (particle_size + colliders[i].extents.x);
  310. if (d < 0.0) {
  311. col = true;
  312. depth = -d;
  313. normal = normalize(rel_vec);
  314. }
  315. } else if (colliders[i].type == COLLIDER_TYPE_BOX) {
  316. vec3 abs_pos = abs(local_pos);
  317. vec3 sgn_pos = sign(local_pos);
  318. if (any(greaterThan(abs_pos, colliders[i].extents.xyz))) {
  319. //point outside box
  320. vec3 closest = min(abs_pos, colliders[i].extents.xyz);
  321. vec3 rel = abs_pos - closest;
  322. depth = length(rel) - particle_size;
  323. if (depth < 0.0) {
  324. col = true;
  325. normal = mat3(colliders[i].transform) * (normalize(rel) * sgn_pos);
  326. depth = -depth;
  327. }
  328. } else {
  329. //point inside box
  330. vec3 axis_len = colliders[i].extents.xyz - abs_pos;
  331. // there has to be a faster way to do this?
  332. if (all(lessThan(axis_len.xx, axis_len.yz))) {
  333. normal = vec3(1, 0, 0);
  334. } else if (all(lessThan(axis_len.yy, axis_len.xz))) {
  335. normal = vec3(0, 1, 0);
  336. } else {
  337. normal = vec3(0, 0, 1);
  338. }
  339. col = true;
  340. depth = dot(normal * axis_len, vec3(1)) + particle_size;
  341. normal = mat3(colliders[i].transform) * (normal * sgn_pos);
  342. }
  343. } else if (colliders[i].type == COLLIDER_TYPE_SDF) {
  344. } else if (colliders[i].type == COLLIDER_TYPE_HEIGHT_FIELD) {
  345. vec3 local_pos_bottom = local_pos;
  346. local_pos_bottom.y -= particle_size;
  347. if (any(greaterThan(abs(local_pos_bottom), colliders[i].extents.xyz))) {
  348. continue;
  349. }
  350. const float DELTA = 1.0 / 8192.0;
  351. vec3 uvw_pos = vec3(local_pos_bottom / colliders[i].extents.xyz) * 0.5 + 0.5;
  352. float y = 1.0 - texture(height_field_texture, uvw_pos.xz).r;
  353. if (y > uvw_pos.y) {
  354. //inside heightfield
  355. vec3 pos1 = (vec3(uvw_pos.x, y, uvw_pos.z) * 2.0 - 1.0) * colliders[i].extents.xyz;
  356. vec3 pos2 = (vec3(uvw_pos.x + DELTA, 1.0 - texture(height_field_texture, uvw_pos.xz + vec2(DELTA, 0)).r, uvw_pos.z) * 2.0 - 1.0) * colliders[i].extents.xyz;
  357. vec3 pos3 = (vec3(uvw_pos.x, 1.0 - texture(height_field_texture, uvw_pos.xz + vec2(0, DELTA)).r, uvw_pos.z + DELTA) * 2.0 - 1.0) * colliders[i].extents.xyz;
  358. normal = normalize(cross(pos1 - pos2, pos1 - pos3));
  359. float local_y = (vec3(local_pos / colliders[i].extents.xyz) * 0.5 + 0.5).y;
  360. col = true;
  361. depth = dot(normal, pos1) - dot(normal, local_pos_bottom);
  362. }
  363. }
  364. if (col) {
  365. if (!collided) {
  366. collided = true;
  367. collision_normal = normal;
  368. collision_depth = depth;
  369. } else {
  370. vec3 c = collision_normal * collision_depth;
  371. c += normal * max(0.0, depth - dot(normal, c));
  372. collision_normal = normalize(c);
  373. collision_depth = length(c);
  374. }
  375. }
  376. }
  377. }
  378. }
  379. if (particle_active) {
  380. #CODE : PROCESS
  381. }
  382. flags &= ~PARTICLE_FLAG_ACTIVE;
  383. if (particle_active) {
  384. flags |= PARTICLE_FLAG_ACTIVE;
  385. }
  386. xform = transpose(xform);
  387. out_xform_1 = xform[0];
  388. out_xform_2 = xform[1];
  389. #ifdef MODE_3D
  390. out_xform_3 = xform[2];
  391. #endif
  392. out_velocity_flags.w = uintBitsToFloat(flags);
  393. }
  394. /* clang-format off */
  395. #[fragment]
  396. void main() {
  397. }
  398. /* clang-format on */