ParticleSystem.js 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968
  1. /**
  2. * @author Mark Kellogg - http://www.github.com/mkkellogg
  3. */
  4. //=======================================
  5. // Particle system
  6. //=======================================
  7. THREE.Particles = THREE.Particles || {};
  8. THREE.Particles.ParticleSystem = function() {
  9. THREE.Object3D.call( this );
  10. this.zSort = false;
  11. this.simulateInLocalSpace = true;
  12. this.matrixAutoUpdate = true;
  13. this.releaseAtOnce = false;
  14. this.releaseAtOnceCount = 0.0;
  15. this.hasInitialReleaseOccurred = false;
  16. this.isActive = false;
  17. this.atlasInitializer = THREE.Particles.ParticleSystem.DefaultInitializer;
  18. this.colorInitializer = THREE.Particles.ParticleSystem.DefaultInitializer;
  19. this.alphaInitializer = THREE.Particles.ParticleSystem.DefaultInitializer;
  20. this.sizeInitializer = THREE.Particles.ParticleSystem.DefaultInitializer;
  21. this.atlasUpdater = THREE.Particles.ParticleSystem.DefaultUpdater;
  22. this.colorUpdater = THREE.Particles.ParticleSystem.DefaultUpdater;
  23. this.alphaUpdater = THREE.Particles.ParticleSystem.DefaultUpdater;
  24. this.sizeUpdater = THREE.Particles.ParticleSystem.DefaultUpdater;
  25. // Particle position and position modifiers (velocity and acceleration)
  26. this.positionUpdater = THREE.Particles.ParticleSystem.DefaultPositionUpdater;
  27. this.velocityUpdater = THREE.Particles.ParticleSystem.DefaultVelocityUpdater;
  28. this.accelerationUpdater = THREE.Particles.ParticleSystem.DefaultUpdater;
  29. this.positionInitializer = THREE.Particles.ParticleSystem.DefaultInitializer;
  30. this.velocityInitializer = THREE.Particles.ParticleSystem.DefaultInitializer;
  31. this.accelerationInitializer = THREE.Particles.ParticleSystem.DefaultInitializer;
  32. // Particle rotation and rotation modifiers (rotational speed and rotational acceleration)
  33. this.rotationUpdater = THREE.Particles.ParticleSystem.DefaultRotationUpdater;
  34. this.rotationalSpeedUpdater = THREE.Particles.ParticleSystem.DefaultRotationalSpeedUpdater;
  35. this.rotationalAccelerationUpdater = THREE.Particles.ParticleSystem.DefaultUpdater;
  36. this.rotationInitializer = THREE.Particles.ParticleSystem.DefaultInitializer;
  37. this.rotationalSpeedInitializer = THREE.Particles.ParticleSystem.DefaultInitializer;
  38. this.rotationalAccelerationInitializer = THREE.Particles.ParticleSystem.DefaultInitializer;
  39. this.particleReleaseRate = 100;
  40. this.particleLifeSpan = 1.0;
  41. this.averageParticleLifeSpan = 1.0;
  42. this.calculateAverageParticleLifeSpan();
  43. this.calculateMaxParticleCount();
  44. this.liveParticleCount = 0;
  45. this.deadParticleCount = 0;
  46. this.liveParticleArray = [];
  47. this.deadParticleArray = [];
  48. this._tempParticleArray = [];
  49. this.timeSinceLastEmit = 0.0;
  50. this.emitting = true;
  51. this.age = 0.0;
  52. this.lifespan = 0;
  53. // temporary storage
  54. this._tempVector3 = new THREE.Vector3();
  55. this._tempQuaternion = new THREE.Quaternion();
  56. this._tempMatrix4 = new THREE.Matrix4();
  57. }
  58. THREE.Particles.ParticleSystem.prototype = Object.create( THREE.Object3D.prototype );
  59. THREE.Particles.ParticleSystem.prototype.constructor = THREE.Particles.ParticleSystem;
  60. //=======================================
  61. // Particle system default shader
  62. //=======================================
  63. THREE.Particles.ParticleSystem.Shader = THREE.Particles.ParticleSystem.Shader || {};
  64. THREE.Particles.ParticleSystem.Shader.VertexVars = [
  65. "attribute vec4 customColor;",
  66. "attribute vec2 size;",
  67. "attribute float rotation;",
  68. "attribute float customIndex;",
  69. "varying vec2 vUV;",
  70. "varying vec4 vColor;",
  71. "uniform vec3 cameraaxisx;",
  72. "uniform vec3 cameraaxisy;",
  73. "uniform vec3 cameraaxisz;",
  74. ].join( "\n" );
  75. THREE.Particles.ParticleSystem.Shader.FragmentVars = [
  76. "varying vec2 vUV;",
  77. "varying vec4 vColor;",
  78. "uniform sampler2D texture;",
  79. ].join( "\n" );
  80. THREE.Particles.ParticleSystem.Shader.ParticleVertexQuadPositionFunction = [
  81. "vec4 getQuadPosition() {",
  82. "vec3 axisX = cameraaxisx;",
  83. "vec3 axisY = cameraaxisy;",
  84. "vec3 axisZ = cameraaxisz;",
  85. "axisX *= cos( rotation );",
  86. "axisY *= sin( rotation );",
  87. "axisX += axisY;",
  88. "axisY = cross( axisZ, axisX );",
  89. "vec3 edge = vec3( 2.0, customIndex, 3.0 );",
  90. "vec3 test = vec3( customIndex, 0.5, customIndex );",
  91. "vec3 result = step( edge, test );",
  92. "float xFactor = -1.0 + ( result.x * 2.0 );",
  93. "float yFactor = -1.0 + ( result.y * 2.0 ) + ( result.z * 2.0 );",
  94. "axisX *= size.x * xFactor;",
  95. "axisY *= size.y * yFactor;",
  96. "return ( modelMatrix * vec4( position, 1.0 ) ) + vec4( axisX + axisY, 0.0 );",
  97. "}",
  98. ].join( "\n" );
  99. THREE.Particles.ParticleSystem.Shader.VertexShader = [
  100. THREE.Particles.ParticleSystem.Shader.VertexVars,
  101. THREE.Particles.ParticleSystem.Shader.ParticleVertexQuadPositionFunction,
  102. "void main() { ",
  103. "vColor = customColor;",
  104. "vUV = uv;",
  105. "vec4 quadPos = getQuadPosition();",
  106. "gl_Position = projectionMatrix * viewMatrix * quadPos;",
  107. "}"
  108. ].join( "\n" );
  109. THREE.Particles.ParticleSystem.Shader.FragmentShader = [
  110. THREE.Particles.ParticleSystem.Shader.FragmentVars,
  111. "void main() { ",
  112. "vec4 textureColor = texture2D( texture, vUV );",
  113. "gl_FragColor = vColor * textureColor;",
  114. "}"
  115. ].join( "\n" );
  116. THREE.Particles.ParticleSystem.createMaterial = function( vertexShader, fragmentShader, customUniforms ) {
  117. customUniforms = customUniforms || {};
  118. customUniforms.texture = { type: "t", value: null };
  119. customUniforms.cameraaxisx = { type: "v3", value: new THREE.Vector3() };
  120. customUniforms.cameraaxisy = { type: "v3", value: new THREE.Vector3() };
  121. customUniforms.cameraaxisz = { type: "v3", value: new THREE.Vector3() };
  122. vertexShader = vertexShader || THREE.Particles.ParticleSystem.Shader.VertexShader;
  123. fragmentShader = fragmentShader || THREE.Particles.ParticleSystem.Shader.FragmentShader;
  124. return new THREE.ShaderMaterial(
  125. {
  126. uniforms: customUniforms,
  127. vertexShader: vertexShader,
  128. fragmentShader: fragmentShader,
  129. transparent: true,
  130. alphaTest: 0.5,
  131. blending: THREE.NormalBlending,
  132. depthTest: true,
  133. depthWrite: false
  134. } );
  135. }
  136. //=======================================
  137. // Particle system functions
  138. //=======================================
  139. THREE.Particles.ParticleSystem.prototype.calculateAverageParticleLifeSpan = function() {
  140. var total = 0.0;
  141. for ( var i = 0; i < 100; i ++ ) {
  142. total += this.particleLifeSpan;
  143. }
  144. total /= 100.0;
  145. this.averageParticleLifeSpan = total;
  146. }
  147. THREE.Particles.ParticleSystem.prototype.calculateMaxParticleCount = function() {
  148. if ( this.releaseAtOnce ) {
  149. this.maxParticleCount = this.releaseAtOnceCount;
  150. } else {
  151. var minLifeSpan = this.particleLifeSpan;
  152. if ( this.lifespan != 0 && this.lifespan < minLifeSpan ) minLifeSpan = this.lifespan;
  153. this.maxParticleCount = Math.max( this.particleReleaseRate * minLifeSpan * 2, 1.0 );
  154. }
  155. this.vertexCount = this.maxParticleCount * THREE.Particles.Constants.VerticesPerParticle;
  156. }
  157. THREE.Particles.ParticleSystem.prototype.initializeGeometry = function() {
  158. this.particleGeometry = new THREE.BufferGeometry();
  159. var particleColor = new Float32Array( this.vertexCount * 4 );
  160. var particleAlpha = new Float32Array( this.vertexCount );
  161. var positions = new Float32Array( this.vertexCount * 3 );
  162. var uvs = new Float32Array( this.vertexCount * 2 );
  163. var size = new Float32Array( this.vertexCount * 2 );
  164. var rotation = new Float32Array( this.vertexCount );
  165. var index = new Float32Array( this.vertexCount );
  166. var particleColorAttribute = new THREE.BufferAttribute( particleColor, 4 );
  167. particleColorAttribute.setDynamic( true );
  168. this.particleGeometry.addAttribute( 'customColor', particleColorAttribute );
  169. var positionAttribute = new THREE.BufferAttribute( positions, 3 );
  170. positionAttribute.setDynamic( true );
  171. this.particleGeometry.addAttribute( 'position', positionAttribute );
  172. var uvAttribute = new THREE.BufferAttribute( uvs, 2 );
  173. uvAttribute.setDynamic( true );
  174. this.particleGeometry.addAttribute( 'uv', uvAttribute );
  175. var sizeAttribute = new THREE.BufferAttribute( size, 2 );
  176. sizeAttribute.setDynamic( true );
  177. this.particleGeometry.addAttribute( 'size', sizeAttribute );
  178. var rotationAttribute = new THREE.BufferAttribute( rotation, 1 );
  179. rotationAttribute.setDynamic( true );
  180. this.particleGeometry.addAttribute( 'rotation', rotationAttribute );
  181. var indexAttribute = new THREE.BufferAttribute( index, 1 );
  182. indexAttribute.setDynamic( true );
  183. this.particleGeometry.addAttribute( 'customIndex', indexAttribute );
  184. }
  185. THREE.Particles.ParticleSystem.prototype.initializeMaterial = function( material ) {
  186. this.particleMaterial = material;
  187. }
  188. THREE.Particles.ParticleSystem.prototype.initializeMesh = function() {
  189. this.destroyMesh();
  190. this.particleMesh = new THREE.Mesh( this.particleGeometry, this.particleMaterial );
  191. this.particleMesh.dynamic = true;
  192. this.particleMesh.matrixAutoUpdate = false;
  193. }
  194. THREE.Particles.ParticleSystem.prototype.destroyMesh = function() {
  195. if ( this.particleMesh ) {
  196. scene.remove( this.particleMesh );
  197. this.particleMesh = undefined;
  198. }
  199. }
  200. THREE.Particles.ParticleSystem.prototype.initializeParticleArray = function() {
  201. for ( var i = 0; i < this.maxParticleCount; i ++ ) {
  202. var particle = this.createParticle();
  203. this.initializeParticle( particle );
  204. this.deadParticleArray[ i ] = particle;
  205. }
  206. this.liveParticleCount = 0;
  207. this.deadParticleCount = this.maxParticleCount;
  208. this.liveParticleArray.length = this.liveParticleCount;
  209. this.deadParticleArray.length = this.deadParticleCount;
  210. }
  211. THREE.Particles.ParticleSystem.prototype.mergeParameters = function( parameters ) {
  212. for ( var key in parameters ) {
  213. this[ key ] = parameters[ key ];
  214. }
  215. }
  216. THREE.Particles.ParticleSystem.prototype.bindInitializer = function( name, modifier ) {
  217. if ( name ) {
  218. this[ name + "Initializer" ] = modifier;
  219. }
  220. }
  221. THREE.Particles.ParticleSystem.prototype.bindUpdater = function( name, modifier ) {
  222. if ( name ) {
  223. this[ name + "Updater" ] = modifier;
  224. }
  225. }
  226. THREE.Particles.ParticleSystem.prototype.bindModifier = function( name, modifier ) {
  227. this.bindInitializer( name, modifier );
  228. this.bindUpdater( name, modifier );
  229. }
  230. THREE.Particles.ParticleSystem.prototype.initialize = function( camera, parameters ) {
  231. this.camera = camera;
  232. this.sizeFrameSet = undefined;
  233. this.colorFrameSet = undefined;
  234. this.alphaFrameSet = undefined;
  235. if ( parameters ) {
  236. this.mergeParameters ( parameters );
  237. }
  238. if ( ! this.sizeFrameSet ) this.sizeFrameSet = new THREE.Particles.FrameSet();
  239. if ( ! this.colorFrameSet ) this.colorFrameSet = new THREE.Particles.FrameSet();
  240. if ( ! this.alphaFrameSet ) this.alphaFrameSet = new THREE.Particles.FrameSet();
  241. this.liveParticleArray = [];
  242. this.timeSinceLastEmit = 0.0;
  243. this.age = 0.0;
  244. this.emitting = true;
  245. this.calculateAverageParticleLifeSpan();
  246. this.calculateMaxParticleCount();
  247. this.initializeParticleArray();
  248. this.initializeGeometry();
  249. this.initializeMaterial( parameters.material );
  250. this.updateAttributesWithParticleData();
  251. this.initializeMesh();
  252. }
  253. THREE.Particles.ParticleSystem.prototype.getCameraWorldAxes = function() {
  254. var quaternion = new THREE.Quaternion();
  255. return function getCameraWorldAxes( camera, axisX, axisY, axisZ ) {
  256. camera.getWorldQuaternion( quaternion );
  257. axisZ.set( 0, 0, 1 ).applyQuaternion( quaternion );
  258. axisY.set( 0, 1, 0 ).applyQuaternion( quaternion );
  259. axisX.crossVectors( axisY, axisZ );
  260. }
  261. }();
  262. THREE.Particles.ParticleSystem.prototype.generateXYAlignedQuadForParticle = function() {
  263. var vectorX = new THREE.Vector3();
  264. var vectorY = new THREE.Vector3();
  265. return function generateXYAlignedQuadForParticle( particle, axisX, axisY, axisZ, pos1, pos2, pos3, pos4 ) {
  266. var position = particle.position;
  267. var rotation = particle.rotation;
  268. vectorX.copy( axisX );
  269. vectorY.copy( axisY );
  270. vectorX.multiplyScalar( Math.cos( rotation * THREE.Particles.Constants.DegreesToRadians ) );
  271. vectorY.multiplyScalar( Math.sin( rotation * THREE.Particles.Constants.DegreesToRadians ) );
  272. vectorX.addVectors( vectorX, vectorY );
  273. vectorY.crossVectors( axisZ, vectorX );
  274. vectorX.multiplyScalar( particle.size.x );
  275. vectorY.multiplyScalar( particle.size.y );
  276. pos1.subVectors( position, vectorX ).addVectors( pos1, vectorY );
  277. pos2.subVectors( position, vectorX ).subVectors( pos2, vectorY );
  278. pos3.addVectors( position, vectorX ).subVectors( pos3, vectorY );
  279. pos4.addVectors( position, vectorX ).addVectors( pos4, vectorY );
  280. }
  281. }();
  282. THREE.Particles.ParticleSystem.prototype.updateAttributesWithParticleData = function() {
  283. var vectorY = new THREE.Vector3();
  284. var vectorX = new THREE.Vector3();
  285. var vectorZ = new THREE.Vector3();
  286. var quadPos1 = new THREE.Vector3();
  287. var quadPos2 = new THREE.Vector3();
  288. var quadPos3 = new THREE.Vector3();
  289. var quadPos4 = new THREE.Vector3();
  290. return function updateAttributesWithParticleData() {
  291. this.getCameraWorldAxes( this.camera, vectorX, vectorY, vectorZ );
  292. this.particleMaterial.uniforms.cameraaxisx.value.copy( vectorX );
  293. this.particleMaterial.uniforms.cameraaxisy.value.copy( vectorY );
  294. this.particleMaterial.uniforms.cameraaxisz.value.copy( vectorZ );
  295. this.particleMaterial.uniforms.texture.value = this.particleAtlas.getTexture();
  296. for ( var p = 0; p < this.liveParticleCount; p ++ ) {
  297. var particle = this.liveParticleArray[ p ];
  298. var position = particle.position;
  299. var baseIndex = p * THREE.Particles.Constants.VerticesPerParticle;
  300. var attributePosition = this.particleGeometry.getAttribute( 'position' );
  301. this.updateAttributeVector3( attributePosition, baseIndex, position );
  302. this.updateAttributeVector3( attributePosition, baseIndex + 1, position );
  303. this.updateAttributeVector3( attributePosition, baseIndex + 2, position );
  304. this.updateAttributeVector3( attributePosition, baseIndex + 3, position );
  305. this.updateAttributeVector3( attributePosition, baseIndex + 4, position );
  306. this.updateAttributeVector3( attributePosition, baseIndex + 5, position );
  307. var imageDesc = this.particleAtlas.getImageDescriptor( particle.atlasIndex.x );
  308. var attributeUV = this.particleGeometry.getAttribute( 'uv' );
  309. this.updateAttributeVector2XY( attributeUV, baseIndex, imageDesc.left, imageDesc.top );
  310. this.updateAttributeVector2XY( attributeUV, baseIndex + 1, imageDesc.left, imageDesc.bottom );
  311. this.updateAttributeVector2XY( attributeUV, baseIndex + 2, imageDesc.right, imageDesc.top );
  312. this.updateAttributeVector2XY( attributeUV, baseIndex + 3, imageDesc.left, imageDesc.bottom );
  313. this.updateAttributeVector2XY( attributeUV, baseIndex + 4, imageDesc.right, imageDesc.bottom );
  314. this.updateAttributeVector2XY( attributeUV, baseIndex + 5, imageDesc.right, imageDesc.top );
  315. var color = particle.color;
  316. var alpha = particle.alpha.x;
  317. color.a = alpha;
  318. var size = particle.size;
  319. var rotation = particle.rotation.x * THREE.Particles.Constants.DegreesToRadians
  320. var attributeColor = this.particleGeometry.getAttribute( 'customColor' );
  321. var attributeSize = this.particleGeometry.getAttribute( 'size' );
  322. var attributeRotation = this.particleGeometry.getAttribute( 'rotation' );
  323. for ( var i = 0; i < THREE.Particles.Constants.VerticesPerParticle; i ++ ) {
  324. var index = baseIndex + i;
  325. this.updateAttributeColor( attributeColor, index, color );
  326. this.updateAttributeVector2XY( attributeSize, index, size.x, size.y );
  327. this.updateAttributeScalar( attributeRotation, index, rotation );
  328. }
  329. var attributeIndex = this.particleGeometry.getAttribute( 'customIndex' );
  330. this.updateAttributeScalar( attributeIndex, baseIndex, 0 );
  331. this.updateAttributeScalar( attributeIndex, baseIndex + 1, 1 );
  332. this.updateAttributeScalar( attributeIndex, baseIndex + 2, 3 );
  333. this.updateAttributeScalar( attributeIndex, baseIndex + 3, 1 );
  334. this.updateAttributeScalar( attributeIndex, baseIndex + 4, 2 );
  335. this.updateAttributeScalar( attributeIndex, baseIndex + 5, 3 );
  336. }
  337. this.particleGeometry.setDrawRange( 0, THREE.Particles.Constants.VerticesPerParticle * this.liveParticleCount );
  338. }
  339. }();
  340. THREE.Particles.ParticleSystem.prototype.updateAttributeVector2XY = function( attribute, index, x, y ) {
  341. attribute.array[ index * 2 ] = x;
  342. attribute.array[ index * 2 + 1 ] = y;
  343. attribute.needsUpdate = true;
  344. }
  345. THREE.Particles.ParticleSystem.prototype.updateAttributeVector3 = function( attribute, index, value ) {
  346. attribute.array[ index * 3 ] = value.x;
  347. attribute.array[ index * 3 + 1 ] = value.y;
  348. attribute.array[ index * 3 + 2 ] = value.z;
  349. attribute.needsUpdate = true;
  350. }
  351. THREE.Particles.ParticleSystem.prototype.updateAttributeColor = function( attribute, index, value ) {
  352. attribute.array[ index * 4 ] = value.r;
  353. attribute.array[ index * 4 + 1 ] = value.g;
  354. attribute.array[ index * 4 + 2 ] = value.b;
  355. attribute.array[ index * 4 + 3 ] = value.a;
  356. attribute.needsUpdate = true;
  357. }
  358. THREE.Particles.ParticleSystem.prototype.updateAttributeScalar = function( attribute, index, value ) {
  359. attribute.array[ index ] = value;
  360. attribute.needsUpdate = true;
  361. }
  362. THREE.Particles.ParticleSystem.prototype.createParticle = function() {
  363. var particle = new THREE.Particles.Particle();
  364. return particle;
  365. }
  366. THREE.Particles.ParticleSystem.prototype.initializeParticle = function( particle ) {
  367. this.resetParticle( particle );
  368. }
  369. THREE.Particles.ParticleSystem.prototype.resetParticle = function( particle ) {
  370. particle.age = 0;
  371. particle.alive = 0;
  372. this.resetParticleDisplayAttributes( particle );
  373. this.resetParticlePositionData( particle );
  374. this.resetParticleRotationData( particle );
  375. }
  376. THREE.Particles.ParticleSystem.prototype.resetParticleDisplayAttributes = function( particle ) {
  377. this.atlasInitializer.update( particle, particle.atlasIndex, 0 );
  378. this.sizeInitializer.update( particle, particle.size, 0 );
  379. this.colorInitializer.update( particle, particle._tempVector3, 0 );
  380. particle.color.setRGB( particle._tempVector3.x, particle._tempVector3.y, particle._tempVector3.z );
  381. this.alphaInitializer.update( particle, particle.alpha, 0 );
  382. }
  383. THREE.Particles.ParticleSystem.prototype.resetParticlePositionData = function( particle ) {
  384. this.positionInitializer.update( particle, particle.position, 0 );
  385. if ( ! this.simulateInLocalSpace ) {
  386. particle._tempVector3.setFromMatrixPosition( this.matrixWorld );
  387. particle.position.addVectors( particle._tempVector3, particle.position );
  388. }
  389. this.velocityInitializer.update( particle, particle.velocity, 0 );
  390. this.accelerationInitializer.update( particle, particle.acceleration, 0 );
  391. }
  392. THREE.Particles.ParticleSystem.prototype.resetParticleRotationData = function( particle ) {
  393. this.rotationInitializer.update( particle, particle.rotation );
  394. this.rotationalSpeedInitializer.update( particle, particle.rotationalSpeed );
  395. this.rotationalAccelerationInitializer.update( particle, particle.rotationalAcceleration );
  396. }
  397. THREE.Particles.ParticleSystem.prototype.advanceParticle = function( particle, deltaTime ) {
  398. particle.age += deltaTime;
  399. this.advanceParticleDisplayAttributes( particle, deltaTime );
  400. this.advanceParticlePositionData( particle, deltaTime );
  401. this.advanceParticleRotationData( particle, deltaTime );
  402. }
  403. THREE.Particles.ParticleSystem.prototype.advanceParticleDisplayAttributes = function( particle, deltaTime ) {
  404. this.atlasUpdater.update( particle, particle.atlasIndex, deltaTime );
  405. this.sizeUpdater.update( particle, particle.size, deltaTime );
  406. this.colorUpdater.update( particle, particle._tempVector3, deltaTime );
  407. particle.color.setRGB( particle._tempVector3.x, particle._tempVector3.y, particle._tempVector3.z );
  408. this.alphaUpdater.update( particle, particle.alpha, deltaTime );
  409. }
  410. THREE.Particles.ParticleSystem.prototype.advanceParticlePositionData = function( particle, deltaTime ) {
  411. this.positionUpdater.update( particle, particle.position, deltaTime );
  412. this.velocityUpdater.update( particle, particle.velocity, deltaTime );
  413. this.accelerationUpdater.update( particle, particle.acceleration, deltaTime );
  414. }
  415. THREE.Particles.ParticleSystem.prototype.advanceParticleRotationData = function( particle, deltaTime ) {
  416. this.rotationUpdater.update( particle, particle.rotation, deltaTime );
  417. this.rotationalSpeedUpdater.update( particle, particle.rotationalSpeed, deltaTime );
  418. this.rotationalAccelerationUpdater.update( particle, particle.rotationalAcceleration, deltaTime );
  419. }
  420. THREE.Particles.ParticleSystem.prototype.advanceParticles = function( deltaTime ) {
  421. var deadCount = 0;
  422. for ( var i = 0; i < this.liveParticleCount; i ++ )
  423. {
  424. var particle = this.liveParticleArray[ i ];
  425. this.advanceParticle( particle, deltaTime );
  426. if ( particle.age > particle.lifeSpan )
  427. {
  428. this.killParticle( particle );
  429. deadCount ++;
  430. }
  431. }
  432. if ( deadCount > 0 ) {
  433. this.cleanupDeadParticles();
  434. }
  435. }
  436. THREE.Particles.ParticleSystem.prototype.killParticle = function( particle ) {
  437. particle.alive = 0.0;
  438. }
  439. THREE.Particles.ParticleSystem.prototype.activateParticle = function( particle ) {
  440. this.resetParticle( particle );
  441. particle.lifeSpan = this.particleLifeSpan;
  442. particle.alive = 1.0;
  443. }
  444. THREE.Particles.ParticleSystem.prototype.cleanupDeadParticles = function() {
  445. var topAlive = this.liveParticleCount - 1;
  446. var bottomDead = 0;
  447. while ( topAlive > bottomDead ) {
  448. while ( this.liveParticleArray[ topAlive ].alive == 0.0 && topAlive > 0 ) {
  449. topAlive --;
  450. }
  451. while ( this.liveParticleArray[ bottomDead ].alive == 1.0 && bottomDead < this.liveParticleCount - 1 ) {
  452. bottomDead ++;
  453. }
  454. if ( topAlive <= bottomDead ) {
  455. break;
  456. }
  457. var swap = this.liveParticleArray[ bottomDead ];
  458. this.liveParticleArray[ bottomDead ] = this.liveParticleArray[ topAlive ];
  459. this.liveParticleArray[ topAlive ] = swap;
  460. }
  461. while ( this.liveParticleCount > 0 && this.liveParticleArray[ this.liveParticleCount - 1 ].alive == 0.0 ) {
  462. this.deadParticleArray[ this.deadParticleCount ] = this.liveParticleArray[ this.liveParticleCount - 1 ];
  463. this.deadParticleCount ++;
  464. this.liveParticleCount --;
  465. }
  466. this.liveParticleArray.length = this.liveParticleCount;
  467. this.deadParticleArray.length = this.deadParticleCount;
  468. }
  469. THREE.Particles.ParticleSystem.prototype.sortParticleArray = function() {
  470. function numericalSort( a, b ) {
  471. return a[ 0 ] - b[ 0 ];
  472. };
  473. var _sortParticleArray = [];
  474. var projectedPosition = new THREE.Vector3();
  475. return function sortParticleArray( mvpMatrix ) {
  476. for ( var p = 0; p < this.liveParticleCount; p ++ ) {
  477. var position = this.liveParticleArray[ p ].position;
  478. projectedPosition.copy( position );
  479. projectedPosition.applyProjection( mvpMatrix );
  480. if ( ! _sortParticleArray[ p ] ) {
  481. _sortParticleArray[ p ] = [ 0, 0 ];
  482. }
  483. _sortParticleArray[ p ][ 0 ] = projectedPosition.z;
  484. _sortParticleArray[ p ][ 1 ] = p;
  485. }
  486. _sortParticleArray.length = this.liveParticleCount;
  487. _sortParticleArray.sort( numericalSort );
  488. for ( p = 0; p < this.liveParticleCount; p ++ ) {
  489. var originalIndex = _sortParticleArray[ p ][ 1 ];
  490. this._tempParticleArray[ p ] = this.liveParticleArray[ originalIndex ];
  491. }
  492. this._tempParticleArray.length = this.liveParticleCount;
  493. var temp = this.liveParticleArray;
  494. this.liveParticleArray = this._tempParticleArray;
  495. this._tempParticleArray = temp;
  496. }
  497. }();
  498. THREE.Particles.ParticleSystem.prototype.activateParticles = function( count ) {
  499. for ( var i = 0; i < count; i ++ ) {
  500. if ( this.liveParticleCount < this.maxParticleCount && this.deadParticleCount > 0 ) {
  501. var newParticle = this.deadParticleArray[ this.deadParticleCount - 1 ];
  502. this.liveParticleArray[ this.liveParticleCount ] = newParticle;
  503. this.deadParticleCount --;
  504. this.liveParticleCount ++;
  505. this.activateParticle ( newParticle );
  506. } else {
  507. break;
  508. }
  509. }
  510. this.liveParticleArray.length = this.liveParticleCount;
  511. this.deadParticleArray.length = this.deadParticleCount;
  512. }
  513. THREE.Particles.ParticleSystem.prototype.update = function() {
  514. var tempMatrix4 = new THREE.Matrix4();
  515. return function update( deltaTime ) {
  516. if ( ! this.emitting )return;
  517. if ( ! this.isActive )return;
  518. this.timeSinceLastEmit += deltaTime;
  519. if ( this.releaseAtOnce ) {
  520. var waitTime = this.averageParticleLifeSpan;
  521. if ( ! this.hasInitialReleaseOccurred || ( this.timeSinceLastEmit > waitTime && this.liveParticleCount <= 0 ) ) {
  522. this.activateParticles( this.maxParticleCount );
  523. this.timeSinceLastEmit = 0.0;
  524. this.hasInitialReleaseOccurred = true;
  525. }
  526. } else {
  527. var emitUnitTime = 1.0 / this.particleReleaseRate;
  528. if ( ! this.hasInitialReleaseOccurred || this.timeSinceLastEmit > emitUnitTime ) {
  529. var releaseCount = Math.max( 1, Math.floor( this.timeSinceLastEmit / emitUnitTime ) );
  530. this.activateParticles( releaseCount );
  531. this.timeSinceLastEmit = 0.0;
  532. this.hasInitialReleaseOccurred = true;
  533. }
  534. }
  535. this.advanceParticles( deltaTime );
  536. if ( this.zSort ) {
  537. this.camera.updateMatrixWorld();
  538. tempMatrix4.copy( this.camera.matrixWorld );
  539. tempMatrix4.getInverse( tempMatrix4 );
  540. this.sortParticleArray( tempMatrix4 );
  541. }
  542. this.updateAttributesWithParticleData();
  543. this.age += deltaTime;
  544. if ( this.lifespan != 0 && this.age > this.lifespan ) {
  545. this.emitting = false;
  546. }
  547. if ( this.simulateInLocalSpace ) {
  548. this.particleMesh.matrix.copy( this.matrixWorld );
  549. this.particleMesh.updateMatrixWorld();
  550. }
  551. }
  552. }();
  553. THREE.Particles.ParticleSystem.prototype.deactivate = function() {
  554. if ( this.isActive ) {
  555. scene.remove( this.particleMesh );
  556. this.isActive = false;
  557. }
  558. }
  559. THREE.Particles.ParticleSystem.prototype.activate = function() {
  560. if ( ! this.isActive ) {
  561. scene.add( this.particleMesh );
  562. this.isActive = true;
  563. }
  564. }
  565. THREE.Particles.ParticleSystem.DefaultPositionUpdater = {
  566. update : function( particle, target, deltaTime ) {
  567. particle._tempVector3.copy( particle.velocity );
  568. particle._tempVector3.multiplyScalar( deltaTime );
  569. particle.position.add( particle._tempVector3 );
  570. }
  571. }
  572. THREE.Particles.ParticleSystem.DefaultVelocityUpdater = {
  573. update : function( particle, target, deltaTime ) {
  574. particle._tempVector3.copy( particle.acceleration );
  575. particle._tempVector3.multiplyScalar( deltaTime );
  576. particle.velocity.add( particle._tempVector3 );
  577. }
  578. }
  579. THREE.Particles.ParticleSystem.DefaultRotationUpdater = {
  580. update : function( particle, target, deltaTime ) {
  581. particle.rotation.set( particle.rotation.x += particle.rotationalSpeed.x * deltaTime );
  582. }
  583. }
  584. THREE.Particles.ParticleSystem.DefaultRotationalSpeedUpdater = {
  585. update : function( particle, target, deltaTime ) {
  586. particle.rotationalSpeed.set( particle.rotationalSpeed.x += particle.rotationalAcceleration.x * deltaTime );
  587. }
  588. }
  589. THREE.Particles.ParticleSystem.DefaultUpdater = {
  590. update : function( particle, target, deltaTime ) {
  591. }
  592. }
  593. THREE.Particles.ParticleSystem.DefaultInitializer = {
  594. update : function( particle, target, deltaTime ) {
  595. target.set( 0, 0, 0, 0 );
  596. }
  597. }
  598. //=======================================
  599. // Particle object
  600. //=======================================
  601. THREE.Particles.Particle = function() {
  602. this.age = 0;
  603. this.alive = 0;
  604. this.lifeSpan = 0;
  605. this.size = new THREE.Vector3();
  606. this.color = new THREE.Color();
  607. this.alpha = new THREE.Particles.SingularVector( 0 );
  608. this.atlasIndex = new THREE.Particles.SingularVector( 0 );
  609. this.position = new THREE.Vector3();
  610. this.velocity = new THREE.Vector3();
  611. this.acceleration = new THREE.Vector3();
  612. this.rotation = new THREE.Particles.SingularVector( 0 );
  613. this.rotationalSpeed = new THREE.Particles.SingularVector( 0 );
  614. this.rotationalAcceleration = new THREE.Particles.SingularVector( 0 );
  615. this._tempVector3 = new THREE.Vector3();
  616. }