BasicParticle.ts 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214
  1. import { PointShapeEmitter, SphereShapeEmitter, BoxShapeEmitter } from '../Shape/emitter'
  2. import { FactorGradient, BasicGradientMethod, ColorGradient } from '../Util/Gradient'
  3. import { IParticleData, ParticleSchema } from './ParticleInterface'
  4. const xrFrameSystem = wx.getXrFrameSystem();
  5. // 注册粒子系统的effect
  6. xrFrameSystem.registerEffect('custom-particle-effect', scene => scene.createEffect({
  7. name: "custom-particle-effect",
  8. properties: [{
  9. "key": 'u_baseColorFactor',
  10. "type": 3,
  11. "default": [1, 1, 1, 1]
  12. }],
  13. images: [{
  14. key: 'u_baseColorMap',
  15. default: 'white',
  16. macro: 'WX_USE_BASECOLORMAP'
  17. }, {
  18. key: 'u_rampColorMap',
  19. default: 'white',
  20. macro: 'WX_USE_RAMPCOLORMAP'
  21. }],
  22. defaultRenderQueue: 3000,
  23. passes: [{
  24. "renderStates": {
  25. cullOn: false,
  26. blendOn: true,
  27. depthWrite: false
  28. },
  29. lightMode: "ForwardBase",
  30. useMaterialRenderStates: true,
  31. shaders: [0, 1]
  32. }],
  33. shaders: [`#version 100
  34. precision mediump float;
  35. uniform highp mat4 u_view;
  36. uniform highp mat4 u_projection;
  37. uniform highp mat4 u_world;
  38. attribute vec3 a_position;
  39. attribute highp vec2 a_texCoord;
  40. attribute vec3 a_offset;
  41. attribute vec4 a_color;
  42. attribute float a_angle;
  43. #ifdef WX_BILLBOARDMODE_STRETCHED
  44. attribute vec3 a_direction;
  45. attribute float a_lengthScale;
  46. #endif
  47. #ifdef WX_USE_RAMPCOLORMAP
  48. attribute vec4 a_rampPos;
  49. #endif
  50. #ifdef WX_SPRITESHEET
  51. attribute vec4 a_cellPosition;
  52. #endif
  53. varying highp vec2 v_Uv;
  54. varying highp vec4 v_Color;
  55. #ifdef WX_USE_RAMPCOLORMAP
  56. varying highp vec4 v_rampData;
  57. #endif
  58. uniform mat4 u_viewInverse;
  59. #ifdef WX_BILLBOARDMODE_Y
  60. vec3 rotate(vec3 yaxis,vec3 rotatedOffset) {
  61. vec3 xaxis=normalize(cross(vec3(0.,1.0,0.),yaxis));
  62. vec3 zaxis=normalize(cross(yaxis,xaxis));
  63. vec3 row0=vec3(xaxis.x,xaxis.y,xaxis.z);
  64. vec3 row1=vec3(yaxis.x,yaxis.y,yaxis.z);
  65. vec3 row2=vec3(zaxis.x,zaxis.y,zaxis.z);
  66. mat3 rotMatrix= mat3(row0,row1,row2);
  67. vec3 alignedOffset=rotMatrix*rotatedOffset;
  68. return alignedOffset;
  69. }
  70. #endif
  71. #ifdef WX_BILLBOARDMODE_STRETCHED
  72. vec3 rotateAlign(vec3 toCamera, vec3 rotatedOffset) {
  73. vec3 normalizedToCamera = normalize(toCamera);
  74. vec3 normalizedCrossVec = normalize(cross(normalize(a_direction), normalizedToCamera));
  75. vec3 normalizedCrossResult = normalize(cross(normalizedToCamera, normalizedCrossVec)) * a_lengthScale;
  76. vec3 row0 = normalizedCrossVec;
  77. vec3 row1 = normalizedCrossResult;
  78. vec3 row2 = normalizedToCamera;
  79. mat3 rotMatrix = mat3(row0, row1, row2);
  80. vec3 alignedOffset = rotMatrix * rotatedOffset;
  81. return alignedOffset;
  82. }
  83. #endif
  84. vec3 extractScale(mat4 matrix){
  85. vec3 scale;
  86. scale.x = length(vec4(matrix[0][0],matrix[0][1],matrix[0][2],matrix[0][3]));
  87. scale.y = length(vec4(matrix[1][0],matrix[1][1],matrix[1][2],matrix[1][3]));
  88. scale.z = length(vec4(matrix[2][0],matrix[2][1],matrix[2][2],matrix[2][3]));
  89. return scale;
  90. }
  91. void main()
  92. {
  93. #ifdef WX_SPRITESHEET
  94. vec2 uvOffset = vec2(a_texCoord.x * a_cellPosition.z ,a_texCoord.y * a_cellPosition.w);
  95. v_Uv = vec2(a_cellPosition.x, a_cellPosition.y) + uvOffset;
  96. #else
  97. v_Uv = a_texCoord;
  98. #endif
  99. vec4 localPosition = vec4(a_position, 1.0);
  100. vec4 cameraPosition;
  101. vec3 rotatedOffset;
  102. vec3 viewPos;
  103. v_Color = a_color;
  104. #ifdef WX_BILLBOARDMODE_Y
  105. rotatedOffset.x = a_offset.x * cos(a_angle) - a_offset.y * sin(a_angle);
  106. rotatedOffset.z = a_offset.x * sin(a_angle) + a_offset.y * cos(a_angle);
  107. rotatedOffset.y = 0.0;
  108. vec3 yaxis = a_position - vec3(u_viewInverse[3][0], u_viewInverse[3][1], u_viewInverse[3][2]);
  109. yaxis.y = 0.0;
  110. vec3 alignedOffset = rotate(yaxis, rotatedOffset);
  111. cameraPosition = u_view * u_world * vec4(localPosition.xyz + alignedOffset.xyz, 1.0);
  112. viewPos = cameraPosition.xyz;
  113. #elif defined(WX_BILLBOARDMODE_STRETCHED)
  114. rotatedOffset.x = a_offset.x * cos(a_angle) - a_offset.y * sin(a_angle);
  115. rotatedOffset.y = a_offset.x * sin(a_angle) + a_offset.y * cos(a_angle);
  116. rotatedOffset.z = 0.0;
  117. vec3 toCamera = a_position - vec3(u_viewInverse[3][0], u_viewInverse[3][1], u_viewInverse[3][2]);
  118. vec3 alignedOffset = rotateAlign(toCamera, rotatedOffset);
  119. cameraPosition = u_view * u_world * vec4(localPosition.xyz + alignedOffset.xyz, 1.0);
  120. viewPos = cameraPosition.xyz;
  121. #elif defined(WX_BILLBOARD)
  122. vec3 scale = extractScale(u_world);
  123. rotatedOffset.x = (a_offset.x * cos(a_angle) - a_offset.y * sin(a_angle)) * scale.x;
  124. rotatedOffset.y = (a_offset.x * sin(a_angle) + a_offset.y * cos(a_angle)) * scale.y;
  125. rotatedOffset.z = 0.0;
  126. cameraPosition = u_view * u_world * localPosition + vec4(rotatedOffset, 1.0);
  127. viewPos = cameraPosition.xyz;
  128. #elif defined(WX_RENDERMESH)
  129. rotatedOffset.x = a_offset.x * cos(a_angle) - a_offset.z * sin(a_angle);
  130. rotatedOffset.z = a_offset.x * sin(a_angle) + a_offset.z * cos(a_angle);
  131. rotatedOffset.y = a_offset.y;
  132. cameraPosition = u_view * u_world * vec4(localPosition.xyz + rotatedOffset.xyz, 1.0);
  133. viewPos = cameraPosition.xyz;
  134. #else
  135. rotatedOffset.x = a_offset.x * cos(a_angle) - a_offset.y * sin(a_angle);
  136. rotatedOffset.y = a_offset.x * sin(a_angle) + a_offset.y * cos(a_angle);
  137. rotatedOffset.z = 0.0;
  138. cameraPosition = u_view * u_world * vec4(localPosition.xyz + rotatedOffset.xyz, 1.0);
  139. viewPos = cameraPosition.xyz;
  140. #endif
  141. #ifdef WX_USE_RAMPCOLORMAP
  142. v_rampData = a_rampPos;
  143. #endif
  144. gl_Position = u_projection * vec4(viewPos, 1.0);
  145. }`,
  146. `#version 100
  147. precision mediump float;
  148. precision highp int;
  149. varying highp vec2 v_Uv;
  150. varying highp vec4 v_Color;
  151. #ifdef WX_USE_RAMPCOLORMAP
  152. varying highp vec4 v_rampData;
  153. uniform sampler2D u_rampColorMap;
  154. #endif
  155. uniform highp vec4 u_baseColorFactor;
  156. #ifdef WX_USE_BASECOLORMAP
  157. uniform sampler2D u_baseColorMap;
  158. #endif
  159. void main()
  160. {
  161. vec4 baseColor;
  162. #ifdef WX_USE_BASECOLORMAP
  163. vec4 textureColor = texture2D(u_baseColorMap, v_Uv) * u_baseColorFactor;
  164. baseColor = textureColor * v_Color;
  165. #else
  166. baseColor = v_Color;
  167. #endif
  168. #ifdef WX_USE_RAMPCOLORMAP
  169. float alpha=baseColor.a;
  170. float remappedIndex=clamp((alpha-v_rampData.x)/v_rampData.y,0.0,1.0);
  171. vec4 rampColor = texture2D(u_rampColorMap,vec2(1.0-remappedIndex,0.));
  172. baseColor.rgb *= rampColor.rgb;
  173. baseColor.a=clamp((alpha*rampColor.a-v_rampData.z)/v_rampData.w,0.0,1.0);
  174. #endif
  175. #ifdef WX_PP_ACTIVE
  176. // removeGammaCorrection
  177. gl_FragData[0] = vec4(pow(baseColor.rgb, vec3(2.2)), baseColor.a);
  178. #else
  179. gl_FragData[0] = baseColor;
  180. #endif
  181. gl_FragData[0] = baseColor;
  182. }
  183. `],
  184. }));
  185. /**
  186. * BillBoard渲染模式。
  187. */
  188. export const enum BillBoardMode {
  189. BILLBOARDMODE_DEFAULT = 0,
  190. BILLBOARDMODE_Y = 1,
  191. BILLBOARDMODE_STRETCHED = 2
  192. }
  193. export default class BasicParticle extends xrFrameSystem.Component<IParticleData> {
  194. public readonly schema: xrFrameSystem.IComponentSchema = ParticleSchema;
  195. protected _data: IParticleData;
  196. // 当前粒子系统所在场景
  197. protected particleScene: xrFrameSystem.Scene;
  198. // 当前粒子系统的元素
  199. protected particleEl: xrFrameSystem.Element;
  200. // 现有粒子对象池
  201. protected _instances: ParticleInstance[] = new Array<ParticleInstance>();
  202. // 粒子对象池
  203. protected _stockInstances: ParticleInstance[] = new Array<ParticleInstance>();
  204. // 粒子总容量
  205. protected _capacity: number = 1;
  206. // 粒子延时启动的时间
  207. protected _delay: number = 0;
  208. // 粒子生命周期的更新速率
  209. protected _updateSpeed: number = 0.01;
  210. // 粒子系统的生命周期
  211. protected _stopDuration: number = 0;
  212. // 粒子发射速率
  213. protected _emitRate: number = 10;
  214. // 重力大小
  215. protected _gravity: number = 0;
  216. protected _preWarmCycles: number = 0;
  217. protected _preWarmStepOffset: number = 5;
  218. protected _particleEmitterType: string;
  219. protected _particleEmitter: BasicShapeEmitter = null;
  220. protected _particleEmitterProperties;
  221. protected particleStride: number;
  222. protected particleVertexSize: number;
  223. protected byteStride: number;
  224. protected ParticleAttributes;
  225. protected _burstCount: number = 0;
  226. protected _burstTime: number = 0;
  227. // -1 = Infinity
  228. protected _burstCycle: number = -1;
  229. // -1 = invalid
  230. protected _burstInterval: number = 1;
  231. protected _burstCountTime: number = 0;
  232. protected _burstCountCycle: number = 0;
  233. protected _burstCountInterval: number = 0;
  234. protected _minLifeTime: number = 1;
  235. protected _maxLifeTime: number = 1;
  236. protected _minScaleX: number = 1;
  237. protected _maxScaleX: number = 1;
  238. protected _minScaleY: number = 1;
  239. protected _maxScaleY: number = 1;
  240. protected _minSize: number = 0.3;
  241. protected _maxSize: number = 0.3;
  242. protected _minSpeed: number = 1;
  243. protected _maxSpeed: number = 1;
  244. protected _particleLengthScale: number = 1;
  245. // the left edge of color at the begin of particle's life cycle
  246. protected _startColor: number[] = [1, 1, 1, 1];
  247. // the right edge of color at the begin of particle's life cycle
  248. protected _startColor2: number[] = null;
  249. // the color at the end of particle's life cycle
  250. protected _endColor: number[] = null;
  251. protected _sizeGradients;
  252. protected _alphaGradients;
  253. protected _colorRemapGradients;
  254. protected _speedScaleGradients;
  255. protected _limitSpeedGradients;
  256. protected _speedDampenFactor: number;
  257. protected _dragGradients;
  258. protected _useSpriteSheet: boolean = false;
  259. protected _startSpriteCellIndex: number = 0;
  260. protected _endSpriteCellIndex: number = 0;
  261. protected _useRandomSpriteCellIndex: boolean = false;
  262. protected _useSpriteCellLoop: boolean = true;
  263. protected _spriteChangeSpeed: number = 1;
  264. protected _spriteFrameInfo: xrFrameSystem.Vector4[];
  265. protected _spriteNameToCellIndex: Map<string, number>;
  266. protected _textureData: xrFrameSystem.Texture = null;
  267. protected _atlasObj: xrFrameSystem.Atlas = null;
  268. protected _atlasTexture: xrFrameSystem.Texture;
  269. protected _mesh: xrFrameSystem.MeshRendererComponent;
  270. protected _sourceMaterial: xrFrameSystem.Material;
  271. protected _material: xrFrameSystem.Material;
  272. protected _trs: xrFrameSystem.Transform;
  273. protected _renderMesh: Geometry = null;
  274. protected _vertexCount: number;
  275. protected _vertexData: Float32Array;
  276. protected _indexData: UInt32Array;
  277. protected _eachIndexSize: number;
  278. protected _indexSize: number = 0;
  279. protected _vertexSize: number = 0;
  280. // 默认,粒子使用billboard, 始终面向相机
  281. protected _useBillboard: boolean = true;
  282. protected _useRenderMesh: boolean = false;
  283. protected _billboardMode: number = BillBoardMode.BILLBOARDMODE_DEFAULT;
  284. protected _useRampGradients: boolean = false;
  285. protected _rampGradients;
  286. protected _rampGradientsTexture: xrFrameSystem.Texture;
  287. protected _colorGradients;
  288. protected _vertexLayoutDirty: boolean = false;
  289. protected _startAngle: number = 0;
  290. protected _startAngle2: number = 0;
  291. protected _minAngularSpeed: number = 0;
  292. protected _maxAngularSpeed: number = 0;
  293. protected _subEmitters: any[] = null;
  294. protected _emitterPosition: xrFrameSystem.Vector3 = xrFrameSystem.Vector3.createFromNumber(0, 0, 0);
  295. get material() {
  296. return this._material;
  297. }
  298. get useBillboard() {
  299. return this._useBillboard;
  300. }
  301. set useBillboard(value) {
  302. if (this.useBillboard != value) {
  303. this._useBillboard = value;
  304. this._vertexLayoutDirty = true;
  305. }
  306. }
  307. get useRampGradients() {
  308. return this._useRampGradients;
  309. }
  310. set useRampGradients(value) {
  311. if (this._useRampGradients != value) {
  312. this._useRampGradients = value;
  313. this._vertexLayoutDirty = true;
  314. }
  315. }
  316. get billboardMode() {
  317. return this._billboardMode;
  318. }
  319. set billboardMode(value) {
  320. if (this._billboardMode != value) {
  321. this._billboardMode = value;
  322. this._vertexLayoutDirty = true;
  323. }
  324. }
  325. get useSpriteSheet() {
  326. return this._useSpriteSheet;
  327. }
  328. set useSpriteSheet(value) {
  329. if (this._useSpriteSheet != value) {
  330. this._useSpriteSheet = value;
  331. this._vertexLayoutDirty = true;
  332. }
  333. }
  334. get useRandomSpriteCellIndex() {
  335. return this._useRandomSpriteCellIndex;
  336. }
  337. get useSpriteCellLoop() {
  338. return this._useSpriteCellLoop;
  339. }
  340. get spriteChangeSpeed() {
  341. return this._spriteChangeSpeed;
  342. }
  343. get emitterPosition() {
  344. return this._emitterPosition;
  345. }
  346. set emitterPosition(value) {
  347. this._emitterPosition = value;
  348. }
  349. /**
  350. * 设置粒子的顶点属性数据
  351. */
  352. protected _parseAttribute() {
  353. this.ParticleAttributes = [];
  354. this.ParticleAttributes.push(
  355. {
  356. name: "a_position",
  357. format: xrFrameSystem.EVertexFormat.FLOAT3,
  358. offset: 0,
  359. usage: xrFrameSystem.EVertexLayoutUsage.POSITION
  360. },
  361. {
  362. name: "a_texCoord",
  363. format: xrFrameSystem.EVertexFormat.FLOAT2,
  364. offset: 12,
  365. usage: xrFrameSystem.EVertexLayoutUsage.UV0
  366. },
  367. {
  368. name: "a_offset",
  369. format: xrFrameSystem.EVertexFormat.FLOAT3,
  370. offset: 20,
  371. // 自定义用途此处可指定为xrFrameSystem.EVertexLayoutUsage.CUSTOM
  372. usage: xrFrameSystem.EVertexLayoutUsage.CUSTOM
  373. },
  374. {
  375. name: "a_color",
  376. format: xrFrameSystem.EVertexFormat.FLOAT4,
  377. offset: 32,
  378. usage: xrFrameSystem.EVertexLayoutUsage.COLOR
  379. },
  380. {
  381. name: "a_angle",
  382. format: xrFrameSystem.EVertexFormat.FLOAT,
  383. offset: 48,
  384. usage: xrFrameSystem.EVertexLayoutUsage.CUSTOM
  385. }
  386. );
  387. var count = 52;
  388. // 根据是否使用billboard,动态增添属性
  389. if (this._useBillboard && this._billboardMode == BillBoardMode.BILLBOARDMODE_STRETCHED) {
  390. this.ParticleAttributes.push({
  391. name: "a_direction",
  392. format: xrFrameSystem.EVertexFormat.FLOAT3,
  393. offset: count,
  394. usage: xrFrameSystem.EVertexLayoutUsage.CUSTOM
  395. })
  396. count += 3 * 4;
  397. this.ParticleAttributes.push({
  398. name: "a_lengthScale",
  399. format: xrFrameSystem.EVertexFormat.FLOAT,
  400. offset: count,
  401. usage: xrFrameSystem.EVertexLayoutUsage.CUSTOM
  402. })
  403. count += 4;
  404. }
  405. if (this._useRampGradients) {
  406. this.ParticleAttributes.push({
  407. name: "a_rampPos",
  408. format: xrFrameSystem.EVertexFormat.FLOAT4,
  409. offset: count,
  410. usage: xrFrameSystem.EVertexLayoutUsage.CUSTOM
  411. })
  412. count += 4 * 4;
  413. }
  414. if (this.useSpriteSheet) {
  415. this.ParticleAttributes.push({
  416. name: "a_cellPosition",
  417. format: xrFrameSystem.EVertexFormat.FLOAT4,
  418. offset: count,
  419. usage: xrFrameSystem.EVertexLayoutUsage.CUSTOM
  420. })
  421. count += 4 * 4;
  422. }
  423. // 每一个粒子的顶点属性偏移量
  424. this.particleStride = count;
  425. // 每一个属性大小背后的字节偏移量
  426. this.byteStride = 4;
  427. // 每一个粒子使用的顶点元素偏移量
  428. this.particleVertexSize = this.particleStride / this.byteStride;
  429. }
  430. /**
  431. * 设置粒子系统的内置粒子effect。
  432. */
  433. protected createMaterial() {
  434. let newMaterial = null;
  435. newMaterial = new xrFrameSystem.Material(this.particleScene);
  436. // 此处初始化指定的custom-particle-effect,因为前面有注册过对应名字的effect
  437. newMaterial.initByEffect(this.particleScene.assets.getAsset("effect", 'custom-particle-effect'));
  438. return newMaterial;
  439. }
  440. // 注册 Geometry 信息
  441. public _registerGeometry() {
  442. // 构建顶点属性布局
  443. const vl = this.particleScene.createVertexLayout({
  444. attributes: this.ParticleAttributes,
  445. stride: this.particleStride
  446. });
  447. const vb = new Float32Array(this._vertexData);
  448. const ib = new Uint16Array(this._indexData);
  449. this._geometry = this.particleScene.createGeometry(vl, vb, ib);
  450. // 指定为子网格0号
  451. this._geometry.addSubMesh(ib.length, 0, 0);
  452. }
  453. /**
  454. * 创建一个点发射器。
  455. * @param {Vector3} direction1 粒子运动方向左区间
  456. * @param {Vector3} direction2 粒子运动方向右区间
  457. * @return {PointShapeEmitter} 点发射器
  458. */
  459. public createPointEmitter(direction1: Vector3, direction2: Vector3) {
  460. var particleEmitter = new PointShapeEmitter();
  461. particleEmitter.direction = direction1;
  462. particleEmitter.direction2 = direction2;
  463. this._particleEmitter = particleEmitter;
  464. this._particleEmitterType = "PointShape";
  465. return particleEmitter;
  466. };
  467. /**
  468. * 创建一个箱形发射器。
  469. * @param {Vector3} direction1 粒子运动方向左区间
  470. * @param {Vector3} direction2 粒子运动方向右区间
  471. * @param {Vector3} minEmitBox 粒子生成位置最小允许坐标
  472. * @param {Vector3} maxEmitBox 粒子生成位置最大允许坐标
  473. * @return {BoxShapeEmitter} 箱形发射器
  474. */
  475. public createBoxEmitter(direction1: Vector3, direction2: Vector3, minEmitBox: Vector3, maxEmitBox: Vector3) {
  476. var particleEmitter = new BoxShapeEmitter();
  477. particleEmitter.direction = direction1;
  478. particleEmitter.direction2 = direction2;
  479. particleEmitter.minEmitBox = minEmitBox;
  480. particleEmitter.maxEmitBox = maxEmitBox;
  481. this._particleEmitter = particleEmitter;
  482. this._particleEmitterType = "BoxShape";
  483. return particleEmitter;
  484. };
  485. /**
  486. * 创建一个球形发射器。
  487. * @param {number} radius 球形半径
  488. * @param {number} radiusRange 球形区域内的覆盖范围[0-1]
  489. * @param {number} arc 粒子在球形内生成的角度区间[0-360]
  490. * @param {number} randomizeDirection 粒子运动方向偏离程度[0-1]
  491. * @return {SphereShapeEmitter} 球形发射器
  492. */
  493. public createSphereEmitter(radius: number, radiusRange: number, arc: number, randomizeDirection: number) {
  494. var particleEmitter = new SphereShapeEmitter();
  495. particleEmitter.radius = radius;
  496. particleEmitter.radiusRange = radiusRange;
  497. particleEmitter.arc = arc;
  498. particleEmitter.randomizeDirection = randomizeDirection;
  499. this._particleEmitter = particleEmitter;
  500. this._particleEmitterType = "SphereShape";
  501. return particleEmitter;
  502. };
  503. protected _parseProperties(data: IParticleData) {
  504. var useNoise: boolean = false;
  505. var useAtlasFrame: boolean = false;
  506. var atlasFrameArray: string[];
  507. for (var k in data) {
  508. var v = data[k]
  509. switch (k) {
  510. case 'capacity':
  511. this._capacity = v;
  512. break;
  513. case 'renderMode':
  514. switch (v) {
  515. case 'off':
  516. this.useBillboard = false;
  517. break;
  518. case 'default':
  519. this.useBillboard = true;
  520. this.billboardMode = BillBoardMode.BILLBOARDMODE_DEFAULT;
  521. break;
  522. case 'y':
  523. this.useBillboard = true;
  524. this.billboardMode = BillBoardMode.BILLBOARDMODE_Y;
  525. break;
  526. case 'stretched':
  527. this.useBillboard = true;
  528. this.billboardMode = BillBoardMode.BILLBOARDMODE_STRETCHED;
  529. break;
  530. case 'mesh':
  531. this.useBillboard = false;
  532. this._useRenderMesh = true;
  533. break;
  534. default:
  535. break;
  536. }
  537. break;
  538. case 'mesh':
  539. if (v == undefined)
  540. break;
  541. this._renderMesh = v;
  542. break;
  543. case 'renderModel':
  544. if (v == undefined)
  545. break;
  546. this.processRenderModel(v);
  547. break;
  548. case 'delay':
  549. this._delay = v;
  550. break;
  551. case 'burstCount':
  552. this._burstCount = v;
  553. break;
  554. case 'burstTime':
  555. this._burstTime = v;
  556. break;
  557. case 'burstCycle':
  558. this._burstCycle = v;
  559. break;
  560. case 'burstInterval':
  561. this._burstInterval = v;
  562. break;
  563. case 'stopDuration':
  564. this._stopDuration = v;
  565. break;
  566. case 'updateSpeed':
  567. this._updateSpeed = v;
  568. break;
  569. case 'emitRate':
  570. this._emitRate = v;
  571. break;
  572. case 'gravity':
  573. this._gravity = v;
  574. break;
  575. case 'prewarmCycles':
  576. this._preWarmCycles = v;
  577. break;
  578. case 'particleLengthScale':
  579. this._particleLengthScale = v;
  580. break;
  581. case "speedDampen":
  582. this._speedDampenFactor = v;
  583. break;
  584. case "texture":
  585. if (v == undefined)
  586. break;
  587. if (typeof v == 'string') {
  588. this._textureData = this.particleScene.assets.getAsset<Texture>('texture', v);
  589. } else {
  590. this._textureData = v;
  591. }
  592. break;
  593. case "useNoise":
  594. if (v == undefined)
  595. break;
  596. useNoise = v;
  597. break;
  598. case 'atlas':
  599. if (v == undefined)
  600. break;
  601. this._useSpriteSheet = true;
  602. this._startSpriteCellIndex = 0;
  603. var count = 0;
  604. this._spriteFrameInfo = new Array();
  605. this._spriteNameToCellIndex = new Map();
  606. var value: Atlas = v;
  607. this._atlasObj = value;
  608. this._atlasTexture = value.texture;
  609. for (var k in value.frames) {
  610. this._spriteNameToCellIndex.set(k, count);
  611. this._spriteFrameInfo.push(value.getUVST(k));
  612. count++;
  613. }
  614. this._endSpriteCellIndex = count;
  615. break;
  616. case 'atlasFrames':
  617. useAtlasFrame = true;
  618. atlasFrameArray = v;
  619. break;
  620. case "atlasLoop":
  621. this._useSpriteCellLoop = v;
  622. break;
  623. case "atlasSpeed":
  624. this._spriteChangeSpeed = v;
  625. break;
  626. case 'atlasRandom':
  627. this._useRandomSpriteCellIndex = v;
  628. break;
  629. case "angle":
  630. this._startAngle = this._startAngle2 = v[0];
  631. if (v[1])
  632. this._startAngle2 = v[1];
  633. break;
  634. case 'lifeTime':
  635. this._minLifeTime = this._maxLifeTime = v[0];
  636. if (v[1])
  637. this._maxLifeTime = v[1];
  638. break;
  639. case 'scaleX':
  640. this._minScaleX = this._maxScaleX = v[0];
  641. if (v[1])
  642. this._maxScaleX = v[1];
  643. break;
  644. case 'scaleY':
  645. this._minScaleY = this._maxScaleY = v[0];
  646. if (v[1])
  647. this._maxScaleY = v[1];
  648. break;
  649. case 'size':
  650. this._minSize = this._maxSize = v[0];
  651. if (v[1])
  652. this._maxSize = v[1];
  653. break;
  654. case 'speed':
  655. this._minSpeed = this._maxSpeed = v[0];
  656. if (v[1])
  657. this._maxSpeed = v[1];
  658. break;
  659. case 'angularSpeed':
  660. this._minAngularSpeed = this._maxAngularSpeed = v[0];
  661. if (v[1])
  662. this._maxAngularSpeed = v[1];
  663. break;
  664. case 'emitterType':
  665. this._particleEmitterType = v;
  666. break;
  667. case 'emitterProps':
  668. this._particleEmitterProperties = v;
  669. break;
  670. case 'emitterPosition':
  671. this._emitterPosition.x = v[0];
  672. this._emitterPosition.y = v[1];
  673. this._emitterPosition.z = v[2];
  674. break;
  675. case 'startColor':
  676. for (var i = 0; i < 4; i++) {
  677. this._startColor[i] = v[i];
  678. }
  679. break;
  680. case 'sizeChange':
  681. v.forEach(([key, value]) => {
  682. this.addSizeGradient(parseFloat(key), parseFloat(value));
  683. })
  684. break;
  685. case 'speedChange':
  686. v.forEach(([key, value]) => {
  687. this.addSpeedScaleGradient(parseFloat(key), parseFloat(value));
  688. })
  689. break;
  690. case 'colorChange':
  691. v.forEach(([key, value]) => {
  692. var valueArray = value.split(' ')
  693. this.addColorGradient(parseFloat(key), xrFrameSystem.Vector4.createFromNumber(
  694. parseFloat(valueArray[0]), parseFloat(valueArray[1]),
  695. parseFloat(valueArray[2]), parseFloat(valueArray[3])));
  696. })
  697. break;
  698. case 'startColor2':
  699. this._startColor2 = this._startColor2 || [0, 0, 0, 0];
  700. for (var i = 0; i < 4; i++) {
  701. this._startColor2[i] = v[i];
  702. }
  703. break;
  704. case 'endColor':
  705. this._endColor = this._endColor || [0, 0, 0, 0];
  706. for (var i = 0; i < 4; i++) {
  707. this._endColor[i] = v[i];
  708. }
  709. break;
  710. }
  711. }
  712. if (useAtlasFrame) {
  713. if (!this._atlasObj) {
  714. console.log("未取得图集信息");
  715. } else {
  716. var count = 0;
  717. this._startSpriteCellIndex = 0;
  718. this._spriteFrameInfo = new Array();
  719. this._spriteNameToCellIndex = new Map();
  720. for (var name in this._atlasObj.frames) {
  721. atlasFrameArray.forEach((v, k) => {
  722. if (name == v) {
  723. this._spriteNameToCellIndex.set(name, count);
  724. this._spriteFrameInfo.push(this._atlasObj.getUVST(name));
  725. count++;
  726. }
  727. })
  728. }
  729. this._endSpriteCellIndex = count;
  730. }
  731. }
  732. }
  733. protected processRenderModel(value){
  734. for(const mesh of value.model.meshes) {
  735. this._renderMesh = mesh.subMeshes[0].geometry
  736. }
  737. this.useBillboard = false;
  738. this._useRenderMesh = true;
  739. }
  740. protected _chooseEmitterProcess() {
  741. if (this._particleEmitter != null) {
  742. return;
  743. }
  744. //Add cache to optimize on onUpdate cycle
  745. else {
  746. switch (this._particleEmitterType) {
  747. case "SphereShape":
  748. this._particleEmitter = new SphereShapeEmitter();
  749. break;
  750. case "BoxShape":
  751. this._particleEmitter = new BoxShapeEmitter();
  752. break;
  753. default:
  754. this._particleEmitter = new PointShapeEmitter();
  755. break;
  756. }
  757. }
  758. this._particleEmitter.setProperty(this._particleEmitterProperties);
  759. }
  760. protected _createVertexBuffers() {
  761. if (this._useRenderMesh) {
  762. const layout = this._renderMesh.getVertexLayout();
  763. const stride = layout.stride;
  764. const vertexBuffer = this._renderMesh._getRawVertexBuffer();
  765. this._vertexCount = vertexBuffer .byteLength / stride;
  766. this._vertexSize = this._capacity * this._vertexCount;
  767. this._vertexData = new Float32Array(this.particleVertexSize * this._vertexSize);
  768. } else {
  769. //*4 是因为每一个粒子面片由上下左右四个点构成
  770. this._vertexSize = this._capacity * 4;
  771. // 这里构建顶点数据数组的长度,为顶点属性的元素数乘以顶点总数
  772. this._vertexData = new Float32Array(this.particleVertexSize * this._vertexSize);
  773. }
  774. }
  775. protected _createIndexBuffer() {
  776. if (this._useRenderMesh) {
  777. const indexBuffer = this._renderMesh._getRawIndiceBuffer();
  778. this._eachIndexSize = indexBuffer.byteLength / 2;
  779. this._indexSize = this._capacity * this._eachIndexSize;
  780. this._indexData = new Uint16Array(this._indexSize);
  781. for (let i = 0; i < this._capacity; i++) {
  782. var firstIndex = i * this._eachIndexSize;
  783. for (let j = 0; j < this._eachIndexSize; j++) {
  784. this._indexData[firstIndex + j] = indexBuffer[j] + i * this._vertexCount;
  785. }
  786. }
  787. }else{
  788. // 粒子索引数量
  789. this._indexSize = this._capacity * 6;
  790. this._indexData = new Uint16Array(this._indexSize);
  791. for (let i = 0; i < this._capacity; i++) {
  792. this._indexData[i * 6] = i * 4;
  793. this._indexData[i * 6 + 1] = i * 4 + 1;
  794. this._indexData[i * 6 + 2] = i * 4 + 2;
  795. this._indexData[i * 6 + 3] = i * 4;
  796. this._indexData[i * 6 + 4] = i * 4 + 2;
  797. this._indexData[i * 6 + 5] = i * 4 + 3;
  798. }
  799. }
  800. }
  801. // 创建材质与mesh网络
  802. protected _createMesh() {
  803. this._material = this.createMaterial()
  804. this._mesh = this.particleEl.getComponent(xrFrameSystem.Mesh);
  805. if (this._mesh == undefined) {
  806. this._mesh = this.particleEl.addComponent(xrFrameSystem.Mesh, {
  807. geometry: this._geometry,
  808. material: this._material,
  809. meshCount: this._renderMesh ? this._renderMesh.getSubMeshCount() : 1,
  810. });
  811. }
  812. }
  813. //往顶点数据数组里设置值,分别为四个点设置偏移与uv值
  814. protected _appendParticleVertices(offset, instance: ParticleInstance = null) {
  815. if (this._useRenderMesh) {
  816. const vertexBufferView = this._renderMesh._getRawVertexBuffer();
  817. const layout = this._renderMesh.vertexLayout;
  818. const stride = layout.stride;
  819. for (var i = 0; i < this._vertexCount; i++) {
  820. const aUV = layout.getConfigByName("a_texCoord");
  821. const aPosition = layout.getConfigByName("a_position");
  822. const realStride = stride / 4;
  823. const posBase = i * realStride + aPosition.offset / 4;
  824. const uvBase = i * realStride + aUV.offset / 4;
  825. this._appendParticleVertex(offset++, instance, vertexBufferView[posBase + 0], vertexBufferView[posBase + 1], vertexBufferView[posBase + 2],
  826. vertexBufferView[uvBase + 0], vertexBufferView[uvBase + 1]);
  827. }
  828. }else{
  829. this._appendParticleVertex(offset++, instance, -1, -1, 0, 0, 1);
  830. this._appendParticleVertex(offset++, instance, 1, -1, 0, 1, 1);
  831. this._appendParticleVertex(offset++, instance, 1, 1, 0, 1, 0);
  832. this._appendParticleVertex(offset++, instance, -1, 1, 0, 0, 0);
  833. }
  834. };
  835. protected _appendParticleVertex(index, instance: ParticleInstance, offsetX, offsetY, offsetZ, u, v) {
  836. var offset = index * this.particleVertexSize;
  837. this._vertexData[offset++] = instance.position.x;
  838. this._vertexData[offset++] = instance.position.y;
  839. this._vertexData[offset++] = instance.position.z;
  840. this._vertexData[offset++] = u;
  841. this._vertexData[offset++] = v;
  842. //Offset
  843. this._vertexData[offset++] = offsetX * instance.size * instance.scale.x;
  844. this._vertexData[offset++] = offsetY * instance.size * instance.scale.y;
  845. this._vertexData[offset++] = offsetZ * instance.size;
  846. //Color
  847. this._vertexData[offset++] = instance.color.x;
  848. this._vertexData[offset++] = instance.color.y;
  849. this._vertexData[offset++] = instance.color.z;
  850. this._vertexData[offset++] = instance.color.w;
  851. //Rotation
  852. this._vertexData[offset++] = instance.angle * Math.PI / 180;
  853. if (this._useBillboard && this._billboardMode == BillBoardMode.BILLBOARDMODE_STRETCHED) {
  854. this._vertexData[offset++] = instance.direction.x;
  855. this._vertexData[offset++] = instance.direction.y;
  856. this._vertexData[offset++] = instance.direction.z;
  857. this._vertexData[offset++] = this._particleLengthScale;
  858. }
  859. //RampColor
  860. if (this._useRampGradients) {
  861. this._vertexData[offset++] = instance.rampPos.x;
  862. this._vertexData[offset++] = instance.rampPos.y;
  863. this._vertexData[offset++] = 0;
  864. this._vertexData[offset++] = 1;
  865. }
  866. //SpriteSheet
  867. if (this.useSpriteSheet) {
  868. var cellIndex = ~~instance.cellIndex;
  869. this._vertexData[offset++] = this._spriteFrameInfo[cellIndex].z;
  870. this._vertexData[offset++] = this._spriteFrameInfo[cellIndex].w;
  871. this._vertexData[offset++] = this._spriteFrameInfo[cellIndex].x;
  872. this._vertexData[offset++] = this._spriteFrameInfo[cellIndex].y;
  873. }
  874. };
  875. // 更新材质上挂载的effect的属性信息
  876. protected _setMeshData(material: Material,
  877. uniforms?: [string, string][], states?: [string, string][]
  878. ) {
  879. if (!uniforms && !states) {
  880. this._material = material;
  881. } else if (this._sourceMaterial !== material || this._sourceMaterial === this._material) {
  882. this._material = material.clone();
  883. }
  884. if (this._textureData) {
  885. this._material.setTexture('u_baseColorMap', this._textureData);
  886. }
  887. if (this._atlasTexture) {
  888. this._material.setTexture('u_baseColorMap', this._atlasTexture);
  889. }
  890. if (this._useRampGradients) {
  891. if (this._rampGradientsTexture)
  892. this._material.setTexture('u_rampColorMap', this._rampGradientsTexture);
  893. }
  894. if (this.useSpriteSheet) {
  895. this._material.setMacro("WX_SPRITESHEET", true);
  896. } else {
  897. this._material.setMacro("WX_SPRITESHEET", false);
  898. }
  899. if (this._useRenderMesh) {
  900. this._material.setMacro("WX_RENDERMESH", true);
  901. } else {
  902. this._material.setMacro("WX_RENDERMESH", false);
  903. }
  904. if (this._useBillboard) {
  905. this._material.setMacros({ "WX_BILLBOARD": true });
  906. switch (this._billboardMode) {
  907. case BillBoardMode.BILLBOARDMODE_Y:
  908. this._material.setMacros({ "WX_BILLBOARDMODE_Y": true });
  909. break;
  910. case BillBoardMode.BILLBOARDMODE_STRETCHED:
  911. this._material.setMacros({ "WX_BILLBOARDMODE_STRETCHED": true });
  912. break;
  913. case BillBoardMode.BILLBOARDMODE_DEFAULT:
  914. this._material.setMacros({ "WX_BILLBOARDMODE_DEFAULT": true });
  915. break;
  916. default:
  917. break;
  918. }
  919. } else {
  920. this._material.setMacro("WX_BILLBOARD", false);
  921. this._material.setMacro("WX_BILLBOARDMODE_Y", false);
  922. this._material.setMacro("WX_BILLBOARDMODE_STRETCHED", false);
  923. this._material.setMacro("WX_BILLBOARDMODE_DEFAULT", false);
  924. }
  925. if (uniforms) {
  926. this._material._parseUniforms(uniforms);
  927. }
  928. if (states) {
  929. this._material._parseRenderStates(states);
  930. }
  931. this._sourceMaterial = material;
  932. const vb = new Float32Array(this._vertexData);
  933. const ib = new Uint16Array(this._indexData);
  934. // 更新顶点与索引信息
  935. this._mesh.geometry.uploadVertexBuffer(0, vb);
  936. this._mesh.geometry.uploadIndexBuffer(0, ib);
  937. }
  938. /**
  939. * 添加粒子运动过程中的颜色变化规则。
  940. * @param {number} gradient 指定所处粒子生命周期的阶段
  941. * @param {Vector4} color1 指定粒子颜色的左区间
  942. * @param {Vector4} color2 指定粒子颜色的右区间
  943. */
  944. public addColorGradient(gradient: number, color1: Vector4, color2?: Vector4) {
  945. if (!this._colorGradients) {
  946. this._colorGradients = [];
  947. }
  948. var colorGradient = new ColorGradient(gradient, color1, color2);
  949. this._colorGradients.push(colorGradient);
  950. this._colorGradients.sort(function (a, b) {
  951. if (a.gradient < b.gradient) {
  952. return -1;
  953. }
  954. else if (a.gradient > b.gradient) {
  955. return 1;
  956. }
  957. return 0;
  958. });
  959. };
  960. /**
  961. * 添加粒子运动过程中的速度变化规则。
  962. * @param {number} gradient 指定所处粒子生命周期的阶段
  963. * @param {Vector4} speed 指定粒子速度的左区间
  964. * @param {Vector4} speed2 指定粒子速度的右区间
  965. */
  966. public addSpeedScaleGradient(gradient: number, speed: number, speed2?: number) {
  967. if (!this._speedScaleGradients) {
  968. this._speedScaleGradients = [];
  969. }
  970. this.addFactorGradient(this._speedScaleGradients, gradient, speed, speed2);
  971. }
  972. /**
  973. * 添加粒子运动过程中的速度限制规则。
  974. * @param {number} gradient 指定所处粒子生命周期的阶段
  975. * @param {number} limitSpeed 指定粒子限制速度的左区间
  976. * @param {number} limitSpeed2 指定粒子限制速度的右区间
  977. */
  978. public addLimitSpeedGradient(gradient: number, limitSpeed: number, limitSpeed2?: number) {
  979. if (!this._limitSpeedGradients) {
  980. this._limitSpeedGradients = [];
  981. }
  982. this.addFactorGradient(this._limitSpeedGradients, gradient, limitSpeed, limitSpeed2);
  983. }
  984. /**
  985. * 添加粒子运动过程中的阻力规则。
  986. * @param {number} gradient 指定所处粒子生命周期的阶段
  987. * @param {number} speed 指定粒子受到的阻力大小的左区间[0-1]
  988. * @param {number} speed2 指定粒子受到的阻力大小的右区间[0-1]
  989. */
  990. public addDragGradient(gradient: number, drag: number, drag2?: number) {
  991. if (!this._dragGradients) {
  992. this._dragGradients = [];
  993. }
  994. this.addFactorGradient(this._dragGradients, gradient, drag, drag2);
  995. }
  996. /**
  997. * 添加粒子运动过程中的透明度变化规则。
  998. * @param {number} gradient 指定所处粒子生命周期的阶段
  999. * @param {number} alpha 指定粒子颜色透明度的左区间[0-1]
  1000. * @param {number} alpha2 指定粒子颜色透明度的右区间[0-1]
  1001. */
  1002. public addAlphaGradient(gradient: number, alpha: number, alpha2?: number) {
  1003. if (!this._alphaGradients) {
  1004. this._alphaGradients = [];
  1005. }
  1006. this.addFactorGradient(this._alphaGradients, gradient, alpha, alpha2);
  1007. }
  1008. /**
  1009. * 添加粒子运动过程中的尺寸变化规则。
  1010. * @param {number} gradient 指定所处粒子生命周期的阶段
  1011. * @param {number} size 指定粒子尺寸的左区间
  1012. * @param {number} size2 指定粒子尺寸的右区间
  1013. */
  1014. public addSizeGradient(gradient: number, size: number, size2?: number) {
  1015. if (!this._sizeGradients) {
  1016. this._sizeGradients = [];
  1017. }
  1018. this.addFactorGradient(this._sizeGradients, gradient, size, size2);
  1019. }
  1020. /**
  1021. * 添加粒子运动过程中的透明度变化范围。
  1022. * @param {number} gradient 指定所处粒子生命周期的阶段
  1023. * @param {number} min 指定粒子透明度值的左区间
  1024. * @param {number} max 指定粒子透明度值的右区间
  1025. */
  1026. public addColorRemapGradient(gradient: number, min: number, max?: number) {
  1027. if (!this._colorRemapGradients) {
  1028. this._colorRemapGradients = [];
  1029. }
  1030. this.addFactorGradient(this._colorRemapGradients, gradient, min, max);
  1031. }
  1032. /**
  1033. * 将存储不同时间段相关属性系数的数组按时间点从小到大进行排序。
  1034. * @param {Array} factorGradients 存储不同时间段相关属性系数的数组
  1035. * @param {number} gradient 一般代表粒子所处生命周期的阶段
  1036. * @param {number} factor 左区间值
  1037. * @param {number} factor2 右区间值
  1038. */
  1039. protected addFactorGradient(factorGradients, gradient, factor, factor2) {
  1040. var newGradient = new FactorGradient(gradient, factor, factor2);
  1041. factorGradients.push(newGradient);
  1042. factorGradients.sort(function (a, b) {
  1043. if (a.gradient < b.gradient) {
  1044. return -1;
  1045. }
  1046. else if (a.gradient > b.gradient) {
  1047. return 1;
  1048. }
  1049. return 0;
  1050. });
  1051. }
  1052. /**
  1053. * 添加粒子运动过程中的根据透明度影响的颜色变化规则,将通过颜色变化图纹理进行采样。
  1054. * @param {number} gradient 指定粒子颜色变化图的具体位置,对应具体值应为(1-alpha)
  1055. * @param {number} color 指定该位置的颜色
  1056. */
  1057. public addRampGradient(gradient, color) {
  1058. if (!this._rampGradients) {
  1059. this._rampGradients = [];
  1060. }
  1061. var rampGradient = new Color3Gradient(gradient, color);
  1062. this._rampGradients.push(rampGradient);
  1063. this._rampGradients.sort(function (a, b) {
  1064. if (a.gradient < b.gradient) {
  1065. return -1;
  1066. }
  1067. else if (a.gradient > b.gradient) {
  1068. return 1;
  1069. }
  1070. return 0;
  1071. });
  1072. this.createRampGradientTexture();
  1073. }
  1074. /**
  1075. * 根据颜色变化数组,生成对应的颜色变化纹理
  1076. */
  1077. protected createRampGradientTexture() {
  1078. var data = new Uint8Array(256 * 4);
  1079. var tmpColor: Vector3;
  1080. var loop = (x: number) => {
  1081. var ratio = x / 256;
  1082. BasicGradientMethod.GetCurrentGradient(ratio, this._rampGradients, function (currentGradient, nextGradient, lerp) {
  1083. tmpColor = currentGradient.color.lerp(nextGradient.color, lerp);
  1084. data[x * 4] = tmpColor.x * 255;
  1085. data[x * 4 + 1] = tmpColor.y * 255;
  1086. data[x * 4 + 2] = tmpColor.z * 255;
  1087. data[x * 4 + 3] = 255;
  1088. });
  1089. }
  1090. for (var x = 0; x < 256; x++) {
  1091. loop(x);
  1092. }
  1093. this._rampGradientsTexture = this.particleScene.createTexture({
  1094. width: 256, height: 1,
  1095. source: [data],
  1096. pixelFormat: ETextureFormat.RGBA8
  1097. })
  1098. }
  1099. /**
  1100. * 根据数组进行插值
  1101. */
  1102. protected lerpNumberArrayToVector(vector, numberArray1, numberArray2, step, length = 4) {
  1103. let result: number[] = new Array(length);
  1104. for (var i = 0; i < length; i++)
  1105. result[i] = numberArray1[i] + (numberArray2[i] - numberArray1[i]) * step;
  1106. vector.setValue(...result);
  1107. }
  1108. }