12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214 |
- import { PointShapeEmitter, SphereShapeEmitter, BoxShapeEmitter } from '../Shape/emitter'
- import { FactorGradient, BasicGradientMethod, ColorGradient } from '../Util/Gradient'
- import { IParticleData, ParticleSchema } from './ParticleInterface'
- const xrFrameSystem = wx.getXrFrameSystem();
- // 注册粒子系统的effect
- xrFrameSystem.registerEffect('custom-particle-effect', scene => scene.createEffect({
- name: "custom-particle-effect",
- properties: [{
- "key": 'u_baseColorFactor',
- "type": 3,
- "default": [1, 1, 1, 1]
- }],
- images: [{
- key: 'u_baseColorMap',
- default: 'white',
- macro: 'WX_USE_BASECOLORMAP'
- }, {
- key: 'u_rampColorMap',
- default: 'white',
- macro: 'WX_USE_RAMPCOLORMAP'
- }],
- defaultRenderQueue: 3000,
- passes: [{
- "renderStates": {
- cullOn: false,
- blendOn: true,
- depthWrite: false
- },
- lightMode: "ForwardBase",
- useMaterialRenderStates: true,
- shaders: [0, 1]
- }],
- shaders: [`#version 100
- precision mediump float;
- uniform highp mat4 u_view;
- uniform highp mat4 u_projection;
- uniform highp mat4 u_world;
-
- attribute vec3 a_position;
- attribute highp vec2 a_texCoord;
- attribute vec3 a_offset;
- attribute vec4 a_color;
- attribute float a_angle;
-
- #ifdef WX_BILLBOARDMODE_STRETCHED
- attribute vec3 a_direction;
- attribute float a_lengthScale;
- #endif
-
- #ifdef WX_USE_RAMPCOLORMAP
- attribute vec4 a_rampPos;
- #endif
-
- #ifdef WX_SPRITESHEET
- attribute vec4 a_cellPosition;
- #endif
-
- varying highp vec2 v_Uv;
- varying highp vec4 v_Color;
-
- #ifdef WX_USE_RAMPCOLORMAP
- varying highp vec4 v_rampData;
- #endif
-
- uniform mat4 u_viewInverse;
-
- #ifdef WX_BILLBOARDMODE_Y
- vec3 rotate(vec3 yaxis,vec3 rotatedOffset) {
- vec3 xaxis=normalize(cross(vec3(0.,1.0,0.),yaxis));
- vec3 zaxis=normalize(cross(yaxis,xaxis));
- vec3 row0=vec3(xaxis.x,xaxis.y,xaxis.z);
- vec3 row1=vec3(yaxis.x,yaxis.y,yaxis.z);
- vec3 row2=vec3(zaxis.x,zaxis.y,zaxis.z);
- mat3 rotMatrix= mat3(row0,row1,row2);
- vec3 alignedOffset=rotMatrix*rotatedOffset;
- return alignedOffset;
- }
- #endif
-
- #ifdef WX_BILLBOARDMODE_STRETCHED
- vec3 rotateAlign(vec3 toCamera, vec3 rotatedOffset) {
- vec3 normalizedToCamera = normalize(toCamera);
- vec3 normalizedCrossVec = normalize(cross(normalize(a_direction), normalizedToCamera));
- vec3 normalizedCrossResult = normalize(cross(normalizedToCamera, normalizedCrossVec)) * a_lengthScale;
- vec3 row0 = normalizedCrossVec;
- vec3 row1 = normalizedCrossResult;
- vec3 row2 = normalizedToCamera;
- mat3 rotMatrix = mat3(row0, row1, row2);
- vec3 alignedOffset = rotMatrix * rotatedOffset;
- return alignedOffset;
- }
- #endif
-
- vec3 extractScale(mat4 matrix){
- vec3 scale;
- scale.x = length(vec4(matrix[0][0],matrix[0][1],matrix[0][2],matrix[0][3]));
- scale.y = length(vec4(matrix[1][0],matrix[1][1],matrix[1][2],matrix[1][3]));
- scale.z = length(vec4(matrix[2][0],matrix[2][1],matrix[2][2],matrix[2][3]));
- return scale;
- }
-
- void main()
- {
- #ifdef WX_SPRITESHEET
- vec2 uvOffset = vec2(a_texCoord.x * a_cellPosition.z ,a_texCoord.y * a_cellPosition.w);
- v_Uv = vec2(a_cellPosition.x, a_cellPosition.y) + uvOffset;
- #else
- v_Uv = a_texCoord;
- #endif
- vec4 localPosition = vec4(a_position, 1.0);
-
- vec4 cameraPosition;
- vec3 rotatedOffset;
- vec3 viewPos;
- v_Color = a_color;
-
- #ifdef WX_BILLBOARDMODE_Y
- rotatedOffset.x = a_offset.x * cos(a_angle) - a_offset.y * sin(a_angle);
- rotatedOffset.z = a_offset.x * sin(a_angle) + a_offset.y * cos(a_angle);
- rotatedOffset.y = 0.0;
- vec3 yaxis = a_position - vec3(u_viewInverse[3][0], u_viewInverse[3][1], u_viewInverse[3][2]);
- yaxis.y = 0.0;
- vec3 alignedOffset = rotate(yaxis, rotatedOffset);
- cameraPosition = u_view * u_world * vec4(localPosition.xyz + alignedOffset.xyz, 1.0);
- viewPos = cameraPosition.xyz;
- #elif defined(WX_BILLBOARDMODE_STRETCHED)
- rotatedOffset.x = a_offset.x * cos(a_angle) - a_offset.y * sin(a_angle);
- rotatedOffset.y = a_offset.x * sin(a_angle) + a_offset.y * cos(a_angle);
- rotatedOffset.z = 0.0;
- vec3 toCamera = a_position - vec3(u_viewInverse[3][0], u_viewInverse[3][1], u_viewInverse[3][2]);
- vec3 alignedOffset = rotateAlign(toCamera, rotatedOffset);
- cameraPosition = u_view * u_world * vec4(localPosition.xyz + alignedOffset.xyz, 1.0);
- viewPos = cameraPosition.xyz;
- #elif defined(WX_BILLBOARD)
- vec3 scale = extractScale(u_world);
- rotatedOffset.x = (a_offset.x * cos(a_angle) - a_offset.y * sin(a_angle)) * scale.x;
- rotatedOffset.y = (a_offset.x * sin(a_angle) + a_offset.y * cos(a_angle)) * scale.y;
- rotatedOffset.z = 0.0;
- cameraPosition = u_view * u_world * localPosition + vec4(rotatedOffset, 1.0);
- viewPos = cameraPosition.xyz;
- #elif defined(WX_RENDERMESH)
- rotatedOffset.x = a_offset.x * cos(a_angle) - a_offset.z * sin(a_angle);
- rotatedOffset.z = a_offset.x * sin(a_angle) + a_offset.z * cos(a_angle);
- rotatedOffset.y = a_offset.y;
- cameraPosition = u_view * u_world * vec4(localPosition.xyz + rotatedOffset.xyz, 1.0);
- viewPos = cameraPosition.xyz;
- #else
- rotatedOffset.x = a_offset.x * cos(a_angle) - a_offset.y * sin(a_angle);
- rotatedOffset.y = a_offset.x * sin(a_angle) + a_offset.y * cos(a_angle);
- rotatedOffset.z = 0.0;
- cameraPosition = u_view * u_world * vec4(localPosition.xyz + rotatedOffset.xyz, 1.0);
- viewPos = cameraPosition.xyz;
- #endif
-
- #ifdef WX_USE_RAMPCOLORMAP
- v_rampData = a_rampPos;
- #endif
- gl_Position = u_projection * vec4(viewPos, 1.0);
- }`,
- `#version 100
- precision mediump float;
- precision highp int;
- varying highp vec2 v_Uv;
- varying highp vec4 v_Color;
- #ifdef WX_USE_RAMPCOLORMAP
- varying highp vec4 v_rampData;
- uniform sampler2D u_rampColorMap;
- #endif
-
- uniform highp vec4 u_baseColorFactor;
-
- #ifdef WX_USE_BASECOLORMAP
- uniform sampler2D u_baseColorMap;
- #endif
-
- void main()
- {
- vec4 baseColor;
- #ifdef WX_USE_BASECOLORMAP
- vec4 textureColor = texture2D(u_baseColorMap, v_Uv) * u_baseColorFactor;
- baseColor = textureColor * v_Color;
- #else
- baseColor = v_Color;
- #endif
-
- #ifdef WX_USE_RAMPCOLORMAP
- float alpha=baseColor.a;
- float remappedIndex=clamp((alpha-v_rampData.x)/v_rampData.y,0.0,1.0);
- vec4 rampColor = texture2D(u_rampColorMap,vec2(1.0-remappedIndex,0.));
- baseColor.rgb *= rampColor.rgb;
- baseColor.a=clamp((alpha*rampColor.a-v_rampData.z)/v_rampData.w,0.0,1.0);
- #endif
-
- #ifdef WX_PP_ACTIVE
- // removeGammaCorrection
- gl_FragData[0] = vec4(pow(baseColor.rgb, vec3(2.2)), baseColor.a);
- #else
- gl_FragData[0] = baseColor;
- #endif
-
- gl_FragData[0] = baseColor;
- }
- `],
- }));
- /**
- * BillBoard渲染模式。
- */
- export const enum BillBoardMode {
- BILLBOARDMODE_DEFAULT = 0,
- BILLBOARDMODE_Y = 1,
- BILLBOARDMODE_STRETCHED = 2
- }
- export default class BasicParticle extends xrFrameSystem.Component<IParticleData> {
- public readonly schema: xrFrameSystem.IComponentSchema = ParticleSchema;
- protected _data: IParticleData;
- // 当前粒子系统所在场景
- protected particleScene: xrFrameSystem.Scene;
- // 当前粒子系统的元素
- protected particleEl: xrFrameSystem.Element;
- // 现有粒子对象池
- protected _instances: ParticleInstance[] = new Array<ParticleInstance>();
- // 粒子对象池
- protected _stockInstances: ParticleInstance[] = new Array<ParticleInstance>();
- // 粒子总容量
- protected _capacity: number = 1;
- // 粒子延时启动的时间
- protected _delay: number = 0;
- // 粒子生命周期的更新速率
- protected _updateSpeed: number = 0.01;
- // 粒子系统的生命周期
- protected _stopDuration: number = 0;
- // 粒子发射速率
- protected _emitRate: number = 10;
- // 重力大小
- protected _gravity: number = 0;
- protected _preWarmCycles: number = 0;
- protected _preWarmStepOffset: number = 5;
- protected _particleEmitterType: string;
- protected _particleEmitter: BasicShapeEmitter = null;
- protected _particleEmitterProperties;
- protected particleStride: number;
- protected particleVertexSize: number;
- protected byteStride: number;
- protected ParticleAttributes;
- protected _burstCount: number = 0;
- protected _burstTime: number = 0;
- // -1 = Infinity
- protected _burstCycle: number = -1;
- // -1 = invalid
- protected _burstInterval: number = 1;
- protected _burstCountTime: number = 0;
- protected _burstCountCycle: number = 0;
- protected _burstCountInterval: number = 0;
- protected _minLifeTime: number = 1;
- protected _maxLifeTime: number = 1;
- protected _minScaleX: number = 1;
- protected _maxScaleX: number = 1;
- protected _minScaleY: number = 1;
- protected _maxScaleY: number = 1;
- protected _minSize: number = 0.3;
- protected _maxSize: number = 0.3;
- protected _minSpeed: number = 1;
- protected _maxSpeed: number = 1;
- protected _particleLengthScale: number = 1;
- // the left edge of color at the begin of particle's life cycle
- protected _startColor: number[] = [1, 1, 1, 1];
- // the right edge of color at the begin of particle's life cycle
- protected _startColor2: number[] = null;
- // the color at the end of particle's life cycle
- protected _endColor: number[] = null;
- protected _sizeGradients;
- protected _alphaGradients;
- protected _colorRemapGradients;
- protected _speedScaleGradients;
- protected _limitSpeedGradients;
- protected _speedDampenFactor: number;
- protected _dragGradients;
- protected _useSpriteSheet: boolean = false;
- protected _startSpriteCellIndex: number = 0;
- protected _endSpriteCellIndex: number = 0;
- protected _useRandomSpriteCellIndex: boolean = false;
- protected _useSpriteCellLoop: boolean = true;
- protected _spriteChangeSpeed: number = 1;
- protected _spriteFrameInfo: xrFrameSystem.Vector4[];
- protected _spriteNameToCellIndex: Map<string, number>;
- protected _textureData: xrFrameSystem.Texture = null;
- protected _atlasObj: xrFrameSystem.Atlas = null;
- protected _atlasTexture: xrFrameSystem.Texture;
- protected _mesh: xrFrameSystem.MeshRendererComponent;
- protected _sourceMaterial: xrFrameSystem.Material;
- protected _material: xrFrameSystem.Material;
- protected _trs: xrFrameSystem.Transform;
- protected _renderMesh: Geometry = null;
- protected _vertexCount: number;
- protected _vertexData: Float32Array;
- protected _indexData: UInt32Array;
- protected _eachIndexSize: number;
- protected _indexSize: number = 0;
- protected _vertexSize: number = 0;
- // 默认,粒子使用billboard, 始终面向相机
- protected _useBillboard: boolean = true;
- protected _useRenderMesh: boolean = false;
- protected _billboardMode: number = BillBoardMode.BILLBOARDMODE_DEFAULT;
- protected _useRampGradients: boolean = false;
- protected _rampGradients;
- protected _rampGradientsTexture: xrFrameSystem.Texture;
- protected _colorGradients;
- protected _vertexLayoutDirty: boolean = false;
- protected _startAngle: number = 0;
- protected _startAngle2: number = 0;
- protected _minAngularSpeed: number = 0;
- protected _maxAngularSpeed: number = 0;
- protected _subEmitters: any[] = null;
- protected _emitterPosition: xrFrameSystem.Vector3 = xrFrameSystem.Vector3.createFromNumber(0, 0, 0);
- get material() {
- return this._material;
- }
- get useBillboard() {
- return this._useBillboard;
- }
- set useBillboard(value) {
- if (this.useBillboard != value) {
- this._useBillboard = value;
- this._vertexLayoutDirty = true;
- }
- }
- get useRampGradients() {
- return this._useRampGradients;
- }
- set useRampGradients(value) {
- if (this._useRampGradients != value) {
- this._useRampGradients = value;
- this._vertexLayoutDirty = true;
- }
- }
- get billboardMode() {
- return this._billboardMode;
- }
- set billboardMode(value) {
- if (this._billboardMode != value) {
- this._billboardMode = value;
- this._vertexLayoutDirty = true;
- }
- }
- get useSpriteSheet() {
- return this._useSpriteSheet;
- }
- set useSpriteSheet(value) {
- if (this._useSpriteSheet != value) {
- this._useSpriteSheet = value;
- this._vertexLayoutDirty = true;
- }
- }
- get useRandomSpriteCellIndex() {
- return this._useRandomSpriteCellIndex;
- }
- get useSpriteCellLoop() {
- return this._useSpriteCellLoop;
- }
- get spriteChangeSpeed() {
- return this._spriteChangeSpeed;
- }
- get emitterPosition() {
- return this._emitterPosition;
- }
- set emitterPosition(value) {
- this._emitterPosition = value;
- }
- /**
- * 设置粒子的顶点属性数据
- */
- protected _parseAttribute() {
- this.ParticleAttributes = [];
- this.ParticleAttributes.push(
- {
- name: "a_position",
- format: xrFrameSystem.EVertexFormat.FLOAT3,
- offset: 0,
- usage: xrFrameSystem.EVertexLayoutUsage.POSITION
- },
- {
- name: "a_texCoord",
- format: xrFrameSystem.EVertexFormat.FLOAT2,
- offset: 12,
- usage: xrFrameSystem.EVertexLayoutUsage.UV0
- },
- {
- name: "a_offset",
- format: xrFrameSystem.EVertexFormat.FLOAT3,
- offset: 20,
- // 自定义用途此处可指定为xrFrameSystem.EVertexLayoutUsage.CUSTOM
- usage: xrFrameSystem.EVertexLayoutUsage.CUSTOM
- },
- {
- name: "a_color",
- format: xrFrameSystem.EVertexFormat.FLOAT4,
- offset: 32,
- usage: xrFrameSystem.EVertexLayoutUsage.COLOR
- },
- {
- name: "a_angle",
- format: xrFrameSystem.EVertexFormat.FLOAT,
- offset: 48,
- usage: xrFrameSystem.EVertexLayoutUsage.CUSTOM
- }
- );
- var count = 52;
- // 根据是否使用billboard,动态增添属性
- if (this._useBillboard && this._billboardMode == BillBoardMode.BILLBOARDMODE_STRETCHED) {
- this.ParticleAttributes.push({
- name: "a_direction",
- format: xrFrameSystem.EVertexFormat.FLOAT3,
- offset: count,
- usage: xrFrameSystem.EVertexLayoutUsage.CUSTOM
- })
- count += 3 * 4;
- this.ParticleAttributes.push({
- name: "a_lengthScale",
- format: xrFrameSystem.EVertexFormat.FLOAT,
- offset: count,
- usage: xrFrameSystem.EVertexLayoutUsage.CUSTOM
- })
- count += 4;
- }
- if (this._useRampGradients) {
- this.ParticleAttributes.push({
- name: "a_rampPos",
- format: xrFrameSystem.EVertexFormat.FLOAT4,
- offset: count,
- usage: xrFrameSystem.EVertexLayoutUsage.CUSTOM
- })
- count += 4 * 4;
- }
- if (this.useSpriteSheet) {
- this.ParticleAttributes.push({
- name: "a_cellPosition",
- format: xrFrameSystem.EVertexFormat.FLOAT4,
- offset: count,
- usage: xrFrameSystem.EVertexLayoutUsage.CUSTOM
- })
- count += 4 * 4;
- }
- // 每一个粒子的顶点属性偏移量
- this.particleStride = count;
- // 每一个属性大小背后的字节偏移量
- this.byteStride = 4;
- // 每一个粒子使用的顶点元素偏移量
- this.particleVertexSize = this.particleStride / this.byteStride;
- }
- /**
- * 设置粒子系统的内置粒子effect。
- */
- protected createMaterial() {
- let newMaterial = null;
- newMaterial = new xrFrameSystem.Material(this.particleScene);
- // 此处初始化指定的custom-particle-effect,因为前面有注册过对应名字的effect
- newMaterial.initByEffect(this.particleScene.assets.getAsset("effect", 'custom-particle-effect'));
- return newMaterial;
- }
- // 注册 Geometry 信息
- public _registerGeometry() {
- // 构建顶点属性布局
- const vl = this.particleScene.createVertexLayout({
- attributes: this.ParticleAttributes,
- stride: this.particleStride
- });
- const vb = new Float32Array(this._vertexData);
- const ib = new Uint16Array(this._indexData);
- this._geometry = this.particleScene.createGeometry(vl, vb, ib);
- // 指定为子网格0号
- this._geometry.addSubMesh(ib.length, 0, 0);
- }
- /**
- * 创建一个点发射器。
- * @param {Vector3} direction1 粒子运动方向左区间
- * @param {Vector3} direction2 粒子运动方向右区间
- * @return {PointShapeEmitter} 点发射器
- */
- public createPointEmitter(direction1: Vector3, direction2: Vector3) {
- var particleEmitter = new PointShapeEmitter();
- particleEmitter.direction = direction1;
- particleEmitter.direction2 = direction2;
- this._particleEmitter = particleEmitter;
- this._particleEmitterType = "PointShape";
- return particleEmitter;
- };
- /**
- * 创建一个箱形发射器。
- * @param {Vector3} direction1 粒子运动方向左区间
- * @param {Vector3} direction2 粒子运动方向右区间
- * @param {Vector3} minEmitBox 粒子生成位置最小允许坐标
- * @param {Vector3} maxEmitBox 粒子生成位置最大允许坐标
- * @return {BoxShapeEmitter} 箱形发射器
- */
- public createBoxEmitter(direction1: Vector3, direction2: Vector3, minEmitBox: Vector3, maxEmitBox: Vector3) {
- var particleEmitter = new BoxShapeEmitter();
- particleEmitter.direction = direction1;
- particleEmitter.direction2 = direction2;
- particleEmitter.minEmitBox = minEmitBox;
- particleEmitter.maxEmitBox = maxEmitBox;
- this._particleEmitter = particleEmitter;
- this._particleEmitterType = "BoxShape";
- return particleEmitter;
- };
- /**
- * 创建一个球形发射器。
- * @param {number} radius 球形半径
- * @param {number} radiusRange 球形区域内的覆盖范围[0-1]
- * @param {number} arc 粒子在球形内生成的角度区间[0-360]
- * @param {number} randomizeDirection 粒子运动方向偏离程度[0-1]
- * @return {SphereShapeEmitter} 球形发射器
- */
- public createSphereEmitter(radius: number, radiusRange: number, arc: number, randomizeDirection: number) {
- var particleEmitter = new SphereShapeEmitter();
- particleEmitter.radius = radius;
- particleEmitter.radiusRange = radiusRange;
- particleEmitter.arc = arc;
- particleEmitter.randomizeDirection = randomizeDirection;
- this._particleEmitter = particleEmitter;
- this._particleEmitterType = "SphereShape";
- return particleEmitter;
- };
- protected _parseProperties(data: IParticleData) {
- var useNoise: boolean = false;
- var useAtlasFrame: boolean = false;
- var atlasFrameArray: string[];
- for (var k in data) {
- var v = data[k]
- switch (k) {
- case 'capacity':
- this._capacity = v;
- break;
- case 'renderMode':
- switch (v) {
- case 'off':
- this.useBillboard = false;
- break;
- case 'default':
- this.useBillboard = true;
- this.billboardMode = BillBoardMode.BILLBOARDMODE_DEFAULT;
- break;
- case 'y':
- this.useBillboard = true;
- this.billboardMode = BillBoardMode.BILLBOARDMODE_Y;
- break;
- case 'stretched':
- this.useBillboard = true;
- this.billboardMode = BillBoardMode.BILLBOARDMODE_STRETCHED;
- break;
- case 'mesh':
- this.useBillboard = false;
- this._useRenderMesh = true;
- break;
- default:
- break;
- }
- break;
- case 'mesh':
- if (v == undefined)
- break;
- this._renderMesh = v;
- break;
- case 'renderModel':
- if (v == undefined)
- break;
- this.processRenderModel(v);
- break;
- case 'delay':
- this._delay = v;
- break;
- case 'burstCount':
- this._burstCount = v;
- break;
- case 'burstTime':
- this._burstTime = v;
- break;
- case 'burstCycle':
- this._burstCycle = v;
- break;
- case 'burstInterval':
- this._burstInterval = v;
- break;
- case 'stopDuration':
- this._stopDuration = v;
- break;
- case 'updateSpeed':
- this._updateSpeed = v;
- break;
- case 'emitRate':
- this._emitRate = v;
- break;
- case 'gravity':
- this._gravity = v;
- break;
- case 'prewarmCycles':
- this._preWarmCycles = v;
- break;
- case 'particleLengthScale':
- this._particleLengthScale = v;
- break;
- case "speedDampen":
- this._speedDampenFactor = v;
- break;
- case "texture":
- if (v == undefined)
- break;
- if (typeof v == 'string') {
- this._textureData = this.particleScene.assets.getAsset<Texture>('texture', v);
- } else {
- this._textureData = v;
- }
- break;
- case "useNoise":
- if (v == undefined)
- break;
- useNoise = v;
- break;
- case 'atlas':
- if (v == undefined)
- break;
- this._useSpriteSheet = true;
- this._startSpriteCellIndex = 0;
- var count = 0;
- this._spriteFrameInfo = new Array();
- this._spriteNameToCellIndex = new Map();
- var value: Atlas = v;
- this._atlasObj = value;
- this._atlasTexture = value.texture;
- for (var k in value.frames) {
- this._spriteNameToCellIndex.set(k, count);
- this._spriteFrameInfo.push(value.getUVST(k));
- count++;
- }
- this._endSpriteCellIndex = count;
- break;
- case 'atlasFrames':
- useAtlasFrame = true;
- atlasFrameArray = v;
- break;
- case "atlasLoop":
- this._useSpriteCellLoop = v;
- break;
- case "atlasSpeed":
- this._spriteChangeSpeed = v;
- break;
- case 'atlasRandom':
- this._useRandomSpriteCellIndex = v;
- break;
- case "angle":
- this._startAngle = this._startAngle2 = v[0];
- if (v[1])
- this._startAngle2 = v[1];
- break;
- case 'lifeTime':
- this._minLifeTime = this._maxLifeTime = v[0];
- if (v[1])
- this._maxLifeTime = v[1];
- break;
- case 'scaleX':
- this._minScaleX = this._maxScaleX = v[0];
- if (v[1])
- this._maxScaleX = v[1];
- break;
- case 'scaleY':
- this._minScaleY = this._maxScaleY = v[0];
- if (v[1])
- this._maxScaleY = v[1];
- break;
- case 'size':
- this._minSize = this._maxSize = v[0];
- if (v[1])
- this._maxSize = v[1];
- break;
- case 'speed':
- this._minSpeed = this._maxSpeed = v[0];
- if (v[1])
- this._maxSpeed = v[1];
- break;
- case 'angularSpeed':
- this._minAngularSpeed = this._maxAngularSpeed = v[0];
- if (v[1])
- this._maxAngularSpeed = v[1];
- break;
- case 'emitterType':
- this._particleEmitterType = v;
- break;
- case 'emitterProps':
- this._particleEmitterProperties = v;
- break;
- case 'emitterPosition':
- this._emitterPosition.x = v[0];
- this._emitterPosition.y = v[1];
- this._emitterPosition.z = v[2];
- break;
- case 'startColor':
- for (var i = 0; i < 4; i++) {
- this._startColor[i] = v[i];
- }
- break;
- case 'sizeChange':
- v.forEach(([key, value]) => {
- this.addSizeGradient(parseFloat(key), parseFloat(value));
- })
- break;
- case 'speedChange':
- v.forEach(([key, value]) => {
- this.addSpeedScaleGradient(parseFloat(key), parseFloat(value));
- })
- break;
- case 'colorChange':
- v.forEach(([key, value]) => {
- var valueArray = value.split(' ')
- this.addColorGradient(parseFloat(key), xrFrameSystem.Vector4.createFromNumber(
- parseFloat(valueArray[0]), parseFloat(valueArray[1]),
- parseFloat(valueArray[2]), parseFloat(valueArray[3])));
- })
- break;
- case 'startColor2':
- this._startColor2 = this._startColor2 || [0, 0, 0, 0];
- for (var i = 0; i < 4; i++) {
- this._startColor2[i] = v[i];
- }
- break;
- case 'endColor':
- this._endColor = this._endColor || [0, 0, 0, 0];
- for (var i = 0; i < 4; i++) {
- this._endColor[i] = v[i];
- }
- break;
- }
- }
- if (useAtlasFrame) {
- if (!this._atlasObj) {
- console.log("未取得图集信息");
- } else {
- var count = 0;
- this._startSpriteCellIndex = 0;
- this._spriteFrameInfo = new Array();
- this._spriteNameToCellIndex = new Map();
- for (var name in this._atlasObj.frames) {
- atlasFrameArray.forEach((v, k) => {
- if (name == v) {
- this._spriteNameToCellIndex.set(name, count);
- this._spriteFrameInfo.push(this._atlasObj.getUVST(name));
- count++;
- }
- })
- }
- this._endSpriteCellIndex = count;
- }
- }
- }
- protected processRenderModel(value){
- for(const mesh of value.model.meshes) {
- this._renderMesh = mesh.subMeshes[0].geometry
- }
- this.useBillboard = false;
- this._useRenderMesh = true;
- }
- protected _chooseEmitterProcess() {
- if (this._particleEmitter != null) {
- return;
- }
- //Add cache to optimize on onUpdate cycle
- else {
- switch (this._particleEmitterType) {
- case "SphereShape":
- this._particleEmitter = new SphereShapeEmitter();
- break;
- case "BoxShape":
- this._particleEmitter = new BoxShapeEmitter();
- break;
- default:
- this._particleEmitter = new PointShapeEmitter();
- break;
- }
- }
- this._particleEmitter.setProperty(this._particleEmitterProperties);
- }
- protected _createVertexBuffers() {
- if (this._useRenderMesh) {
- const layout = this._renderMesh.getVertexLayout();
- const stride = layout.stride;
- const vertexBuffer = this._renderMesh._getRawVertexBuffer();
- this._vertexCount = vertexBuffer .byteLength / stride;
- this._vertexSize = this._capacity * this._vertexCount;
- this._vertexData = new Float32Array(this.particleVertexSize * this._vertexSize);
- } else {
- //*4 是因为每一个粒子面片由上下左右四个点构成
- this._vertexSize = this._capacity * 4;
- // 这里构建顶点数据数组的长度,为顶点属性的元素数乘以顶点总数
- this._vertexData = new Float32Array(this.particleVertexSize * this._vertexSize);
- }
- }
- protected _createIndexBuffer() {
- if (this._useRenderMesh) {
- const indexBuffer = this._renderMesh._getRawIndiceBuffer();
- this._eachIndexSize = indexBuffer.byteLength / 2;
- this._indexSize = this._capacity * this._eachIndexSize;
- this._indexData = new Uint16Array(this._indexSize);
- for (let i = 0; i < this._capacity; i++) {
- var firstIndex = i * this._eachIndexSize;
- for (let j = 0; j < this._eachIndexSize; j++) {
- this._indexData[firstIndex + j] = indexBuffer[j] + i * this._vertexCount;
- }
- }
- }else{
- // 粒子索引数量
- this._indexSize = this._capacity * 6;
- this._indexData = new Uint16Array(this._indexSize);
- for (let i = 0; i < this._capacity; i++) {
- this._indexData[i * 6] = i * 4;
- this._indexData[i * 6 + 1] = i * 4 + 1;
- this._indexData[i * 6 + 2] = i * 4 + 2;
- this._indexData[i * 6 + 3] = i * 4;
- this._indexData[i * 6 + 4] = i * 4 + 2;
- this._indexData[i * 6 + 5] = i * 4 + 3;
- }
- }
- }
- // 创建材质与mesh网络
- protected _createMesh() {
- this._material = this.createMaterial()
- this._mesh = this.particleEl.getComponent(xrFrameSystem.Mesh);
- if (this._mesh == undefined) {
- this._mesh = this.particleEl.addComponent(xrFrameSystem.Mesh, {
- geometry: this._geometry,
- material: this._material,
- meshCount: this._renderMesh ? this._renderMesh.getSubMeshCount() : 1,
- });
- }
- }
- //往顶点数据数组里设置值,分别为四个点设置偏移与uv值
- protected _appendParticleVertices(offset, instance: ParticleInstance = null) {
- if (this._useRenderMesh) {
- const vertexBufferView = this._renderMesh._getRawVertexBuffer();
- const layout = this._renderMesh.vertexLayout;
- const stride = layout.stride;
- for (var i = 0; i < this._vertexCount; i++) {
- const aUV = layout.getConfigByName("a_texCoord");
- const aPosition = layout.getConfigByName("a_position");
- const realStride = stride / 4;
- const posBase = i * realStride + aPosition.offset / 4;
- const uvBase = i * realStride + aUV.offset / 4;
- this._appendParticleVertex(offset++, instance, vertexBufferView[posBase + 0], vertexBufferView[posBase + 1], vertexBufferView[posBase + 2],
- vertexBufferView[uvBase + 0], vertexBufferView[uvBase + 1]);
- }
- }else{
- this._appendParticleVertex(offset++, instance, -1, -1, 0, 0, 1);
- this._appendParticleVertex(offset++, instance, 1, -1, 0, 1, 1);
- this._appendParticleVertex(offset++, instance, 1, 1, 0, 1, 0);
- this._appendParticleVertex(offset++, instance, -1, 1, 0, 0, 0);
- }
- };
- protected _appendParticleVertex(index, instance: ParticleInstance, offsetX, offsetY, offsetZ, u, v) {
- var offset = index * this.particleVertexSize;
- this._vertexData[offset++] = instance.position.x;
- this._vertexData[offset++] = instance.position.y;
- this._vertexData[offset++] = instance.position.z;
- this._vertexData[offset++] = u;
- this._vertexData[offset++] = v;
- //Offset
- this._vertexData[offset++] = offsetX * instance.size * instance.scale.x;
- this._vertexData[offset++] = offsetY * instance.size * instance.scale.y;
- this._vertexData[offset++] = offsetZ * instance.size;
- //Color
- this._vertexData[offset++] = instance.color.x;
- this._vertexData[offset++] = instance.color.y;
- this._vertexData[offset++] = instance.color.z;
- this._vertexData[offset++] = instance.color.w;
- //Rotation
- this._vertexData[offset++] = instance.angle * Math.PI / 180;
- if (this._useBillboard && this._billboardMode == BillBoardMode.BILLBOARDMODE_STRETCHED) {
- this._vertexData[offset++] = instance.direction.x;
- this._vertexData[offset++] = instance.direction.y;
- this._vertexData[offset++] = instance.direction.z;
- this._vertexData[offset++] = this._particleLengthScale;
- }
- //RampColor
- if (this._useRampGradients) {
- this._vertexData[offset++] = instance.rampPos.x;
- this._vertexData[offset++] = instance.rampPos.y;
- this._vertexData[offset++] = 0;
- this._vertexData[offset++] = 1;
- }
- //SpriteSheet
- if (this.useSpriteSheet) {
- var cellIndex = ~~instance.cellIndex;
- this._vertexData[offset++] = this._spriteFrameInfo[cellIndex].z;
- this._vertexData[offset++] = this._spriteFrameInfo[cellIndex].w;
- this._vertexData[offset++] = this._spriteFrameInfo[cellIndex].x;
- this._vertexData[offset++] = this._spriteFrameInfo[cellIndex].y;
- }
- };
- // 更新材质上挂载的effect的属性信息
- protected _setMeshData(material: Material,
- uniforms?: [string, string][], states?: [string, string][]
- ) {
- if (!uniforms && !states) {
- this._material = material;
- } else if (this._sourceMaterial !== material || this._sourceMaterial === this._material) {
- this._material = material.clone();
- }
- if (this._textureData) {
- this._material.setTexture('u_baseColorMap', this._textureData);
- }
- if (this._atlasTexture) {
- this._material.setTexture('u_baseColorMap', this._atlasTexture);
- }
- if (this._useRampGradients) {
- if (this._rampGradientsTexture)
- this._material.setTexture('u_rampColorMap', this._rampGradientsTexture);
- }
- if (this.useSpriteSheet) {
- this._material.setMacro("WX_SPRITESHEET", true);
- } else {
- this._material.setMacro("WX_SPRITESHEET", false);
- }
- if (this._useRenderMesh) {
- this._material.setMacro("WX_RENDERMESH", true);
- } else {
- this._material.setMacro("WX_RENDERMESH", false);
- }
- if (this._useBillboard) {
- this._material.setMacros({ "WX_BILLBOARD": true });
- switch (this._billboardMode) {
- case BillBoardMode.BILLBOARDMODE_Y:
- this._material.setMacros({ "WX_BILLBOARDMODE_Y": true });
- break;
- case BillBoardMode.BILLBOARDMODE_STRETCHED:
- this._material.setMacros({ "WX_BILLBOARDMODE_STRETCHED": true });
- break;
- case BillBoardMode.BILLBOARDMODE_DEFAULT:
- this._material.setMacros({ "WX_BILLBOARDMODE_DEFAULT": true });
- break;
- default:
- break;
- }
- } else {
- this._material.setMacro("WX_BILLBOARD", false);
- this._material.setMacro("WX_BILLBOARDMODE_Y", false);
- this._material.setMacro("WX_BILLBOARDMODE_STRETCHED", false);
- this._material.setMacro("WX_BILLBOARDMODE_DEFAULT", false);
- }
- if (uniforms) {
- this._material._parseUniforms(uniforms);
- }
- if (states) {
- this._material._parseRenderStates(states);
- }
- this._sourceMaterial = material;
- const vb = new Float32Array(this._vertexData);
- const ib = new Uint16Array(this._indexData);
- // 更新顶点与索引信息
- this._mesh.geometry.uploadVertexBuffer(0, vb);
- this._mesh.geometry.uploadIndexBuffer(0, ib);
- }
- /**
- * 添加粒子运动过程中的颜色变化规则。
- * @param {number} gradient 指定所处粒子生命周期的阶段
- * @param {Vector4} color1 指定粒子颜色的左区间
- * @param {Vector4} color2 指定粒子颜色的右区间
- */
- public addColorGradient(gradient: number, color1: Vector4, color2?: Vector4) {
- if (!this._colorGradients) {
- this._colorGradients = [];
- }
- var colorGradient = new ColorGradient(gradient, color1, color2);
- this._colorGradients.push(colorGradient);
- this._colorGradients.sort(function (a, b) {
- if (a.gradient < b.gradient) {
- return -1;
- }
- else if (a.gradient > b.gradient) {
- return 1;
- }
- return 0;
- });
- };
- /**
- * 添加粒子运动过程中的速度变化规则。
- * @param {number} gradient 指定所处粒子生命周期的阶段
- * @param {Vector4} speed 指定粒子速度的左区间
- * @param {Vector4} speed2 指定粒子速度的右区间
- */
- public addSpeedScaleGradient(gradient: number, speed: number, speed2?: number) {
- if (!this._speedScaleGradients) {
- this._speedScaleGradients = [];
- }
- this.addFactorGradient(this._speedScaleGradients, gradient, speed, speed2);
- }
- /**
- * 添加粒子运动过程中的速度限制规则。
- * @param {number} gradient 指定所处粒子生命周期的阶段
- * @param {number} limitSpeed 指定粒子限制速度的左区间
- * @param {number} limitSpeed2 指定粒子限制速度的右区间
- */
- public addLimitSpeedGradient(gradient: number, limitSpeed: number, limitSpeed2?: number) {
- if (!this._limitSpeedGradients) {
- this._limitSpeedGradients = [];
- }
- this.addFactorGradient(this._limitSpeedGradients, gradient, limitSpeed, limitSpeed2);
- }
- /**
- * 添加粒子运动过程中的阻力规则。
- * @param {number} gradient 指定所处粒子生命周期的阶段
- * @param {number} speed 指定粒子受到的阻力大小的左区间[0-1]
- * @param {number} speed2 指定粒子受到的阻力大小的右区间[0-1]
- */
- public addDragGradient(gradient: number, drag: number, drag2?: number) {
- if (!this._dragGradients) {
- this._dragGradients = [];
- }
- this.addFactorGradient(this._dragGradients, gradient, drag, drag2);
- }
- /**
- * 添加粒子运动过程中的透明度变化规则。
- * @param {number} gradient 指定所处粒子生命周期的阶段
- * @param {number} alpha 指定粒子颜色透明度的左区间[0-1]
- * @param {number} alpha2 指定粒子颜色透明度的右区间[0-1]
- */
- public addAlphaGradient(gradient: number, alpha: number, alpha2?: number) {
- if (!this._alphaGradients) {
- this._alphaGradients = [];
- }
- this.addFactorGradient(this._alphaGradients, gradient, alpha, alpha2);
- }
- /**
- * 添加粒子运动过程中的尺寸变化规则。
- * @param {number} gradient 指定所处粒子生命周期的阶段
- * @param {number} size 指定粒子尺寸的左区间
- * @param {number} size2 指定粒子尺寸的右区间
- */
- public addSizeGradient(gradient: number, size: number, size2?: number) {
- if (!this._sizeGradients) {
- this._sizeGradients = [];
- }
- this.addFactorGradient(this._sizeGradients, gradient, size, size2);
- }
- /**
- * 添加粒子运动过程中的透明度变化范围。
- * @param {number} gradient 指定所处粒子生命周期的阶段
- * @param {number} min 指定粒子透明度值的左区间
- * @param {number} max 指定粒子透明度值的右区间
- */
- public addColorRemapGradient(gradient: number, min: number, max?: number) {
- if (!this._colorRemapGradients) {
- this._colorRemapGradients = [];
- }
- this.addFactorGradient(this._colorRemapGradients, gradient, min, max);
- }
- /**
- * 将存储不同时间段相关属性系数的数组按时间点从小到大进行排序。
- * @param {Array} factorGradients 存储不同时间段相关属性系数的数组
- * @param {number} gradient 一般代表粒子所处生命周期的阶段
- * @param {number} factor 左区间值
- * @param {number} factor2 右区间值
- */
- protected addFactorGradient(factorGradients, gradient, factor, factor2) {
- var newGradient = new FactorGradient(gradient, factor, factor2);
- factorGradients.push(newGradient);
- factorGradients.sort(function (a, b) {
- if (a.gradient < b.gradient) {
- return -1;
- }
- else if (a.gradient > b.gradient) {
- return 1;
- }
- return 0;
- });
- }
- /**
- * 添加粒子运动过程中的根据透明度影响的颜色变化规则,将通过颜色变化图纹理进行采样。
- * @param {number} gradient 指定粒子颜色变化图的具体位置,对应具体值应为(1-alpha)
- * @param {number} color 指定该位置的颜色
- */
- public addRampGradient(gradient, color) {
- if (!this._rampGradients) {
- this._rampGradients = [];
- }
- var rampGradient = new Color3Gradient(gradient, color);
- this._rampGradients.push(rampGradient);
- this._rampGradients.sort(function (a, b) {
- if (a.gradient < b.gradient) {
- return -1;
- }
- else if (a.gradient > b.gradient) {
- return 1;
- }
- return 0;
- });
- this.createRampGradientTexture();
- }
- /**
- * 根据颜色变化数组,生成对应的颜色变化纹理
- */
- protected createRampGradientTexture() {
- var data = new Uint8Array(256 * 4);
- var tmpColor: Vector3;
- var loop = (x: number) => {
- var ratio = x / 256;
- BasicGradientMethod.GetCurrentGradient(ratio, this._rampGradients, function (currentGradient, nextGradient, lerp) {
- tmpColor = currentGradient.color.lerp(nextGradient.color, lerp);
- data[x * 4] = tmpColor.x * 255;
- data[x * 4 + 1] = tmpColor.y * 255;
- data[x * 4 + 2] = tmpColor.z * 255;
- data[x * 4 + 3] = 255;
- });
- }
- for (var x = 0; x < 256; x++) {
- loop(x);
- }
- this._rampGradientsTexture = this.particleScene.createTexture({
- width: 256, height: 1,
- source: [data],
- pixelFormat: ETextureFormat.RGBA8
- })
- }
- /**
- * 根据数组进行插值
- */
- protected lerpNumberArrayToVector(vector, numberArray1, numberArray2, step, length = 4) {
- let result: number[] = new Array(length);
- for (var i = 0; i < length; i++)
- result[i] = numberArray1[i] + (numberArray2[i] - numberArray1[i]) * step;
- vector.setValue(...result);
- }
- }
|