index.ts 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790
  1. import XrFrame from 'XrFrame';
  2. import BasicParticle from './SystemProperty/BasicParticle'
  3. import SubEmitter, { SubEmitterState } from './Util/SubEmitter'
  4. import ParticleInstance from './SystemProperty/ParticleInstance'
  5. import { BasicGradientMethod } from './Util/Gradient'
  6. const xrFrameSystem = wx.getXrFrameSystem();
  7. const tempVec1 = xrFrameSystem.Vector3.createFromNumber(0, 0, 0);
  8. const tempVec2 = xrFrameSystem.Vector3.createFromNumber(0, 0, 0);
  9. function randomBetween(v1, v2, randomSeed = Math.random()) {
  10. if (v1 === v2) {
  11. return v1;
  12. } else {
  13. return randomSeed * Math.abs(v1 - v2) + Math.min(v1, v2);
  14. }
  15. };
  16. // 继承了控制粒子系统渲染的基础类,这里将实现粒子运作的逻辑
  17. export default class CustomParticle extends BasicParticle {
  18. public readonly priority: number = 300;
  19. public subEmitters = null;
  20. private _start: boolean = false;
  21. private _stop: boolean = false;
  22. private _alive: boolean = false;
  23. private _actualFrame: number = 0;
  24. private _excessInstance: number = 0;
  25. private _emitterWorldMatrix: XrFrame.Matrix4;
  26. private _emitterInverseWorldMatrix: XrFrame.Matrix4;
  27. private _tempEndColor: XrFrame.Vector4 = xrFrameSystem.Vector4.createFromNumber(0, 0, 0, 0);
  28. private _tempDiffColor: XrFrame.Vector4 = xrFrameSystem.Vector4.createFromNumber(0, 0, 0, 0);
  29. private _tempAccColorStep: XrFrame.Vector4 = xrFrameSystem.Vector4.createFromNumber(0, 0, 0, 0);
  30. private _activeSubEmitterSystem;
  31. private _rootEmitterSystem;
  32. get material() {
  33. return this._material;
  34. }
  35. set material(value: Material) {
  36. if (!this._mesh) {
  37. return;
  38. }
  39. }
  40. get id() {
  41. return this._mesh.id;
  42. }
  43. get data() {
  44. return this._data;
  45. }
  46. get particleEmitter() {
  47. return this._particleEmitter;
  48. }
  49. set data(value: IParticleData) {
  50. this._data = value;
  51. }
  52. /**
  53. * 粒子系统开始播放。
  54. *
  55. * @param delay 设定粒子延时几秒后再播放。
  56. */
  57. public start(delay) {
  58. if (delay) {
  59. setTimeout(() => {
  60. this.start(0);
  61. }, delay);
  62. return;
  63. }
  64. this._start = true;
  65. this._stop = false;
  66. if (this._preWarmCycles) {
  67. for (var index = 0; index < this._preWarmCycles; index++) {
  68. this._updateRenderData(0, true);
  69. }
  70. }
  71. }
  72. /**
  73. * 停止粒子系统与其子发射器的播放。
  74. */
  75. public stop() {
  76. if (this._stop) {
  77. return;
  78. }
  79. this._stop = true;
  80. this.stopSubEmitters();
  81. }
  82. /**
  83. * 当粒子系统添加到场景中时会执行的函数
  84. */
  85. public onAdd(parent: Element, data: IParticleData) {
  86. if (this._mesh) {
  87. return;
  88. }
  89. // 将元素和粒子所在场景给予对应成员变量
  90. this.particleEl = this.el;
  91. this.particleScene = this.el.scene;
  92. this._data = data;
  93. this.initParticle(this._data);
  94. // 检查是否存在子发射器
  95. this._prepareSubEmitterArray();
  96. // 粒子系统开始运行,delay控制几秒后执行
  97. this.start(this._delay);
  98. }
  99. /**
  100. * 初始化粒子系统的状态。
  101. */
  102. public initParticle(data: IParticleData) {
  103. this._systemId = CustomParticle.count++;
  104. this._parseProperties(data);
  105. this._parseAttribute();
  106. this._createVertexBuffers();
  107. this._createIndexBuffer();
  108. this._registerGeometry();
  109. this._createMesh();
  110. this._chooseEmitterProcess();
  111. this._setMeshData(this._material, data.uniforms, data.states);
  112. }
  113. /**
  114. * 获取一个粒子子发射器。
  115. */
  116. public createSubEmitter(data: IParticleData) {
  117. var particleSystem = new CustomParticle();
  118. var tempData: IParticleData = {};
  119. particleSystem.data = tempData;
  120. particleSystem.particleEl = this.particleEl || this.el;
  121. particleSystem.particleScene = this.particleScene || this.el.scene;
  122. for (var key in data) {
  123. particleSystem.data[key] = data[key];
  124. }
  125. //此时还未解析后加入的properties数据, 当此subEmitter被clone后成员数据更新生效
  126. var subEmitter = new SubEmitter(particleSystem)
  127. return subEmitter;
  128. }
  129. /**
  130. * 获取一个拷贝的粒子系统。
  131. */
  132. public clone() {
  133. var cloneParticleSystem = new CustomParticle();
  134. var tempData: IParticleData = {};
  135. for (var key in this._data) {
  136. tempData[key] = this._data[key]
  137. }
  138. cloneParticleSystem.data = tempData;
  139. cloneParticleSystem.particleEl = this.particleScene.createElement(xrFrameSystem.XRNode, {
  140. position: "0 0 0"
  141. });
  142. this.particleEl.addChild(cloneParticleSystem.particleEl);
  143. cloneParticleSystem.particleScene = this.particleScene;
  144. return cloneParticleSystem;
  145. }
  146. /**
  147. * 重置粒子系统的状态。
  148. */
  149. public resetParticle() {
  150. this._stockInstances.length = 0;
  151. this._instances.length = 0;
  152. // canvas must be redrawed to make right phenomenon
  153. this._updateRenderData(0);
  154. this._setMeshData(this._material)
  155. };
  156. /**
  157. * 检测子发射器的类型
  158. */
  159. protected _prepareSubEmitterArray() {
  160. this._subEmitters = [];
  161. if (this.subEmitters) {
  162. this.subEmitters.forEach((subEmitter) => {
  163. if (subEmitter instanceof CustomParticle) {
  164. this._subEmitters.push([new SubEmitter(subEmitter)]);
  165. } else if (subEmitter instanceof SubEmitter) {
  166. this._subEmitters.push([subEmitter]);
  167. } else if (subEmitter instanceof Array) {
  168. this._subEmitters.push(subEmitter);
  169. }
  170. })
  171. }
  172. if (this._subEmitters && this._subEmitters.length != 0) {
  173. this._activeSubEmitterSystem = new Array();
  174. }
  175. }
  176. /**
  177. * 停止所有粒子子系统的发射状态。
  178. */
  179. protected stopSubEmitters() {
  180. if (!this._activeSubEmitterSystem) {
  181. return;
  182. }
  183. this._activeSubEmitterSystem.forEach((subEmitterSystem) => {
  184. subEmitterSystem.stop();
  185. })
  186. this._activeSubEmitterSystem = new Array();
  187. }
  188. /**
  189. * 粒子子发射系统从依附的粒子系统中剥离。
  190. */
  191. protected removeFromRoot() {
  192. if (!this._rootEmitterSystem) {
  193. return;
  194. }
  195. var index = this._rootEmitterSystem._activeSubEmitterSystem.indexOf(this);
  196. if (index !== -1) {
  197. this._rootEmitterSystem._activeSubEmitterSystem.splice(index, 1);
  198. }
  199. this._rootEmitterSystem = null;
  200. }
  201. /**
  202. * 每一帧粒子系统更新的逻辑
  203. */
  204. public onTick(deltaTime: number, data: IParticleData): void {
  205. this._updateSpeed = deltaTime / 1000;
  206. //layout发生变化时,会重置粒子系统
  207. if (this._vertexLayoutDirty) {
  208. this.onUpdate(data, null);
  209. } else {
  210. this._updateRenderData(deltaTime);
  211. this._setMeshData(this._material, data.uniforms);
  212. }
  213. this._material?._checkTextures(deltaTime);
  214. }
  215. public onUpdate(data: IParticleData, preData: IParticleData) {
  216. if (!this._mesh) {
  217. return;
  218. }
  219. // 如果顶点布局发生变化,则需要重置粒子系统
  220. if (this._vertexLayoutDirty) {
  221. this.resetParticle();
  222. this._parseAttribute();
  223. this._createVertexBuffers();
  224. this._setMeshData(this._material, data.uniforms);
  225. this._vertexLayoutDirty = false;
  226. } else {
  227. //wxml属性更新
  228. this.resetParticle();
  229. this.initParticle(data);
  230. }
  231. }
  232. // 每一帧进行粒子生成和粒子位置与轨迹运算的核心逻辑
  233. protected _updateRenderData(deltaTime: number, isPreWarm: boolean = false) {
  234. if (!this._start) {
  235. return;
  236. }
  237. var newInstanceSum;
  238. var rate = this._emitRate;
  239. var _scaledUpdateSpeed = this._updateSpeed * (isPreWarm ? this._preWarmStepOffset : 1);
  240. newInstanceSum = (rate * _scaledUpdateSpeed) >> 0;
  241. this._excessInstance += rate * _scaledUpdateSpeed - newInstanceSum;
  242. if (this._excessInstance > 1.0) {
  243. newInstanceSum += this._excessInstance >> 0;
  244. this._excessInstance -= this._excessInstance >> 0;
  245. }
  246. //burst mode
  247. //控制粒子喷射效果的逻辑
  248. if (this._burstCount > 0) {
  249. var cycle: boolean = false;
  250. var begin: boolean = false;
  251. //达到喷射时间时,开始第一次喷射
  252. if (this._burstCountTime < this._burstTime) {
  253. this._burstCountTime += this._updateSpeed;
  254. } else {
  255. begin = true;
  256. }
  257. if (begin) {
  258. // 判断喷射间隙, 如果喷射间隙过短则视为仅喷射一次
  259. if (this._burstInterval < 0.01) {
  260. if (this._burstInterval >= 0) {
  261. newInstanceSum += this._burstCount;
  262. this._burstInterval = -1;
  263. }
  264. } else {
  265. this._burstCountInterval += this._updateSpeed;
  266. if (this._burstCountInterval > this._burstInterval) {
  267. cycle = true;
  268. this._burstCountInterval = 0
  269. }
  270. }
  271. }
  272. // 判断喷射循环的次数
  273. if (cycle) {
  274. if (this._burstCycle != -1) {
  275. if (this._burstCountCycle >= this._burstCycle >> 0) {
  276. cycle = false;
  277. } else {
  278. this._burstCountCycle++;
  279. }
  280. }
  281. }
  282. if (cycle) {
  283. newInstanceSum += this._burstCount >> 0;
  284. }
  285. }
  286. this._alive = false;
  287. if (!this._stop) {
  288. this._actualFrame += _scaledUpdateSpeed;
  289. if (this._stopDuration && this._actualFrame >= this._stopDuration) {
  290. this.stop();
  291. }
  292. }
  293. else {
  294. newInstanceSum = 0;
  295. }
  296. this.update(newInstanceSum);
  297. if (this._stop) {
  298. if (!this._alive) {
  299. this._start = false;
  300. this.resetParticle();
  301. this.removeFromRoot();
  302. }
  303. }
  304. if (!isPreWarm) {
  305. var offset = 0;
  306. // 每帧此处需要清空_vertexData
  307. this._vertexData.fill(0);
  308. for (var index = 0; index < this._instances.length; index++) {
  309. var particle = this._instances[index];
  310. this._appendParticleVertices(offset, particle);
  311. if (this._useRenderMesh) {
  312. offset += this._vertexCount;
  313. } else {
  314. offset += 4;
  315. }
  316. if (particle.subEmitterMuster && particle.subEmitterMuster.length > 0) {
  317. particle.subEmitterMuster.forEach((subEmitter: SubEmitter) => {
  318. subEmitter.particleSystem.onTick(deltaTime, subEmitter.particleSystem.data);
  319. })
  320. }
  321. }
  322. if (this._activeSubEmitterSystem && this._activeSubEmitterSystem.length > 0) {
  323. this._activeSubEmitterSystem.forEach((particleSystem) => {
  324. particleSystem.onTick(deltaTime, particleSystem.data);
  325. })
  326. }
  327. }
  328. }
  329. /**
  330. * 创建一个粒子实例。
  331. */
  332. protected createParticle() {
  333. var instance: ParticleInstance;
  334. if (this._stockInstances.length !== 0) {
  335. instance = this._stockInstances.pop();
  336. instance.reset();
  337. }
  338. else {
  339. instance = new ParticleInstance(this);
  340. }
  341. if (this._subEmitters && this._subEmitters.length > 0) {
  342. var subEmitters = this._subEmitters[Math.floor(Math.random() * this._subEmitters.length)];
  343. instance.subEmitterMuster = [];
  344. subEmitters.forEach((subEmitter) => {
  345. if (subEmitter.state == SubEmitterState.ATTACH) {
  346. var tempEmitter = subEmitter.clone();
  347. instance.subEmitterMuster.push(tempEmitter);
  348. tempEmitter.particleSystem.start();
  349. }
  350. })
  351. }
  352. return instance;
  353. };
  354. /**
  355. * 启动处于END状态的粒子子发射器。
  356. * @param {ParticleInstance} instance 粒子实例
  357. */
  358. protected particleSubEmitter(instance: ParticleInstance) {
  359. if (!this._subEmitters || this._subEmitters.length == 0) {
  360. return;
  361. }
  362. var tempIndex = Math.floor(Math.random() * this._subEmitters.length);
  363. this._subEmitters[tempIndex].forEach((subEmitter) => {
  364. if (subEmitter.state == SubEmitterState.END) {
  365. var tempEmitter = subEmitter.clone();
  366. tempEmitter.particleSystem._rootEmitterSystem = this;
  367. // the position of sub emitter from one particle
  368. tempEmitter.particleSystem.emitterPosition = instance.position.clone();
  369. this._activeSubEmitterSystem.push(tempEmitter.particleSystem);
  370. tempEmitter.particleSystem.start();
  371. }
  372. })
  373. }
  374. /**
  375. * 回收当前粒子实例,并放入储备粒子队列。
  376. * @param {ParticleInstance} particle 粒子实例
  377. */
  378. protected recycleParticle(particle: ParticleInstance) {
  379. var lastParticle = this._instances.pop();
  380. if (lastParticle !== particle) {
  381. lastParticle.copyTo(particle);
  382. }
  383. this._stockInstances.push(lastParticle);
  384. }
  385. /**
  386. * 更新每一个粒子的状态。
  387. * @param {number} instancesSum 新生成的粒子数
  388. */
  389. protected update(instancesSum: number) {
  390. // Update current
  391. this._alive = this._instances.length > 0;
  392. if (!this._alive && this._stop) {
  393. return;
  394. }
  395. var emitterPosition = this._emitterPosition;
  396. this._emitterWorldMatrix = xrFrameSystem.Matrix4.IDENTITY.translate(emitterPosition.x, emitterPosition.y, emitterPosition.z);
  397. this._emitterWorldMatrix.inverse(this._emitterInverseWorldMatrix);
  398. var instance: ParticleInstance;
  399. var loop = (index) => {
  400. if (this._instances.length === this._capacity) {
  401. return "break";
  402. }
  403. instance = this.createParticle();
  404. this._instances.push(instance);
  405. this.initInstanceProperty(instance);
  406. };
  407. for (var index = 0; index < instancesSum; index++) {
  408. var state = loop(index);
  409. if (state === "break")
  410. break;
  411. }
  412. this.updateInstanceProperty(this._instances);
  413. };
  414. /**
  415. * 初始化粒子实例。
  416. * @param {ParticleInstance} instance 需要初始化的粒子实例
  417. */
  418. protected initInstanceProperty(instance: ParticleInstance) {
  419. instance.lifeTime = randomBetween(this._minLifeTime, this._maxLifeTime);
  420. //Ramp
  421. if (this._useRampGradients) {
  422. instance.rampPos = xrFrameSystem.Vector4.createFromNumber(0, 1, 0, 1);
  423. }
  424. //Position
  425. this._particleEmitter.startPosition(this._emitterWorldMatrix, instance.position);
  426. //Rotation
  427. instance.angularSpeed = randomBetween(this._minAngularSpeed, this._maxAngularSpeed);
  428. instance.angle = randomBetween(this._startAngle, this._startAngle2);
  429. //Direction
  430. instance.speed = randomBetween(this._minSpeed, this._maxSpeed);
  431. this._particleEmitter.startDirection(this._emitterWorldMatrix, instance.direction, instance.position);
  432. //Color
  433. if (this._colorGradients && this._colorGradients.length > 0) {
  434. instance.currentColorGradient = this._colorGradients[0];
  435. instance.currentColorGradient.getColor(instance.currentColor);
  436. instance.color = instance.currentColor.clone();
  437. if (this._colorGradients.length > 1) {
  438. this._colorGradients[1].getColor(instance.currentColor2);
  439. } else {
  440. instance.currentColor2 = instance.currentColor.clone();
  441. }
  442. } else {
  443. var lerpStep = Math.random();
  444. var startColor2, endColor;
  445. startColor2 = this._startColor2 ?? this._startColor;
  446. endColor = this._endColor ?? this._startColor;
  447. this.lerpNumberArrayToVector(instance.color, this._startColor, startColor2, lerpStep);
  448. this.lerpNumberArrayToVector(this._tempEndColor, endColor, endColor, lerpStep);
  449. this._tempEndColor.sub(instance.color, this._tempDiffColor);
  450. this._tempDiffColor.scale(1 / instance.lifeTime, instance.colorStep);
  451. }
  452. //Color-alpha
  453. if (this._alphaGradients && this._alphaGradients.length > 0) {
  454. instance.currentAlphaGradient = this._alphaGradients[0];
  455. instance.currentAlpha = instance.currentAlphaGradient.getFactor();
  456. instance.color.w = instance.currentAlpha;
  457. if (this._alphaGradients.length > 1) {
  458. instance.currentAlpha2 = this._alphaGradients[1].getFactor();
  459. } else {
  460. instance.currentAlpha2 = instance.currentAlpha;
  461. }
  462. }
  463. //Speed
  464. if (this._speedScaleGradients && this._speedScaleGradients.length > 0) {
  465. instance.currentSpeedScaleGradient = this._speedScaleGradients[0];
  466. instance.currentSpeedScale = instance.currentSpeedScaleGradient.getFactor();
  467. if (this._speedScaleGradients.length > 1) {
  468. instance.currentSpeedScale2 = this._speedScaleGradients[1].getFactor();
  469. } else {
  470. instance.currentSpeedScale2 = instance.currentSpeedScale;
  471. }
  472. }
  473. //Limit-speed
  474. if (this._limitSpeedGradients && this._limitSpeedGradients.length > 0) {
  475. instance.currentLimitSpeedGradient = this._limitSpeedGradients[0];
  476. instance.currentLimitSpeed = instance.currentLimitSpeedGradient.getFactor();
  477. if (this._limitSpeedGradients.length > 1) {
  478. instance.currentLimitSpeed2 = this._limitSpeedGradients[1].getFactor();
  479. } else {
  480. instance.currentLimitSpeed2 = instance.currentLimitSpeed;
  481. }
  482. }
  483. //Drag
  484. if (this._dragGradients && this._dragGradients.length > 0) {
  485. instance.currentDragGradient = this._dragGradients[0];
  486. instance.currentDrag = instance.currentDragGradient.getFactor();
  487. if (this._dragGradients.length > 1) {
  488. instance.currentDrag2 = this._dragGradients[1].getFactor();
  489. } else {
  490. instance.currentDrag2 = instance.currentDrag;
  491. }
  492. }
  493. //Scale
  494. instance.scale.setValue(randomBetween(this._minScaleX, this._maxScaleX), randomBetween(this._minScaleY, this._maxScaleY));
  495. if (this._sizeGradients && this._sizeGradients.length > 0) {
  496. instance.currentSizeGradient = this._sizeGradients[0];
  497. instance.currentSize = instance.currentSizeGradient.getFactor();
  498. instance.sizeGradientFactor = instance.currentSize;
  499. instance.startSize = randomBetween(this._minSize, this._maxSize);
  500. instance.size = instance.startSize * instance.sizeGradientFactor;
  501. if (this._sizeGradients.length > 1) {
  502. instance.currentSize2 = this._sizeGradients[1].getFactor();
  503. } else {
  504. instance.currentSize2 = instance.currentSize;
  505. }
  506. } else {
  507. instance.size = randomBetween(this._minSize, this._maxSize);
  508. }
  509. //SpriteSheet
  510. if (this.useSpriteSheet) {
  511. instance.startSpriteCellIndex = this._startSpriteCellIndex;
  512. instance.endSpriteCellIndex = this._endSpriteCellIndex;
  513. }
  514. }
  515. protected fetch(u, v, width, height, content) {
  516. u = u * 0.5 + 0.5;
  517. v = v * 0.5 + 0.5;
  518. const wrappedU = (u * width) % width | 0;
  519. const wrappedV = (v * height) % height | 0;
  520. const position = (wrappedU + wrappedV * width) * 4;
  521. return content[position] / 255;
  522. }
  523. /**
  524. * 更新运动过程中粒子实例的各项属性以及子发射器状态。
  525. * @param {Array} instances 粒子实例数组
  526. */
  527. protected updateInstanceProperty(instances) {
  528. var loop = (index) => {
  529. var instance: ParticleInstance = instances[index];
  530. var scaledUpdateSpeed = this._updateSpeed;
  531. var previousAge = instance.age;
  532. instance.age += this._updateSpeed;
  533. if (instance.age > instance.lifeTime) {
  534. var diff = instance.age - previousAge;
  535. var oldDiff = instance.lifeTime - previousAge;
  536. scaledUpdateSpeed = (oldDiff * scaledUpdateSpeed) / diff;
  537. instance.age = instance.lifeTime;
  538. }
  539. this.processInstance(instance);
  540. if (this._particleEmitter.processInstance) {
  541. this._particleEmitter.processInstance(instance, this._updateSpeed);
  542. }
  543. // attached subemitter dynamic position
  544. if (instance.subEmitterMuster) {
  545. instance.subEmitterMuster.forEach((subEmitter) => {
  546. subEmitter.particleSystem.emitterPosition = instance.position.clone();
  547. })
  548. }
  549. if (this.useSpriteSheet) {
  550. instance.updateCellIndex();
  551. }
  552. if (instance.age >= instance.lifeTime) {
  553. this.particleSubEmitter(instance);
  554. if (instance.subEmitterMuster) {
  555. instance.subEmitterMuster.forEach((subEmitter) => {
  556. subEmitter.particleSystem.stop();
  557. })
  558. instance.subEmitterMuster = null;
  559. }
  560. this.recycleParticle(instance);
  561. index--;
  562. }
  563. popIndex = index;
  564. }
  565. var popIndex;
  566. for (var index = 0; index < instances.length; index++) {
  567. loop(index);
  568. index = popIndex;
  569. }
  570. }
  571. /**
  572. * 更新粒子实例的各项属性。
  573. * @param {ParticleInstance} instance 待更新的粒子实例
  574. */
  575. protected processInstance(instance: ParticleInstance) {
  576. var ratio = instance.age / instance.lifeTime;
  577. var scaledUpdateSpeed = this._updateSpeed;
  578. //RampColor
  579. if (this._useRampGradients) {
  580. if (this._colorRemapGradients && this._colorRemapGradients.length > 0) {
  581. BasicGradientMethod.GetCurrentGradient(ratio, this._colorRemapGradients, (currentGradient, nextGradient, lerp) => {
  582. var min = currentGradient.factor + (nextGradient.factor - currentGradient.factor) * lerp;
  583. var max = currentGradient.factor2 + (nextGradient.factor2 - currentGradient.factor2) * lerp;
  584. instance.rampPos.x = min;
  585. instance.rampPos.y = max - min;
  586. })
  587. }
  588. }
  589. //Color
  590. if (this._colorGradients && this._colorGradients.length > 0) {
  591. BasicGradientMethod.GetCurrentGradient(ratio, this._colorGradients, (currentGradient, nextGradient, lerp) => {
  592. if (instance.currentColorGradient != currentGradient) {
  593. instance.currentColor = instance.currentColor2.clone();
  594. nextGradient.getColor(instance.currentColor2);
  595. instance.currentColorGradient = currentGradient;
  596. }
  597. instance.color.x = instance.currentColor.x + (instance.currentColor2.x - instance.currentColor.x) * lerp;
  598. instance.color.y = instance.currentColor.y + (instance.currentColor2.y - instance.currentColor.y) * lerp;
  599. instance.color.z = instance.currentColor.z + (instance.currentColor2.z - instance.currentColor.z) * lerp;
  600. instance.color.w = instance.currentColor.w + (instance.currentColor2.w - instance.currentColor.w) * lerp;
  601. })
  602. } else {
  603. instance.colorStep.scale(scaledUpdateSpeed, this._tempAccColorStep);
  604. instance.color.add(this._tempAccColorStep, instance.color);
  605. if (instance.color.w < 0) {
  606. instance.color.w = 0;
  607. }
  608. if (instance.color.w > 1) {
  609. instance.color.w = 1;
  610. }
  611. }
  612. //Color Alpha
  613. if (this._alphaGradients && this._alphaGradients.length > 0) {
  614. BasicGradientMethod.GetCurrentGradient(ratio, this._alphaGradients, (currentGradient, nextGradient, lerp) => {
  615. if (instance.currentAlphaGradient != currentGradient) {
  616. instance.currentAlpha = instance.currentAlpha2;
  617. instance.currentAlpha2 = nextGradient.getFactor();
  618. instance.currentAlphaGradient = currentGradient;
  619. }
  620. instance.color.w = instance.currentAlpha + (instance.currentAlpha2 - instance.currentAlpha) * lerp;
  621. })
  622. }
  623. //--- Velocity ---//
  624. var speed = instance.speed;
  625. //Speed
  626. if (this._speedScaleGradients && this._speedScaleGradients.length > 0) {
  627. BasicGradientMethod.GetCurrentGradient(ratio, this._speedScaleGradients, (currentGradient, nextGradient, lerp) => {
  628. if (instance.currentSpeedScaleGradient != currentGradient) {
  629. instance.currentSpeedScale = instance.currentSpeedScale2;
  630. instance.currentSpeedScale = nextGradient.getFactor();
  631. instance.currentSpeedScaleGradient = currentGradient;
  632. }
  633. var currentSpeedScale = instance.currentSpeedScale + (instance.currentSpeedScale2 - instance.currentSpeedScale) * lerp;
  634. speed = speed * currentSpeedScale;
  635. })
  636. }
  637. //Limit-speed
  638. if (this._limitSpeedGradients && this._limitSpeedGradients.length > 0) {
  639. BasicGradientMethod.GetCurrentGradient(ratio, this._limitSpeedGradients, (currentGradient, nextGradient, lerp) => {
  640. if (instance.currentLimitSpeedGradient != currentGradient) {
  641. instance.currentLimitSpeed = instance.currentSpeedScale2;
  642. instance.currentLimitSpeed = nextGradient.getFactor();
  643. instance.currentLimitSpeedGradient = currentGradient;
  644. }
  645. var limitSpeed = instance.currentLimitSpeed + (instance.currentLimitSpeed2 - instance.currentLimitSpeed) * lerp;
  646. if (Math.abs(instance.speed) > limitSpeed) {
  647. speed = speed * (1 - this._speedDampenFactor);
  648. }
  649. })
  650. }
  651. //Drag
  652. if (this._dragGradients && this._dragGradients.length > 0) {
  653. BasicGradientMethod.GetCurrentGradient(ratio, this._dragGradients, (currentGradient, nextGradient, lerp) => {
  654. if (instance.currentDragGradient != currentGradient) {
  655. instance.currentDrag = instance.currentSpeedScale2;
  656. instance.currentDrag = nextGradient.getFactor();
  657. instance.currentDragGradient = currentGradient;
  658. }
  659. instance.drag = instance.currentDrag + (instance.currentDrag2 - instance.currentDrag) * lerp;
  660. })
  661. }
  662. var velocity = instance.direction.scale(speed * (1 - instance.drag));
  663. //--- End Velocity ---//
  664. //Angle
  665. instance.angle += instance.angularSpeed * scaledUpdateSpeed;
  666. //Gravity
  667. var scaledGravityDirection = xrFrameSystem.Vector3.createFromNumber(0, -1 * this._gravity, 0);
  668. //Direction
  669. var scaledDirection = velocity.add(scaledGravityDirection).scale(scaledUpdateSpeed);
  670. //Position
  671. instance.position.add(scaledDirection, instance.position);
  672. //Size
  673. if (this._sizeGradients && this._sizeGradients.length > 0) {
  674. BasicGradientMethod.GetCurrentGradient(ratio, this._sizeGradients, (currentGradient, nextGradient, lerp) => {
  675. if (instance.currentSizeGradient != currentGradient) {
  676. instance.currentSize = instance.currentSize2;
  677. instance.currentSize2 = nextGradient.getFactor();
  678. instance.currentSizeGradient = currentGradient;
  679. }
  680. instance.sizeGradientFactor = instance.currentSize + (instance.currentSize2 - instance.currentSize) * lerp;
  681. instance.size = instance.startSize * instance.sizeGradientFactor;
  682. })
  683. }
  684. }
  685. }
  686. xrFrameSystem.registerComponent('custom-particle', CustomParticle)