particle_sparks_fountain_textured.shader 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. shader_type spatial;
  2. render_mode blend_add, depth_draw_opaque, cull_disabled, diffuse_burley, specular_schlick_ggx, unshaded;
  3. // based on https://www.vertexshaderart.com/art/TdqvseMQyoJ3ZrjrD // Garden Fireworks - @P_Malin
  4. // do not use my code, this is very bad, exist just for testing/my own learning, use linked original
  5. uniform float iTime = 0.;
  6. uniform sampler2D texture_p: hint_albedo;
  7. uniform vec4 colorx: hint_color;
  8. const float scale_g = 0.35;
  9. const float height_g = 9.;
  10. const float fRadius_g = 0.035;
  11. const float fShutterSpeed_g = 4.0 / 60.0;
  12. const float fAperture_g = 1.1;
  13. const float fFocalLength_g = 0.15;
  14. const float fExposure_g = 5.;
  15. const float fFloorHeight_const_g = 0.0;
  16. const float QUAD_VERTEX_COUNT = (4. * 3.);
  17. vec3 my_normalize3(vec3 v) {
  18. float len = length(v);
  19. vec3 ret = vec3(0.);
  20. if (len == 0.0) ret = vec3(1.0, 0.0, 0.0);
  21. else ret = v / len;
  22. return ret;
  23. }
  24. mat4 lookAt(vec3 from, vec3 to, vec3 tup) {
  25. vec3 forward = my_normalize3(from - to);
  26. if (length(forward.xz) <= 0.001) forward.x = 0.001;
  27. vec3 right = cross(normalize(tup), forward);
  28. right = my_normalize3(right);
  29. vec3 up = cross(forward, right);
  30. mat4 camToWorld = mat4(1.);
  31. camToWorld[0].xyz = right.xyz;
  32. camToWorld[1].xyz = up.xyz;
  33. camToWorld[2].xyz = forward.xyz;
  34. camToWorld[3].xyz = from.xyz;
  35. return camToWorld;
  36. }
  37. float rCross( in vec2 A, in vec2 B) {
  38. return A.x * B.y - A.y * B.x;
  39. }
  40. void GetQuadInfo( in float vertexIndex, out vec2 quadVertId, out float quadId) {
  41. float twoTriVertexIndex = mod(vertexIndex, 6.0);
  42. float triVertexIndex = mod(vertexIndex, 3.0);
  43. if (twoTriVertexIndex < 0.5) quadVertId = vec2(0.0, 0.0);
  44. else if (twoTriVertexIndex < 1.5) quadVertId = vec2(1.0, 0.0);
  45. else if (twoTriVertexIndex < 2.5) quadVertId = vec2(0.0, 1.0);
  46. else if (twoTriVertexIndex < 3.5) quadVertId = vec2(1.0, 0.0);
  47. else if (twoTriVertexIndex < 4.5) quadVertId = vec2(1.0, 1.0);
  48. else quadVertId = vec2(0.0, 1.0);
  49. quadId = floor(vertexIndex / 6.0);
  50. }
  51. // hash function from https://www.shadertoy.com/view/4djSRW
  52. float Hash(float p) {
  53. vec2 p2 = fract(vec2(p * 5.3983, p * 5.4427));
  54. p2 += dot(p2.yx, p2.xy + vec2(21.5351, 14.3137));
  55. return fract(p2.x * p2.y * 95.4337);
  56. }
  57. const vec3 MOD3 = vec3(.1031, .11369, .13787);
  58. const vec4 MOD4 = vec4(.1031, .11369, .13787, .09987);
  59. vec3 Hash3(float p) {
  60. vec3 p3 = fract(vec3(p) * MOD3);
  61. p3 += dot(p3, p3.yzx + 19.19);
  62. return fract(vec3((p3.x + p3.y) * p3.z, (p3.x + p3.z) * p3.y, (p3.y + p3.z) * p3.x));
  63. }
  64. void GetHexagonVertex( in float fAperture, in float fFocalLength, in float fExposure, in float fVertexIndex, in vec2 vOrigin, in vec2 vDir, in float r, in vec3 col0, in vec3 col1,
  65. out vec2 vPos, out vec3 vColor) {
  66. float fAngleOffset = fAperture * 0.5;
  67. float fVertexIndexB = fVertexIndex;
  68. float fQuadId;
  69. vec2 vQuadVertId;
  70. GetQuadInfo(fVertexIndexB, vQuadVertId, fQuadId);
  71. float fEdgeAngle = atan(vDir.x, vDir.y) - fAngleOffset;
  72. fEdgeAngle = floor(fEdgeAngle * 6.0 / radians(360.0) - 1.0) * radians(360.0) / 6.0;
  73. if (fQuadId > 0.0) {
  74. fEdgeAngle += radians(180.0);
  75. }
  76. float fRadius = vQuadVertId.y * r;
  77. vec2 vPost = vec2(sin(fEdgeAngle + fAngleOffset), cos(fEdgeAngle + fAngleOffset)) * fRadius;
  78. vPost += vDir * vQuadVertId.x;
  79. vPos.xy = vOrigin + vPost;
  80. vColor.rgb = mix(col0, col1, vQuadVertId.y);
  81. }
  82. vec3 GetViewPos( in vec3 vPosition, in mat3 mRotation, vec3 vWorldPos) {
  83. return (vWorldPos - vPosition) * mRotation;
  84. }
  85. vec2 GetScreenPos( in float fAperture, in float fFocalLength, vec3 vViewPos) {
  86. return vViewPos.xy * fFocalLength * 5.0 / vViewPos.z;
  87. }
  88. vec2 SolveQuadratic(float a, float b, float c) {
  89. float d = sqrt(b * b - 4.0 * a * c);
  90. vec2 dV = vec2(d, -d);
  91. return (-b + dV) / (2.0 * a);
  92. }
  93. vec3 BounceParticle(vec3 vOrigin, vec3 vInitialVel, float fGravity, float fFloorHeight, float fTime) {
  94. vec3 u = vInitialVel;
  95. vec3 a = vec3(0.0, fGravity, 0.0);
  96. vec3 vPos = vOrigin;
  97. float t = fTime;
  98. for (int iBounce = 0; iBounce < 3; iBounce++) {
  99. // When will we hit the ground?
  100. vec2 q = SolveQuadratic(0.5 * a.y, u.y, -fFloorHeight + vPos.y);
  101. float tInt = max(q.x, q.y);
  102. tInt -= 0.0001;
  103. if (t < tInt) {
  104. vPos += u * t + 0.5 * a * t * t;
  105. break;
  106. } else {
  107. // Calculate velocity at intersect time
  108. vec3 v = u + a * tInt;
  109. // step to intersect time
  110. vPos += u * tInt + 0.5 * a * tInt * tInt;
  111. u = v;
  112. // bounce
  113. u.y = -u.y * 0.3;
  114. u.xz *= 0.6;
  115. t -= tInt;
  116. }
  117. }
  118. return -vPos * scale_g;
  119. }
  120. void Fountain( in float fLightIndex, in vec3 vPos, float fTime, vec3 vCol, float fSpread, out vec3 vWorldPos,
  121. out float fRadius,
  122. out vec3 vColor) {
  123. float fParticleLifetime = 1.5;
  124. float h = Hash(fLightIndex + 12.0);
  125. vec3 h3 = Hash3(fLightIndex + 13.0);
  126. float fAngle = fLightIndex;
  127. vec3 vInitialVel = (normalize(h3 * 2.0 - 1.0) * max(fSpread, 1.5) + vec3(0.0, height_g - fSpread * 1.3, 0.0)) * (0.4 + h * 0.4);
  128. vec3 vOrigin = vPos + vec3(0.0, fFloorHeight_const_g + 0.1, 0.0) + vInitialVel * 0.1;
  129. vWorldPos = BounceParticle(vOrigin, vInitialVel, -9.81, fFloorHeight_const_g, fTime);
  130. fRadius = fRadius_g;
  131. vColor = vCol;
  132. vColor *= clamp(1.0 - fTime + fParticleLifetime - 1.0, 0.0, 1.0);
  133. }
  134. void GetSequenceInfo(float fSetIndex, float fTime, out float fSequenceSet,
  135. out float fSequenceIndex,
  136. out float fSequenceStartTime,
  137. out float fSequenceSeed,
  138. out vec3 vSequenceHash,
  139. out vec3 vCol,
  140. out vec3 vPos,
  141. out vec3 vTarget) {
  142. float fSequenceSetCount = 1.0;
  143. fSequenceSet = mod(fSetIndex, fSequenceSetCount);
  144. float sh = Hash(fSequenceSet);
  145. float fSequenceSetLength = 10.0 + sh * 5.0;
  146. fSequenceIndex = floor(fTime / fSequenceSetLength);
  147. fSequenceStartTime = (fSequenceIndex * fSequenceSetLength);
  148. fSequenceSeed = fSequenceIndex + fSequenceSet * 12.3;
  149. vSequenceHash = Hash3(fSequenceSeed);
  150. vCol = vec3(1.);
  151. vPos = vec3(0.0);
  152. vPos.xz = vSequenceHash.yz * 6.0 - 3.0;
  153. vTarget = vPos;
  154. //vTarget.y = 1.5;
  155. vTarget = vec3(0.);
  156. vPos = vec3(0.);
  157. }
  158. void GetFireworkSparkInfo( in float fLightIndex, float fTime, float fDeltaTime, vec3 h3, out vec3 vWorldPos,
  159. out float fRadius,
  160. out vec3 vColor) {
  161. float fParticleLifetime = 1.5;
  162. float fParticleSpawnTime = (floor((fTime / fParticleLifetime) + h3.x) - h3.x) * fParticleLifetime;
  163. float fParticleEndTime = fParticleSpawnTime + fParticleLifetime;
  164. float fParticleGlobalT = fTime - fParticleSpawnTime;
  165. float fParticleT = mod(fParticleGlobalT, fParticleLifetime) + fDeltaTime;
  166. float fSequenceSet;
  167. float fSequenceIndex;
  168. float fSequenceStartTime;
  169. float fSequenceSeed;
  170. vec3 vSequenceHash;
  171. vec3 vCol;
  172. vec3 vPos;
  173. vec3 vTarget;
  174. GetSequenceInfo(fLightIndex, fParticleSpawnTime, fSequenceSet,
  175. fSequenceIndex,
  176. fSequenceStartTime,
  177. fSequenceSeed,
  178. vSequenceHash,
  179. vCol,
  180. vPos,
  181. vTarget);
  182. float fSpread = fract(vSequenceHash.z + vSequenceHash.y) + 1.0;
  183. Fountain(fLightIndex, vPos, fParticleT, vCol, fSpread, vWorldPos, fRadius, vColor);
  184. }
  185. void GetLightInfo( in float fLightIndex, float fTime, float fDeltaTime, in vec3 vPosition, in vec3 vTarget, in mat3 mRotation, out vec3 vWorldPos,
  186. out float fRadius,
  187. out vec3 vColor
  188. ) {
  189. //float h = Hash( fLightIndex );
  190. vec3 h3 = Hash3(fLightIndex);
  191. float kHangingLightCount = 32.0;
  192. float kHangingLightMax = 0.0 + kHangingLightCount;
  193. float kStarCount = 0.0;
  194. float kStarMax = kHangingLightMax + kStarCount;
  195. float kDirtCount = 16.0;
  196. float kDirtMax = kStarMax + kDirtCount;
  197. float kStreetLightCount = 64.0;
  198. float kStreetLightMax = kDirtMax + kStreetLightCount;
  199. float kGardenLightCount = 16.0;
  200. float kGardenLightMax = kStreetLightMax + kGardenLightCount;
  201. {
  202. GetFireworkSparkInfo(fLightIndex, fTime, fDeltaTime, h3, vWorldPos, fRadius, vColor);
  203. }
  204. }
  205. void GetBokehVertex( in float fAperture, in float fFocalLength, in float fExposure,
  206. float fVertexIndex, vec2 vOrigin, vec2 vDir, float fSize, float fCoC, vec3 vCol, out vec2 vPos, out vec3 vColor) {
  207. float fInnerSize = fSize + fCoC;
  208. if (fVertexIndex < QUAD_VERTEX_COUNT) {
  209. GetHexagonVertex(fAperture, fFocalLength, fExposure, fVertexIndex, vOrigin, vDir, fInnerSize, vCol, vCol, vPos, vColor);
  210. } else {
  211. vPos.xy = vec2(.0);
  212. vColor.rgb = vec3(.0);
  213. }
  214. }
  215. vec3 get_vpos(float vertexId, mat4 mworld, mat4 mcam, mat4 rcam, mat4 micam, out vec4 vcol, float time, out float d) {
  216. float fVertexIndex = vertexId;
  217. vec3 icam = -mcam[3].xyz;
  218. vec3 vTarget = vec3(0.);
  219. vec3 vPosition = icam + mworld[3].xyz;
  220. mat3 mRotation = mat3(-mcam[0].xyz, -mcam[1].xyz, mcam[2].xyz);
  221. vec2 vPos;
  222. vec3 vColor_pos;
  223. float fBokehIndex = floor(fVertexIndex / QUAD_VERTEX_COUNT);
  224. vec3 vWorldPos;
  225. float fRadius;
  226. vec3 vColor;
  227. GetLightInfo(fBokehIndex, time, 0.0, vPosition,
  228. vTarget,
  229. mRotation, vWorldPos, fRadius, vColor);
  230. vec3 vWorldPos_last;
  231. float fRadius_last;
  232. vec3 vColor_last;
  233. GetLightInfo(fBokehIndex, time, -fShutterSpeed_g, vPosition,
  234. vTarget,
  235. mRotation, vWorldPos_last, fRadius_last, vColor_last);
  236. vec3 vViewPos = GetViewPos(vPosition, mRotation, vWorldPos);
  237. vec3 vLastViewPos = GetViewPos(vPosition,
  238. mRotation, vWorldPos_last);
  239. vec2 vScreenPos = GetScreenPos(fAperture_g, fFocalLength_g, vViewPos);
  240. vec2 vLastScreenPos = GetScreenPos(fAperture_g, fFocalLength_g, vLastViewPos);
  241. float fScreenSize = GetScreenPos(fAperture_g, fFocalLength_g, vec3(fRadius, fRadius, vViewPos.z)).x;
  242. fScreenSize *= scale_g;
  243. vec2 vOrigin = vScreenPos.xy;
  244. vec2 vDir = vLastScreenPos.xy - vScreenPos.xy;
  245. float fCoC = 0.025;
  246. vec3 vCol = vColor;
  247. float fSize = fCoC + fScreenSize;
  248. vCol *= fScreenSize * fScreenSize * 3.14 / (length(vDir) * fSize + fSize * fSize * 3.14);
  249. float fBokehVertexIndex = mod(fVertexIndex, QUAD_VERTEX_COUNT);
  250. GetBokehVertex(fAperture_g, fFocalLength_g,
  251. fExposure_g, fBokehVertexIndex, vOrigin, vDir, fScreenSize, fCoC, vCol, vPos, vColor_pos);
  252. vec4 ret = vec4(vPos.x, vPos.y, 1. / (vertexId + 1000.), 1);
  253. float fFinalExposure = fExposure_g / (fAperture_g * fAperture_g);
  254. vec4 v_color = vec4(0.);
  255. v_color.rgb = 1.0 - exp2(vColor_pos * -fFinalExposure);
  256. v_color.rgb = pow(v_color.rgb, vec3(1.0 / 2.2));
  257. v_color.a = 1.0;
  258. d = vViewPos.z;
  259. float fNearClip = .5 * scale_g;
  260. v_color.a *= smoothstep(0., 0.0175, vViewPos.z - fNearClip);
  261. if (vViewPos.z <= fNearClip) {
  262. ret = vec4(0.0);
  263. v_color = vec4(0.0);
  264. }
  265. vcol = v_color;
  266. return ret.xyz;
  267. }
  268. int triangle_uv(vec2 p) {
  269. vec2 op = p;
  270. const float k = 1.73205080756; //sqrt(3.0);
  271. p.x = abs(p.x) - 1.0;
  272. p.y = p.y + 1.0 / k;
  273. int ret = -1;
  274. if (p.x + k * p.y > 0.0) {
  275. p = vec2(p.x - k * p.y, -k * p.x - p.y) / 2.0;
  276. ret = 1;
  277. }
  278. if ((ret == 1) && (op.x < .0) && ((p.y) > 0.)) {
  279. ret = 1;
  280. } else
  281. if ((ret == 1) && (op.x > .0) && ((p.y) > 0.)) {
  282. ret = 2;
  283. } else
  284. if (p.y > 0.) {
  285. ret = 0;
  286. } else {
  287. ret = -1;
  288. }
  289. return ret;
  290. }
  291. mat2 MD(float a) {
  292. float s = sin(a);
  293. float c = cos(a);
  294. return mat2(vec2(c, -s), vec2(s, c));
  295. }
  296. uniform float tvalx = 0.;
  297. vec2 get_quad_uv(int idx, vec2 ouv) {
  298. vec2 uv = vec2(0.);
  299. float ts = 1. / 0.75;
  300. if ((idx == 1) || (idx == 3)) {
  301. vec2 tuv = (ouv - 0.5) * MD(3.1415926 / 3.) + 0.5;
  302. vec2 p = vec2(tuv.y - 0.25, ouv.y);
  303. uv = p;
  304. } else
  305. if ((idx == 0) || (idx == 2)) {
  306. vec2 tuv = (ouv - 0.5) * MD(3.1415926 / 6.) + 0.5;
  307. vec2 tuv2 = (ouv - 0.5) * MD(3.1415926 / 3.) + 0.5;
  308. vec2 p = vec2(tuv.x, tuv2.y - 0.25);
  309. uv = p.xy;
  310. }
  311. uv *= ts;
  312. if ((idx == 1) || (idx == 0)) {
  313. uv.y = (1. - uv.y);
  314. uv.y *= 0.5;
  315. } else
  316. if ((idx == 2) || (idx == 3)) {
  317. uv.y *= 0.5;
  318. uv.y += 0.5;
  319. }
  320. return uv;
  321. }
  322. varying float z_dist;
  323. void vertex() {
  324. vec3 tvid = VERTEX;
  325. int tid = triangle_uv((tvid.xz) * 2.);
  326. COLOR.rgb = VERTEX;
  327. mat4 wm = WORLD_MATRIX;
  328. mat4 cm = CAMERA_MATRIX;
  329. mat4 mtx;
  330. // bilboard project
  331. //mtx = mat4(normalize(CAMERA_MATRIX[0]) * length(WORLD_MATRIX[0]), normalize(CAMERA_MATRIX[1]) * length(WORLD_MATRIX[0]), normalize(CAMERA_MATRIX[2]) * length(WORLD_MATRIX[2]), WORLD_MATRIX[3]);
  332. // lookAt project, comment/uncomment
  333. vec3 cam_pos = CAMERA_MATRIX[3].xyz;
  334. mtx = lookAt(cam_pos, WORLD_MATRIX[3].xyz, vec3(0., 1., 0.));
  335. cm = mtx;
  336. cm[3].xyz = cam_pos;
  337. vec4 col;
  338. float d;
  339. vec3 ctx = get_vpos(float(INSTANCE_ID * 3 + max(tid, 0)), wm, cm, CAMERA_MATRIX, INV_CAMERA_MATRIX, col, iTime * 0.35, d);
  340. VERTEX = (ctx) * ((cm[3].xyz + -wm[3].xyz) / normalize(cm[3].xyz + -wm[3].xyz));
  341. mtx[3].xyz = WORLD_MATRIX[3].xyz;
  342. MODELVIEW_MATRIX = INV_CAMERA_MATRIX * mtx;
  343. int tid_g = ((INSTANCE_ID * 3 + max(tid, 0)) % int(QUAD_VERTEX_COUNT)) / 3;
  344. UV = get_quad_uv(int(tid_g), UV);
  345. z_dist = clamp(1. - (2.5 / d) / 50., 0., 1.);
  346. z_dist += ctx.z;
  347. COLOR = col;
  348. }
  349. void fragment() {
  350. vec3 rd = normalize(((CAMERA_MATRIX) * vec4(normalize(VERTEX), 0.0)).xyz);
  351. vec3 nor = normalize((CAMERA_MATRIX * vec4(NORMAL, 0.0)).xyz);
  352. ALBEDO = COLOR.rgb * COLOR.a;
  353. ALBEDO = vec3(smoothstep(0., 0.001, UV.y - 0.5 + tvalx));
  354. vec4 col = texture(texture_p, UV.yx);
  355. float dt = min(dot(COLOR.rgb, vec3(1.)), 1.);
  356. ALBEDO = dt * col.a * 0.05 * COLOR.a * colorx.rgb / max(1. - col.a, 0.001);
  357. DEPTH = z_dist - .5 * (1. - FRAGCOORD.z) * max(length(FRAGCOORD.xy / VIEWPORT_SIZE.y - 0.5 * VIEWPORT_SIZE.xy / VIEWPORT_SIZE.y), 0.);
  358. //ALPHA=col.a*0.015*COLOR.a;
  359. }