laya.particle.js 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633
  1. (function (exports, Laya) {
  2. 'use strict';
  3. class ParticleSetting {
  4. constructor() {
  5. this.textureName = null;
  6. this.textureCount = 1;
  7. this.maxPartices = 100;
  8. this.duration = 1;
  9. this.ageAddScale = 0;
  10. this.emitterVelocitySensitivity = 1;
  11. this.minStartSize = 100;
  12. this.maxStartSize = 100;
  13. this.minEndSize = 100;
  14. this.maxEndSize = 100;
  15. this.minHorizontalVelocity = 0;
  16. this.maxHorizontalVelocity = 0;
  17. this.minVerticalVelocity = 0;
  18. this.maxVerticalVelocity = 0;
  19. this.endVelocity = 1;
  20. this.gravity = new Float32Array([0, 0, 0]);
  21. this.minRotateSpeed = 0;
  22. this.maxRotateSpeed = 0;
  23. this.minStartRadius = 0;
  24. this.maxStartRadius = 0;
  25. this.minEndRadius = 0;
  26. this.maxEndRadius = 0;
  27. this.minHorizontalStartRadian = 0;
  28. this.maxHorizontalStartRadian = 0;
  29. this.minVerticalStartRadian = 0;
  30. this.maxVerticalStartRadian = 0;
  31. this.useEndRadian = true;
  32. this.minHorizontalEndRadian = 0;
  33. this.maxHorizontalEndRadian = 0;
  34. this.minVerticalEndRadian = 0;
  35. this.maxVerticalEndRadian = 0;
  36. this.minStartColor = new Float32Array([1, 1, 1, 1]);
  37. this.maxStartColor = new Float32Array([1, 1, 1, 1]);
  38. this.minEndColor = new Float32Array([1, 1, 1, 1]);
  39. this.maxEndColor = new Float32Array([1, 1, 1, 1]);
  40. this.colorComponentInter = false;
  41. this.disableColor = false;
  42. this.blendState = 0;
  43. this.emitterType = "null";
  44. this.emissionRate = 0;
  45. this.pointEmitterPosition = new Float32Array([0, 0, 0]);
  46. this.pointEmitterPositionVariance = new Float32Array([0, 0, 0]);
  47. this.pointEmitterVelocity = new Float32Array([0, 0, 0]);
  48. this.pointEmitterVelocityAddVariance = new Float32Array([0, 0, 0]);
  49. this.boxEmitterCenterPosition = new Float32Array([0, 0, 0]);
  50. this.boxEmitterSize = new Float32Array([0, 0, 0]);
  51. this.boxEmitterVelocity = new Float32Array([0, 0, 0]);
  52. this.boxEmitterVelocityAddVariance = new Float32Array([0, 0, 0]);
  53. this.sphereEmitterCenterPosition = new Float32Array([0, 0, 0]);
  54. this.sphereEmitterRadius = 1;
  55. this.sphereEmitterVelocity = 0;
  56. this.sphereEmitterVelocityAddVariance = 0;
  57. this.ringEmitterCenterPosition = new Float32Array([0, 0, 0]);
  58. this.ringEmitterRadius = 30;
  59. this.ringEmitterVelocity = 0;
  60. this.ringEmitterVelocityAddVariance = 0;
  61. this.ringEmitterUp = 2;
  62. this.positionVariance = new Float32Array([0, 0, 0]);
  63. }
  64. static checkSetting(setting) {
  65. var key;
  66. for (key in ParticleSetting._defaultSetting) {
  67. if (!(key in setting)) {
  68. setting[key] = ParticleSetting._defaultSetting[key];
  69. }
  70. }
  71. setting.endVelocity = +setting.endVelocity;
  72. setting.gravity[0] = +setting.gravity[0];
  73. setting.gravity[1] = +setting.gravity[1];
  74. setting.gravity[2] = +setting.gravity[2];
  75. }
  76. }
  77. ParticleSetting._defaultSetting = new ParticleSetting();
  78. class ParticleTemplateBase {
  79. constructor() {
  80. }
  81. addParticleArray(position, velocity) {
  82. }
  83. }
  84. class ParticleData {
  85. constructor() {
  86. }
  87. static Create(settings, position, velocity, time) {
  88. var particleData = new ParticleData();
  89. particleData.position = position;
  90. Laya.MathUtil.scaleVector3(velocity, settings.emitterVelocitySensitivity, ParticleData._tempVelocity);
  91. var horizontalVelocity = Laya.MathUtil.lerp(settings.minHorizontalVelocity, settings.maxHorizontalVelocity, Math.random());
  92. var horizontalAngle = Math.random() * Math.PI * 2;
  93. ParticleData._tempVelocity[0] += horizontalVelocity * Math.cos(horizontalAngle);
  94. ParticleData._tempVelocity[2] += horizontalVelocity * Math.sin(horizontalAngle);
  95. ParticleData._tempVelocity[1] += Laya.MathUtil.lerp(settings.minVerticalVelocity, settings.maxVerticalVelocity, Math.random());
  96. particleData.velocity = ParticleData._tempVelocity;
  97. particleData.startColor = ParticleData._tempStartColor;
  98. particleData.endColor = ParticleData._tempEndColor;
  99. var i;
  100. if (settings.disableColor) {
  101. for (i = 0; i < 3; i++) {
  102. particleData.startColor[i] = 1;
  103. particleData.endColor[i] = 1;
  104. }
  105. particleData.startColor[i] = Laya.MathUtil.lerp(settings.minStartColor[i], settings.maxStartColor[i], Math.random());
  106. particleData.endColor[i] = Laya.MathUtil.lerp(settings.minEndColor[i], settings.maxEndColor[i], Math.random());
  107. }
  108. else {
  109. if (settings.colorComponentInter) {
  110. for (i = 0; i < 4; i++) {
  111. particleData.startColor[i] = Laya.MathUtil.lerp(settings.minStartColor[i], settings.maxStartColor[i], Math.random());
  112. particleData.endColor[i] = Laya.MathUtil.lerp(settings.minEndColor[i], settings.maxEndColor[i], Math.random());
  113. }
  114. }
  115. else {
  116. Laya.MathUtil.lerpVector4(settings.minStartColor, settings.maxStartColor, Math.random(), particleData.startColor);
  117. Laya.MathUtil.lerpVector4(settings.minEndColor, settings.maxEndColor, Math.random(), particleData.endColor);
  118. }
  119. }
  120. particleData.sizeRotation = ParticleData._tempSizeRotation;
  121. var sizeRandom = Math.random();
  122. particleData.sizeRotation[0] = Laya.MathUtil.lerp(settings.minStartSize, settings.maxStartSize, sizeRandom);
  123. particleData.sizeRotation[1] = Laya.MathUtil.lerp(settings.minEndSize, settings.maxEndSize, sizeRandom);
  124. particleData.sizeRotation[2] = Laya.MathUtil.lerp(settings.minRotateSpeed, settings.maxRotateSpeed, Math.random());
  125. particleData.radius = ParticleData._tempRadius;
  126. var radiusRandom = Math.random();
  127. particleData.radius[0] = Laya.MathUtil.lerp(settings.minStartRadius, settings.maxStartRadius, radiusRandom);
  128. particleData.radius[1] = Laya.MathUtil.lerp(settings.minEndRadius, settings.maxEndRadius, radiusRandom);
  129. particleData.radian = ParticleData._tempRadian;
  130. particleData.radian[0] = Laya.MathUtil.lerp(settings.minHorizontalStartRadian, settings.maxHorizontalStartRadian, Math.random());
  131. particleData.radian[1] = Laya.MathUtil.lerp(settings.minVerticalStartRadian, settings.maxVerticalStartRadian, Math.random());
  132. var useEndRadian = settings.useEndRadian;
  133. particleData.radian[2] = useEndRadian ? Laya.MathUtil.lerp(settings.minHorizontalEndRadian, settings.maxHorizontalEndRadian, Math.random()) : particleData.radian[0];
  134. particleData.radian[3] = useEndRadian ? Laya.MathUtil.lerp(settings.minVerticalEndRadian, settings.maxVerticalEndRadian, Math.random()) : particleData.radian[1];
  135. particleData.durationAddScale = settings.ageAddScale * Math.random();
  136. particleData.time = time;
  137. return particleData;
  138. }
  139. }
  140. ParticleData._tempVelocity = new Float32Array(3);
  141. ParticleData._tempStartColor = new Float32Array(4);
  142. ParticleData._tempEndColor = new Float32Array(4);
  143. ParticleData._tempSizeRotation = new Float32Array(3);
  144. ParticleData._tempRadius = new Float32Array(2);
  145. ParticleData._tempRadian = new Float32Array(4);
  146. class ParticleTemplateWebGL extends ParticleTemplateBase {
  147. constructor(parSetting) {
  148. super();
  149. this._floatCountPerVertex = 29;
  150. this._firstActiveElement = 0;
  151. this._firstNewElement = 0;
  152. this._firstFreeElement = 0;
  153. this._firstRetiredElement = 0;
  154. this._currentTime = 0;
  155. this.settings = parSetting;
  156. }
  157. reUse(context, pos) {
  158. return 0;
  159. }
  160. initialize() {
  161. var floatStride = 0;
  162. this._vertices = this._mesh._vb.getFloat32Array();
  163. floatStride = this._mesh._stride / 4;
  164. var bufi = 0;
  165. var bufStart = 0;
  166. for (var i = 0; i < this.settings.maxPartices; i++) {
  167. var random = Math.random();
  168. var cornerYSegement = this.settings.textureCount ? 1.0 / this.settings.textureCount : 1.0;
  169. var cornerY;
  170. for (cornerY = 0; cornerY < this.settings.textureCount; cornerY += cornerYSegement) {
  171. if (random < cornerY + cornerYSegement)
  172. break;
  173. }
  174. this._vertices[bufi++] = -1;
  175. this._vertices[bufi++] = -1;
  176. this._vertices[bufi++] = 0;
  177. this._vertices[bufi++] = cornerY;
  178. bufi = (bufStart += floatStride);
  179. this._vertices[bufi++] = 1;
  180. this._vertices[bufi++] = -1;
  181. this._vertices[bufi++] = 1;
  182. this._vertices[bufi++] = cornerY;
  183. bufi = bufStart += floatStride;
  184. this._vertices[bufi++] = 1;
  185. this._vertices[bufi++] = 1;
  186. this._vertices[bufi++] = 1;
  187. this._vertices[bufi++] = cornerY + cornerYSegement;
  188. bufi = bufStart += floatStride;
  189. this._vertices[bufi++] = -1;
  190. this._vertices[bufi++] = 1;
  191. this._vertices[bufi++] = 0;
  192. this._vertices[bufi++] = cornerY + cornerYSegement;
  193. bufi = bufStart += floatStride;
  194. }
  195. }
  196. update(elapsedTime) {
  197. this._currentTime += elapsedTime / 1000;
  198. this.retireActiveParticles();
  199. this.freeRetiredParticles();
  200. if (this._firstActiveElement == this._firstFreeElement)
  201. this._currentTime = 0;
  202. if (this._firstRetiredElement == this._firstActiveElement)
  203. this._drawCounter = 0;
  204. }
  205. retireActiveParticles() {
  206. const epsilon = 0.0001;
  207. var particleDuration = this.settings.duration;
  208. while (this._firstActiveElement != this._firstNewElement) {
  209. var offset = this._firstActiveElement * this._floatCountPerVertex * 4;
  210. var index = offset + 28;
  211. var particleAge = this._currentTime - this._vertices[index];
  212. particleAge *= (1.0 + this._vertices[offset + 27]);
  213. if (particleAge + epsilon < particleDuration)
  214. break;
  215. this._vertices[index] = this._drawCounter;
  216. this._firstActiveElement++;
  217. if (this._firstActiveElement >= this.settings.maxPartices)
  218. this._firstActiveElement = 0;
  219. }
  220. }
  221. freeRetiredParticles() {
  222. while (this._firstRetiredElement != this._firstActiveElement) {
  223. var age = this._drawCounter - this._vertices[this._firstRetiredElement * this._floatCountPerVertex * 4 + 28];
  224. if (age < 3)
  225. break;
  226. this._firstRetiredElement++;
  227. if (this._firstRetiredElement >= this.settings.maxPartices)
  228. this._firstRetiredElement = 0;
  229. }
  230. }
  231. addNewParticlesToVertexBuffer() {
  232. }
  233. addParticleArray(position, velocity) {
  234. var nextFreeParticle = this._firstFreeElement + 1;
  235. if (nextFreeParticle >= this.settings.maxPartices)
  236. nextFreeParticle = 0;
  237. if (nextFreeParticle === this._firstRetiredElement)
  238. return;
  239. var particleData = ParticleData.Create(this.settings, position, velocity, this._currentTime);
  240. var startIndex = this._firstFreeElement * this._floatCountPerVertex * 4;
  241. for (var i = 0; i < 4; i++) {
  242. var j, offset;
  243. for (j = 0, offset = 4; j < 3; j++)
  244. this._vertices[startIndex + i * this._floatCountPerVertex + offset + j] = particleData.position[j];
  245. for (j = 0, offset = 7; j < 3; j++)
  246. this._vertices[startIndex + i * this._floatCountPerVertex + offset + j] = particleData.velocity[j];
  247. for (j = 0, offset = 10; j < 4; j++)
  248. this._vertices[startIndex + i * this._floatCountPerVertex + offset + j] = particleData.startColor[j];
  249. for (j = 0, offset = 14; j < 4; j++)
  250. this._vertices[startIndex + i * this._floatCountPerVertex + offset + j] = particleData.endColor[j];
  251. for (j = 0, offset = 18; j < 3; j++)
  252. this._vertices[startIndex + i * this._floatCountPerVertex + offset + j] = particleData.sizeRotation[j];
  253. for (j = 0, offset = 21; j < 2; j++)
  254. this._vertices[startIndex + i * this._floatCountPerVertex + offset + j] = particleData.radius[j];
  255. for (j = 0, offset = 23; j < 4; j++)
  256. this._vertices[startIndex + i * this._floatCountPerVertex + offset + j] = particleData.radian[j];
  257. this._vertices[startIndex + i * this._floatCountPerVertex + 27] = particleData.durationAddScale;
  258. this._vertices[startIndex + i * this._floatCountPerVertex + 28] = particleData.time;
  259. }
  260. this._firstFreeElement = nextFreeParticle;
  261. }
  262. }
  263. var parvs = "attribute vec4 a_CornerTextureCoordinate;\r\nattribute vec3 a_Position;\r\nattribute vec3 a_Velocity;\r\nattribute vec4 a_StartColor;\r\nattribute vec4 a_EndColor;\r\nattribute vec3 a_SizeRotation;\r\nattribute vec2 a_Radius;\r\nattribute vec4 a_Radian;\r\nattribute float a_AgeAddScale;\r\nattribute float a_Time;\r\n\r\nvarying vec4 v_Color;\r\nvarying vec2 v_TextureCoordinate;\r\n\r\nuniform float u_CurrentTime;\r\nuniform float u_Duration;\r\nuniform float u_EndVelocity;\r\nuniform vec3 u_Gravity;\r\n\r\nuniform vec2 size;\r\nuniform mat4 u_mmat;\r\n\r\nvec4 ComputeParticlePosition(in vec3 position, in vec3 velocity,in float age,in float normalizedAge)\r\n{\r\n\r\n float startVelocity = length(velocity);//起始标量速度\r\n float endVelocity = startVelocity * u_EndVelocity;//结束标量速度\r\n\r\n float velocityIntegral = startVelocity * normalizedAge +(endVelocity - startVelocity) * normalizedAge *normalizedAge/2.0;//计算当前速度的标量(单位空间),vt=v0*t+(1/2)*a*(t^2)\r\n \r\n vec3 addPosition = normalize(velocity) * velocityIntegral * u_Duration;//计算受自身速度影响的位置,转换标量到矢量 \r\n addPosition += u_Gravity * age * normalizedAge;//计算受重力影响的位置\r\n \r\n float radius=mix(a_Radius.x, a_Radius.y, normalizedAge); //计算粒子受半径和角度影响(无需计算角度和半径时,可用宏定义优化屏蔽此计算)\r\n float radianHorizontal =mix(a_Radian.x,a_Radian.z,normalizedAge);\r\n float radianVertical =mix(a_Radian.y,a_Radian.w,normalizedAge);\r\n \r\n float r =cos(radianVertical)* radius;\r\n addPosition.y += sin(radianVertical) * radius;\r\n\t\r\n addPosition.x += cos(radianHorizontal) *r;\r\n addPosition.z += sin(radianHorizontal) *r;\r\n \r\n addPosition.y=-addPosition.y;//2D粒子位置更新需要取负,2D粒子坐标系Y轴正向朝上\r\n position+=addPosition;\r\n return vec4(position,1.0);\r\n}\r\n\r\nfloat ComputeParticleSize(in float startSize,in float endSize, in float normalizedAge)\r\n{ \r\n float size = mix(startSize, endSize, normalizedAge);\r\n return size;\r\n}\r\n\r\nmat2 ComputeParticleRotation(in float rot,in float age)\r\n{ \r\n float rotation =rot * age;\r\n //计算2x2旋转矩阵.\r\n float c = cos(rotation);\r\n float s = sin(rotation);\r\n return mat2(c, -s, s, c);\r\n}\r\n\r\nvec4 ComputeParticleColor(in vec4 startColor,in vec4 endColor,in float normalizedAge)\r\n{\r\n\tvec4 color=mix(startColor,endColor,normalizedAge);\r\n //硬编码设置,使粒子淡入很快,淡出很慢,6.7的缩放因子把置归一在0到1之间,可以谷歌x*(1-x)*(1-x)*6.7的制图表\r\n color.a *= normalizedAge * (1.0-normalizedAge) * (1.0-normalizedAge) * 6.7;\r\n \r\n return color;\r\n}\r\n\r\nvoid main()\r\n{\r\n float age = u_CurrentTime - a_Time;\r\n age *= 1.0 + a_AgeAddScale;\r\n float normalizedAge = clamp(age / u_Duration,0.0,1.0);\r\n gl_Position = ComputeParticlePosition(a_Position, a_Velocity, age, normalizedAge);//计算粒子位置\r\n float pSize = ComputeParticleSize(a_SizeRotation.x,a_SizeRotation.y, normalizedAge);\r\n mat2 rotation = ComputeParticleRotation(a_SizeRotation.z, age);\r\n\t\r\n mat4 mat=u_mmat;\r\n gl_Position=vec4((mat*gl_Position).xy,0.0,1.0);\r\n gl_Position.xy += (rotation*a_CornerTextureCoordinate.xy) * pSize*vec2(mat[0][0],mat[1][1]);\r\n gl_Position=vec4((gl_Position.x/size.x-0.5)*2.0,(0.5-gl_Position.y/size.y)*2.0,0.0,1.0);\r\n \r\n v_Color = ComputeParticleColor(a_StartColor,a_EndColor, normalizedAge);\r\n v_TextureCoordinate =a_CornerTextureCoordinate.zw;\r\n}\r\n\r\n";
  264. var parps = "#ifdef GL_FRAGMENT_PRECISION_HIGH\r\nprecision highp float;\r\n#else\r\nprecision mediump float;\r\n#endif\r\n\r\nvarying vec4 v_Color;\r\nvarying vec2 v_TextureCoordinate;\r\nuniform sampler2D u_texture;\r\n\r\nvoid main()\r\n{\t\r\n\tgl_FragColor=texture2D(u_texture,v_TextureCoordinate)*v_Color;\r\n\tgl_FragColor.xyz *= v_Color.w;\r\n}";
  265. class ParticleShader extends Laya.Shader {
  266. constructor() {
  267. super(parvs, parps, "ParticleShader", null, ['a_CornerTextureCoordinate', 0, 'a_Position', 1, 'a_Velocity', 2, 'a_StartColor', 3,
  268. 'a_EndColor', 4, 'a_SizeRotation', 5, 'a_Radius', 6, 'a_Radian', 7, 'a_AgeAddScale', 8, 'a_Time', 9]);
  269. }
  270. }
  271. ParticleShader.vs = parvs;
  272. ParticleShader.ps = parps;
  273. class ParticleShaderValue extends Laya.Value2D {
  274. constructor() {
  275. super(0, 0);
  276. if (!ParticleShaderValue.pShader) {
  277. ParticleShaderValue.pShader = new ParticleShader();
  278. }
  279. }
  280. upload() {
  281. var size = this.size;
  282. size[0] = Laya.RenderState2D.width;
  283. size[1] = Laya.RenderState2D.height;
  284. this.alpha = this.ALPHA * Laya.RenderState2D.worldAlpha;
  285. ParticleShaderValue.pShader.upload(this);
  286. }
  287. }
  288. ParticleShaderValue.pShader = null;
  289. class ParticleTemplate2D extends ParticleTemplateWebGL {
  290. constructor(parSetting) {
  291. super(parSetting);
  292. this.x = 0;
  293. this.y = 0;
  294. this.sv = new ParticleShaderValue();
  295. this._key = {};
  296. var _this = this;
  297. Laya.ILaya.loader.load(this.settings.textureName, Laya.Handler.create(null, function (texture) {
  298. _this.texture = texture;
  299. }), null, Laya.Loader.IMAGE);
  300. this.sv.u_Duration = this.settings.duration;
  301. this.sv.u_Gravity = this.settings.gravity;
  302. this.sv.u_EndVelocity = this.settings.endVelocity;
  303. this._blendFn = Laya.BlendMode.fns[parSetting.blendState];
  304. this._mesh = Laya.MeshParticle2D.getAMesh(this.settings.maxPartices);
  305. this.initialize();
  306. }
  307. getRenderType() { return -111; }
  308. releaseRender() { }
  309. addParticleArray(position, velocity) {
  310. position[0] += this.x;
  311. position[1] += this.y;
  312. super.addParticleArray(position, velocity);
  313. }
  314. addNewParticlesToVertexBuffer() {
  315. var _vertexBuffer2D = this._mesh._vb;
  316. _vertexBuffer2D.clear();
  317. _vertexBuffer2D.append(this._vertices);
  318. var start;
  319. if (this._firstNewElement < this._firstFreeElement) {
  320. start = this._firstNewElement * 4 * this._floatCountPerVertex * 4;
  321. _vertexBuffer2D.subUpload(start, start, start + (this._firstFreeElement - this._firstNewElement) * 4 * this._floatCountPerVertex * 4);
  322. }
  323. else {
  324. start = this._firstNewElement * 4 * this._floatCountPerVertex * 4;
  325. _vertexBuffer2D.subUpload(start, start, start + (this.settings.maxPartices - this._firstNewElement) * 4 * this._floatCountPerVertex * 4);
  326. if (this._firstFreeElement > 0) {
  327. _vertexBuffer2D.setNeedUpload();
  328. _vertexBuffer2D.subUpload(0, 0, this._firstFreeElement * 4 * this._floatCountPerVertex * 4);
  329. }
  330. }
  331. this._firstNewElement = this._firstFreeElement;
  332. }
  333. renderSubmit() {
  334. if (this.texture && this.texture.getIsReady()) {
  335. this.update(Laya.ILaya.timer._delta);
  336. this.sv.u_CurrentTime = this._currentTime;
  337. if (this._firstNewElement != this._firstFreeElement) {
  338. this.addNewParticlesToVertexBuffer();
  339. }
  340. this.blend();
  341. if (this._firstActiveElement != this._firstFreeElement) {
  342. var gl = Laya.WebGLContext.mainContext;
  343. this._mesh.useMesh(gl);
  344. this.sv.u_texture = this.texture._getSource();
  345. this.sv.upload();
  346. if (this._firstActiveElement < this._firstFreeElement) {
  347. gl.drawElements(gl.TRIANGLES, (this._firstFreeElement - this._firstActiveElement) * 6, gl.UNSIGNED_SHORT, this._firstActiveElement * 6 * 2);
  348. }
  349. else {
  350. Laya.WebGLContext.mainContext.drawElements(gl.TRIANGLES, (this.settings.maxPartices - this._firstActiveElement) * 6, gl.UNSIGNED_SHORT, this._firstActiveElement * 6 * 2);
  351. if (this._firstFreeElement > 0)
  352. gl.drawElements(gl.TRIANGLES, this._firstFreeElement * 6, gl.UNSIGNED_SHORT, 0);
  353. }
  354. Laya.Stat.renderBatches++;
  355. }
  356. this._drawCounter++;
  357. }
  358. return 1;
  359. }
  360. updateParticleForNative() {
  361. if (this.texture && this.texture.getIsReady()) {
  362. this.update(Laya.ILaya.timer._delta);
  363. this.sv.u_CurrentTime = this._currentTime;
  364. if (this._firstNewElement != this._firstFreeElement) {
  365. this._firstNewElement = this._firstFreeElement;
  366. }
  367. }
  368. }
  369. getMesh() {
  370. return this._mesh;
  371. }
  372. getConchMesh() {
  373. return this._conchMesh;
  374. }
  375. getFirstNewElement() {
  376. return this._firstNewElement;
  377. }
  378. getFirstFreeElement() {
  379. return this._firstFreeElement;
  380. }
  381. getFirstActiveElement() {
  382. return this._firstActiveElement;
  383. }
  384. getFirstRetiredElement() {
  385. return this._firstRetiredElement;
  386. }
  387. setFirstFreeElement(_value) {
  388. this._firstFreeElement = _value;
  389. }
  390. setFirstNewElement(_value) {
  391. this._firstNewElement = _value;
  392. }
  393. addDrawCounter() {
  394. this._drawCounter++;
  395. }
  396. blend() {
  397. if (Laya.BlendMode.activeBlendFunction !== this._blendFn) {
  398. var gl = Laya.WebGLContext.mainContext;
  399. gl.enable(gl.BLEND);
  400. this._blendFn(gl);
  401. Laya.BlendMode.activeBlendFunction = this._blendFn;
  402. }
  403. }
  404. dispose() {
  405. this._mesh.releaseMesh();
  406. }
  407. }
  408. ParticleTemplate2D.activeBlendType = -1;
  409. class EmitterBase {
  410. constructor() {
  411. this._frameTime = 0;
  412. this._emissionRate = 60;
  413. this._emissionTime = 0;
  414. this.minEmissionTime = 1 / 60;
  415. }
  416. set particleTemplate(particleTemplate) {
  417. this._particleTemplate = particleTemplate;
  418. }
  419. set emissionRate(_emissionRate) {
  420. if (_emissionRate <= 0)
  421. return;
  422. this._emissionRate = _emissionRate;
  423. (_emissionRate > 0) && (this.minEmissionTime = 1 / _emissionRate);
  424. }
  425. get emissionRate() {
  426. return this._emissionRate;
  427. }
  428. start(duration = Number.MAX_VALUE) {
  429. if (this._emissionRate != 0)
  430. this._emissionTime = duration;
  431. }
  432. stop() {
  433. this._emissionTime = 0;
  434. }
  435. clear() {
  436. this._emissionTime = 0;
  437. }
  438. emit() {
  439. }
  440. advanceTime(passedTime = 1) {
  441. this._emissionTime -= passedTime;
  442. if (this._emissionTime < 0)
  443. return;
  444. this._frameTime += passedTime;
  445. if (this._frameTime < this.minEmissionTime)
  446. return;
  447. while (this._frameTime > this.minEmissionTime) {
  448. this._frameTime -= this.minEmissionTime;
  449. this.emit();
  450. }
  451. }
  452. }
  453. class Emitter2D extends EmitterBase {
  454. constructor(_template) {
  455. super();
  456. this.template = _template;
  457. }
  458. set template(template) {
  459. this._particleTemplate = template;
  460. if (!template) {
  461. this._emitFun = null;
  462. this.setting = null;
  463. this._posRange = null;
  464. }
  465. this.setting = template.settings;
  466. this._posRange = this.setting.positionVariance;
  467. if (this._particleTemplate instanceof ParticleTemplate2D) {
  468. this._emitFun = this.webGLEmit;
  469. }
  470. }
  471. get template() {
  472. return this._particleTemplate;
  473. }
  474. emit() {
  475. super.emit();
  476. if (this._emitFun != null)
  477. this._emitFun();
  478. }
  479. getRandom(value) {
  480. return (Math.random() * 2 - 1) * value;
  481. }
  482. webGLEmit() {
  483. var pos = new Float32Array(3);
  484. pos[0] = this.getRandom(this._posRange[0]);
  485. pos[1] = this.getRandom(this._posRange[1]);
  486. pos[2] = this.getRandom(this._posRange[2]);
  487. var v = new Float32Array(3);
  488. v[0] = 0;
  489. v[1] = 0;
  490. v[2] = 0;
  491. this._particleTemplate.addParticleArray(pos, v);
  492. }
  493. canvasEmit() {
  494. var pos = new Float32Array(3);
  495. pos[0] = this.getRandom(this._posRange[0]);
  496. pos[1] = this.getRandom(this._posRange[1]);
  497. pos[2] = this.getRandom(this._posRange[2]);
  498. var v = new Float32Array(3);
  499. v[0] = 0;
  500. v[1] = 0;
  501. v[2] = 0;
  502. this._particleTemplate.addParticleArray(pos, v);
  503. }
  504. }
  505. class Particle2D extends Laya.Sprite {
  506. constructor(setting) {
  507. super();
  508. this._matrix4 = new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
  509. this.autoPlay = true;
  510. this.customRenderEnable = true;
  511. if (setting)
  512. this.setParticleSetting(setting);
  513. }
  514. set url(url) {
  515. this.load(url);
  516. }
  517. load(url) {
  518. Laya.ILaya.loader.load(url, Laya.Handler.create(this, this.setParticleSetting), null, Laya.ILaya.Loader.JSON);
  519. }
  520. setParticleSetting(setting) {
  521. if (!setting)
  522. return this.stop();
  523. ParticleSetting.checkSetting(setting);
  524. this.customRenderEnable = true;
  525. this._particleTemplate = new ParticleTemplate2D(setting);
  526. this.graphics._saveToCmd(null, Laya.DrawParticleCmd.create(this._particleTemplate));
  527. if (!this._emitter) {
  528. this._emitter = new Emitter2D(this._particleTemplate);
  529. }
  530. else {
  531. this._emitter.template = this._particleTemplate;
  532. }
  533. if (this.autoPlay) {
  534. this.emitter.start();
  535. this.play();
  536. }
  537. }
  538. get emitter() {
  539. return this._emitter;
  540. }
  541. play() {
  542. Laya.ILaya.timer.frameLoop(1, this, this._loop);
  543. }
  544. stop() {
  545. Laya.ILaya.timer.clear(this, this._loop);
  546. }
  547. _loop() {
  548. this.advanceTime(1 / 60);
  549. }
  550. advanceTime(passedTime = 1) {
  551. if (this._canvasTemplate) {
  552. this._canvasTemplate.advanceTime(passedTime);
  553. }
  554. if (this._emitter) {
  555. this._emitter.advanceTime(passedTime);
  556. }
  557. }
  558. customRender(context, x, y) {
  559. this._matrix4[0] = context._curMat.a;
  560. this._matrix4[1] = context._curMat.b;
  561. this._matrix4[4] = context._curMat.c;
  562. this._matrix4[5] = context._curMat.d;
  563. this._matrix4[12] = context._curMat.tx;
  564. this._matrix4[13] = context._curMat.ty;
  565. var sv = this._particleTemplate.sv;
  566. sv.u_mmat = this._matrix4;
  567. if (this._canvasTemplate) {
  568. this._canvasTemplate.render(context, x, y);
  569. }
  570. }
  571. destroy(destroyChild = true) {
  572. if (this._particleTemplate instanceof ParticleTemplate2D)
  573. this._particleTemplate.dispose();
  574. super.destroy(destroyChild);
  575. }
  576. }
  577. Laya.ILaya.regClass(Particle2D);
  578. class ParticleEmitter {
  579. constructor(templet, particlesPerSecond, initialPosition) {
  580. this._timeLeftOver = 0;
  581. this._tempVelocity = new Float32Array([0, 0, 0]);
  582. this._tempPosition = new Float32Array([0, 0, 0]);
  583. this._templet = templet;
  584. this._timeBetweenParticles = 1.0 / particlesPerSecond;
  585. this._previousPosition = initialPosition;
  586. }
  587. update(elapsedTime, newPosition) {
  588. elapsedTime = elapsedTime / 1000;
  589. if (elapsedTime > 0) {
  590. Laya.MathUtil.subtractVector3(newPosition, this._previousPosition, this._tempVelocity);
  591. Laya.MathUtil.scaleVector3(this._tempVelocity, 1 / elapsedTime, this._tempVelocity);
  592. var timeToSpend = this._timeLeftOver + elapsedTime;
  593. var currentTime = -this._timeLeftOver;
  594. while (timeToSpend > this._timeBetweenParticles) {
  595. currentTime += this._timeBetweenParticles;
  596. timeToSpend -= this._timeBetweenParticles;
  597. Laya.MathUtil.lerpVector3(this._previousPosition, newPosition, currentTime / elapsedTime, this._tempPosition);
  598. this._templet.addParticleArray(this._tempPosition, this._tempVelocity);
  599. }
  600. this._timeLeftOver = timeToSpend;
  601. }
  602. this._previousPosition[0] = newPosition[0];
  603. this._previousPosition[1] = newPosition[1];
  604. this._previousPosition[2] = newPosition[2];
  605. }
  606. }
  607. exports.Emitter2D = Emitter2D;
  608. exports.EmitterBase = EmitterBase;
  609. exports.Particle2D = Particle2D;
  610. exports.ParticleData = ParticleData;
  611. exports.ParticleEmitter = ParticleEmitter;
  612. exports.ParticleSetting = ParticleSetting;
  613. exports.ParticleShader = ParticleShader;
  614. exports.ParticleShaderValue = ParticleShaderValue;
  615. exports.ParticleTemplate2D = ParticleTemplate2D;
  616. exports.ParticleTemplateBase = ParticleTemplateBase;
  617. exports.ParticleTemplateWebGL = ParticleTemplateWebGL;
  618. }(window.Laya = window.Laya || {}, Laya));