/** * @file ParticleSystem2.ts * @description Advanced Particle System with GPU Compute and Visual Editor * PRO-1.4: Professional Editor Features * * Features: * - GPU-accelerated particles (WebGPU Compute) * - Multiple emitter shapes * - Force fields (gravity, wind, vortex, etc.) * - Sub-emitters and trails * - Collision detection * - LOD system * - Visual editor integration */ export type ParticleSimulationSpace = 'local' | 'world'; export type ParticleRenderMode = 'billboard' | 'stretchedBillboard' | 'horizontalBillboard' | 'verticalBillboard' | 'mesh' | 'trail'; export type ParticleBlendMode = 'alpha' | 'additive' | 'multiply' | 'premultiplied'; export type ParticleSortingMode = 'none' | 'byDistance' | 'oldestFirst' | 'youngestFirst'; export type InterpolationMode = 'linear' | 'smooth' | 'step'; export interface CurveKeyframe { time: number; value: number; inTangent: number; outTangent: number; mode: 'auto' | 'free' | 'linear' | 'constant'; } export interface ParticleAnimationCurve { keyframes: CurveKeyframe[]; preWrapMode: 'clamp' | 'loop' | 'pingPong'; postWrapMode: 'clamp' | 'loop' | 'pingPong'; } export interface Gradient { colorKeys: { time: number; color: [number, number, number]; }[]; alphaKeys: { time: number; alpha: number; }[]; mode: 'blend' | 'fixed'; } export type MinMaxCurve = { mode: 'constant'; value: number; } | { mode: 'curve'; curve: ParticleAnimationCurve; multiplier: number; } | { mode: 'randomBetweenTwoConstants'; min: number; max: number; } | { mode: 'randomBetweenTwoCurves'; curveMin: ParticleAnimationCurve; curveMax: ParticleAnimationCurve; multiplier: number; }; export type MinMaxGradient = { mode: 'color'; color: [number, number, number, number]; } | { mode: 'gradient'; gradient: Gradient; } | { mode: 'randomBetweenTwoColors'; colorMin: [number, number, number, number]; colorMax: [number, number, number, number]; } | { mode: 'randomBetweenTwoGradients'; gradientMin: Gradient; gradientMax: Gradient; }; export type MinMaxVector3 = { mode: 'constant'; value: [number, number, number]; } | { mode: 'randomBetweenTwoConstants'; min: [number, number, number]; max: [number, number, number]; }; export type EmitterShape = SphereShape | HemisphereShape | ConeShape | BoxShape | CircleShape | RectangleShape | EdgeShape | MeshShape | SkinnnedMeshShape; export interface SphereShape { type: 'sphere'; radius: number; radiusThickness: number; arc: number; arcMode: 'random' | 'loop' | 'pingPong' | 'burstSpread'; arcSpeed: number; position: [number, number, number]; rotation: [number, number, number]; scale: [number, number, number]; } export interface HemisphereShape { type: 'hemisphere'; radius: number; radiusThickness: number; arc: number; arcMode: 'random' | 'loop' | 'pingPong' | 'burstSpread'; arcSpeed: number; position: [number, number, number]; rotation: [number, number, number]; scale: [number, number, number]; } export interface ConeShape { type: 'cone'; angle: number; radius: number; radiusThickness: number; arc: number; arcMode: 'random' | 'loop' | 'pingPong' | 'burstSpread'; arcSpeed: number; length: number; emitFrom: 'base' | 'volume' | 'shell' | 'volumeShell'; position: [number, number, number]; rotation: [number, number, number]; scale: [number, number, number]; } export interface BoxShape { type: 'box'; emitFrom: 'volume' | 'shell' | 'edge'; position: [number, number, number]; rotation: [number, number, number]; scale: [number, number, number]; } export interface CircleShape { type: 'circle'; radius: number; radiusThickness: number; arc: number; arcMode: 'random' | 'loop' | 'pingPong' | 'burstSpread'; arcSpeed: number; position: [number, number, number]; rotation: [number, number, number]; scale: [number, number, number]; } export interface RectangleShape { type: 'rectangle'; emitFrom: 'vertex' | 'edge' | 'shell'; position: [number, number, number]; rotation: [number, number, number]; scale: [number, number, number]; } export interface EdgeShape { type: 'edge'; radius: number; radiusMode: 'random' | 'loop' | 'pingPong' | 'burstSpread'; radiusSpeed: number; position: [number, number, number]; rotation: [number, number, number]; scale: [number, number, number]; } export interface MeshShape { type: 'mesh'; meshId: string; emitFrom: 'vertex' | 'edge' | 'triangle'; useMeshColors: boolean; normalOffset: number; position: [number, number, number]; rotation: [number, number, number]; scale: [number, number, number]; } export interface SkinnnedMeshShape { type: 'skinnedMesh'; meshId: string; emitFrom: 'vertex' | 'edge' | 'triangle'; useMeshColors: boolean; normalOffset: number; position: [number, number, number]; rotation: [number, number, number]; scale: [number, number, number]; } export type ForceField = GravityField | DirectionalField | VortexField | DragField | TurbulenceField | AttractorField | VectorField; export interface GravityField { type: 'gravity'; strength: number; direction: [number, number, number]; } export interface DirectionalField { type: 'directional'; strength: MinMaxCurve; direction: [number, number, number]; randomize: number; } export interface VortexField { type: 'vortex'; center: [number, number, number]; axis: [number, number, number]; strength: MinMaxCurve; attractionStrength: number; radius: number; } export interface DragField { type: 'drag'; coefficient: MinMaxCurve; multiplyBySize: boolean; multiplyByVelocity: boolean; } export interface TurbulenceField { type: 'turbulence'; strength: MinMaxCurve; frequency: number; scrollSpeed: [number, number, number]; octaves: number; roughness: number; } export interface AttractorField { type: 'attractor'; position: [number, number, number]; strength: MinMaxCurve; radius: number; radiusScale: number; killOnArrive: boolean; } export interface VectorField { type: 'vectorField'; textureId: string; strength: MinMaxCurve; speed: number; attractionSpeed: number; position: [number, number, number]; rotation: [number, number, number]; scale: [number, number, number]; } export interface ParticleCollision { enabled: boolean; type: 'planes' | 'world' | 'depth'; planes: CollisionPlane[]; bounce: MinMaxCurve; lifetimeLoss: MinMaxCurve; minKillSpeed: number; radiusScale: number; dampen: MinMaxCurve; enableDynamicColliders: boolean; colliderForce: number; multiplyByCollisionAngle: boolean; multiplyByParticleSpeed: boolean; multiplyByParticleSize: boolean; sendCollisionMessages: boolean; } export interface CollisionPlane { normal: [number, number, number]; position: [number, number, number]; } export type SubEmitterTrigger = 'birth' | 'collision' | 'death' | 'trigger' | 'manual'; export interface SubEmitter { id: string; systemId: string; trigger: SubEmitterTrigger; probability: number; inheritProperties: { color: boolean; size: boolean; rotation: boolean; lifetime: boolean; duration: boolean; }; emitProbability: number; } export interface ParticleTrail { enabled: boolean; ratio: number; lifetime: MinMaxCurve; minVertexDistance: number; textureMode: 'stretch' | 'tile' | 'distributePerSegment' | 'repeatPerSegment'; worldSpace: boolean; dieWithParticle: boolean; sizeAffectsWidth: boolean; sizeAffectsLifetime: boolean; inheritParticleColor: boolean; colorOverLifetime: MinMaxGradient; widthOverTrail: MinMaxCurve; colorOverTrail: MinMaxGradient; generateLightingData: boolean; shadowBias: number; } export interface TextureSheetAnimation { enabled: boolean; mode: 'grid' | 'sprites'; tilesX: number; tilesY: number; animation: 'wholeSheet' | 'singleRow'; rowIndex: number; rowMode: 'custom' | 'random' | 'meshIndex'; timeMode: 'lifetime' | 'speed' | 'fps'; frameOverTime: MinMaxCurve; startFrame: MinMaxCurve; cycleCount: number; speedRange: [number, number]; fps: number; sprites: { name: string; frame: number; }[]; } export interface ParticleLights { enabled: boolean; ratio: number; randomDistribution: boolean; light: { type: 'point' | 'spot'; color: MinMaxGradient; intensity: MinMaxCurve; range: MinMaxCurve; spotAngle?: number; }; useParticleColor: boolean; sizeAffectsRange: boolean; alphaAffectsIntensity: boolean; maxLights: number; } export interface ParticleNoise { enabled: boolean; separateAxes: boolean; strength: MinMaxCurve; strengthX?: MinMaxCurve; strengthY?: MinMaxCurve; strengthZ?: MinMaxCurve; frequency: number; scrollSpeed: number; damping: boolean; octaves: number; octaveMultiplier: number; octaveScale: number; quality: 'low' | 'medium' | 'high'; remapEnabled: boolean; remapCurve: ParticleAnimationCurve; remapX?: ParticleAnimationCurve; remapY?: ParticleAnimationCurve; remapZ?: ParticleAnimationCurve; positionAmount: MinMaxCurve; rotationAmount: MinMaxCurve; sizeAmount: MinMaxCurve; } export interface ParticleSystemDef { id: string; name: string; main: { duration: number; looping: boolean; prewarm: boolean; startDelay: MinMaxCurve; startLifetime: MinMaxCurve; startSpeed: MinMaxCurve; startSize3D: boolean; startSize: MinMaxCurve; startSizeX?: MinMaxCurve; startSizeY?: MinMaxCurve; startSizeZ?: MinMaxCurve; startRotation3D: boolean; startRotation: MinMaxCurve; startRotationX?: MinMaxCurve; startRotationY?: MinMaxCurve; startRotationZ?: MinMaxCurve; flipRotation: number; startColor: MinMaxGradient; gravityModifier: MinMaxCurve; simulationSpace: ParticleSimulationSpace; simulationSpeed: number; deltaTime: 'scaled' | 'unscaled'; scalingMode: 'hierarchy' | 'local' | 'shape'; playOnAwake: boolean; emitterVelocityMode: 'transform' | 'rigidbody' | 'custom'; maxParticles: number; stopAction: 'none' | 'disable' | 'destroy' | 'callback'; cullingMode: 'automatic' | 'pauseAndCatchUp' | 'pause' | 'alwaysSimulate'; ringBufferMode: 'disabled' | 'pauseUntilReplaced' | 'loopUntilReplaced'; ringBufferLoopRange: [number, number]; }; emission: { enabled: boolean; rateOverTime: MinMaxCurve; rateOverDistance: MinMaxCurve; bursts: EmissionBurst[]; }; shape: EmitterShape; velocityOverLifetime: { enabled: boolean; space: 'local' | 'world'; linear: MinMaxVector3; orbital: MinMaxVector3; offset: MinMaxVector3; radial: MinMaxCurve; speedModifier: MinMaxCurve; }; limitVelocityOverLifetime: { enabled: boolean; separateAxes: boolean; speed: MinMaxCurve; speedX?: MinMaxCurve; speedY?: MinMaxCurve; speedZ?: MinMaxCurve; space: 'local' | 'world'; dampen: number; drag: MinMaxCurve; multiplyDragBySize: boolean; multiplyDragByVelocity: boolean; }; inheritVelocity: { enabled: boolean; mode: 'initial' | 'current'; curve: MinMaxCurve; }; lifetimeByEmitterSpeed: { enabled: boolean; curve: MinMaxCurve; speedRange: [number, number]; }; forceOverLifetime: { enabled: boolean; space: 'local' | 'world'; x: MinMaxCurve; y: MinMaxCurve; z: MinMaxCurve; randomize: boolean; }; colorOverLifetime: { enabled: boolean; color: MinMaxGradient; }; colorBySpeed: { enabled: boolean; color: MinMaxGradient; speedRange: [number, number]; }; sizeOverLifetime: { enabled: boolean; separateAxes: boolean; size: MinMaxCurve; sizeX?: MinMaxCurve; sizeY?: MinMaxCurve; sizeZ?: MinMaxCurve; }; sizeBySpeed: { enabled: boolean; separateAxes: boolean; size: MinMaxCurve; sizeX?: MinMaxCurve; sizeY?: MinMaxCurve; sizeZ?: MinMaxCurve; speedRange: [number, number]; }; rotationOverLifetime: { enabled: boolean; separateAxes: boolean; angularVelocity: MinMaxCurve; angularVelocityX?: MinMaxCurve; angularVelocityY?: MinMaxCurve; angularVelocityZ?: MinMaxCurve; }; rotationBySpeed: { enabled: boolean; separateAxes: boolean; angularVelocity: MinMaxCurve; angularVelocityX?: MinMaxCurve; angularVelocityY?: MinMaxCurve; angularVelocityZ?: MinMaxCurve; speedRange: [number, number]; }; externalForces: { enabled: boolean; multiplier: MinMaxCurve; influenceFilter: 'layerMask' | 'list' | 'listAndLayerMask'; influenceMask: number; forceFields: ForceField[]; }; noise: ParticleNoise; collision: ParticleCollision; triggers: { enabled: boolean; inside: 'ignore' | 'kill' | 'callback'; outside: 'ignore' | 'kill' | 'callback'; enter: 'ignore' | 'kill' | 'callback'; exit: 'ignore' | 'kill' | 'callback'; colliderQueryMode: 'disabled' | 'one' | 'all'; radiusScale: number; }; subEmitters: SubEmitter[]; textureSheetAnimation: TextureSheetAnimation; lights: ParticleLights; trails: ParticleTrail; customData: { enabled: boolean; stream1: { mode: 'disabled' | 'vector' | 'color'; components: number; }; stream2: { mode: 'disabled' | 'vector' | 'color'; components: number; }; }; renderer: { enabled: boolean; renderMode: ParticleRenderMode; material: string; trailMaterial?: string; sortMode: ParticleSortingMode; sortingFudge: number; minParticleSize: number; maxParticleSize: number; cameraVelocityScale: number; velocityScale: number; lengthScale: number; normalDirection: number; shadowCastingMode: 'off' | 'on' | 'twoSided' | 'shadowsOnly'; receiveShadows: boolean; motionVectors: 'cameraMotionOnly' | 'perObjectMotion' | 'forceNoMotion'; lightProbes: 'off' | 'blendProbes' | 'useProxyVolume'; reflectionProbes: 'off' | 'blendProbes' | 'blendProbesAndSkybox' | 'simple'; maskInteraction: 'none' | 'visibleInsideMask' | 'visibleOutsideMask'; pivot: [number, number, number]; flip: [number, number, number]; allowRoll: boolean; freeformStretching: boolean; rotateWithStretchDirection: boolean; mesh?: string; meshes?: string[]; meshDistribution?: 'uniformRandom' | 'nonUniformRandom'; meshWeights?: number[]; enableGPUInstancing: boolean; }; } export interface EmissionBurst { time: number; count: MinMaxCurve; cycles: number; interval: number; probability: number; } export interface Particle { position: Float32Array; velocity: Float32Array; startColor: Float32Array; color: Float32Array; startSize: Float32Array; size: Float32Array; rotation: Float32Array; angularVelocity: Float32Array; startLifetime: number; remainingLifetime: number; normalizedLifetime: number; randomSeed: number; startSpeed: number; axisOfRotation: Float32Array; meshIndex: number; customData1: Float32Array; customData2: Float32Array; } export interface ParticleSystemState { particles: Particle[]; activeCount: number; time: number; isPlaying: boolean; isPaused: boolean; isStopped: boolean; isEmitting: boolean; randomSeed: number; emitCounter: number; distanceTraveled: number; lastPosition: Float32Array; burstStates: BurstState[]; } export interface BurstState { burstIndex: number; cycleCount: number; nextTime: number; } export interface ParticleGPUBuffers { positionBuffer: GPUBuffer | WebGLBuffer; velocityBuffer: GPUBuffer | WebGLBuffer; colorBuffer: GPUBuffer | WebGLBuffer; sizeBuffer: GPUBuffer | WebGLBuffer; rotationBuffer: GPUBuffer | WebGLBuffer; lifetimeBuffer: GPUBuffer | WebGLBuffer; randomBuffer: GPUBuffer | WebGLBuffer; indirectDrawBuffer: GPUBuffer | WebGLBuffer; aliveIndexBuffer: GPUBuffer | WebGLBuffer; deadIndexBuffer: GPUBuffer | WebGLBuffer; counterBuffer: GPUBuffer | WebGLBuffer; } export declare class ParticleSystem2 { private definition; private state; private gpuBuffers?; private useGPU; constructor(def: ParticleSystemDef); private createInitialState; private createDeadParticle; play(): void; pause(): void; stop(clear?: boolean): void; clear(): void; private resetBurstStates; private prewarm; emit(count: number, position?: [number, number, number]): void; private emitSingleParticle; private findDeadParticleIndex; private initializeParticle; private sampleEmitterShape; private sampleSphere; private sampleHemisphere; private sampleCone; private sampleBox; private sampleCircle; simulate(deltaTime: number): void; private processEmission; private updateParticle; private applyForces; private applyForceField; private applyVelocityOverLifetime; private applyForceOverLifetime; private applyLimitVelocityOverLifetime; private applyNoise; private applyColorOverLifetime; private applySizeOverLifetime; private applyRotationOverLifetime; private applyColorBySpeed; private applySizeBySpeed; private applyRotationBySpeed; private handleCollision; private triggerSubEmitters; private evaluateMinMaxCurve; private evaluateAnimationCurve; private handleWrapMode; private evaluateMinMaxGradient; private evaluateGradient; private evaluateMinMaxVector3; private seededRandom; private normalizedTime; get particleCount(): number; get isPlaying(): boolean; get isPaused(): boolean; get isStopped(): boolean; get time(): number; get duration(): number; getParticles(): Particle[]; getDefinition(): ParticleSystemDef; setDefinition(def: ParticleSystemDef): void; } export declare function createDefaultParticleSystem(name: string): ParticleSystemDef; export declare function createParticleSystem(def: ParticleSystemDef): ParticleSystem2; export declare function createFireParticleSystem(): ParticleSystemDef; export declare function createSmokeParticleSystem(): ParticleSystemDef; export declare function createSparkParticleSystem(): ParticleSystemDef;