cylinderParticleEmitter.ts 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. import { Tools } from "Tools";
  2. import { Vector3, Matrix, Scalar } from "Math";
  3. import { Effect } from "Materials";
  4. import { IParticleEmitterType, Particle } from "Particles";
  5. /**
  6. * Particle emitter emitting particles from the inside of a cylinder.
  7. * It emits the particles alongside the cylinder radius. The emission direction might be randomized.
  8. */
  9. export class CylinderParticleEmitter implements IParticleEmitterType {
  10. /**
  11. * Creates a new instance CylinderParticleEmitter
  12. * @param radius the radius of the emission cylinder (1 by default)
  13. * @param height the height of the emission cylinder (1 by default)
  14. * @param radiusRange the range of the emission cylinder [0-1] 0 Surface only, 1 Entire Radius (1 by default)
  15. * @param directionRandomizer defines how much to randomize the particle direction [0-1]
  16. */
  17. constructor(
  18. /**
  19. * The radius of the emission cylinder.
  20. */
  21. public radius = 1,
  22. /**
  23. * The height of the emission cylinder.
  24. */
  25. public height = 1,
  26. /**
  27. * The range of emission [0-1] 0 Surface only, 1 Entire Radius.
  28. */
  29. public radiusRange = 1,
  30. /**
  31. * How much to randomize the particle direction [0-1].
  32. */
  33. public directionRandomizer = 0) {
  34. }
  35. /**
  36. * Called by the particle System when the direction is computed for the created particle.
  37. * @param worldMatrix is the world matrix of the particle system
  38. * @param directionToUpdate is the direction vector to update with the result
  39. * @param particle is the particle we are computed the direction for
  40. */
  41. public startDirectionFunction(worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle): void {
  42. var direction = particle.position.subtract(worldMatrix.getTranslation()).normalize();
  43. var randY = Scalar.RandomRange(-this.directionRandomizer / 2, this.directionRandomizer / 2);
  44. var angle = Math.atan2(direction.x, direction.z);
  45. angle += Scalar.RandomRange(-Math.PI / 2, Math.PI / 2) * this.directionRandomizer;
  46. direction.y = randY; // set direction y to rand y to mirror normal of cylinder surface
  47. direction.x = Math.sin(angle);
  48. direction.z = Math.cos(angle);
  49. direction.normalize();
  50. Vector3.TransformNormalFromFloatsToRef(direction.x, direction.y, direction.z, worldMatrix, directionToUpdate);
  51. }
  52. /**
  53. * Called by the particle System when the position is computed for the created particle.
  54. * @param worldMatrix is the world matrix of the particle system
  55. * @param positionToUpdate is the position vector to update with the result
  56. * @param particle is the particle we are computed the position for
  57. */
  58. public startPositionFunction(worldMatrix: Matrix, positionToUpdate: Vector3, particle: Particle): void {
  59. var yPos = Scalar.RandomRange(-this.height / 2, this.height / 2);
  60. var angle = Scalar.RandomRange(0, 2 * Math.PI);
  61. // Pick a properly distributed point within the circle https://programming.guide/random-point-within-circle.html
  62. var radiusDistribution = Scalar.RandomRange((1 - this.radiusRange) * (1 - this.radiusRange), 1);
  63. var positionRadius = Math.sqrt(radiusDistribution) * this.radius;
  64. var xPos = positionRadius * Math.cos(angle);
  65. var zPos = positionRadius * Math.sin(angle);
  66. Vector3.TransformCoordinatesFromFloatsToRef(xPos, yPos, zPos, worldMatrix, positionToUpdate);
  67. }
  68. /**
  69. * Clones the current emitter and returns a copy of it
  70. * @returns the new emitter
  71. */
  72. public clone(): CylinderParticleEmitter {
  73. let newOne = new CylinderParticleEmitter(this.radius, this.directionRandomizer);
  74. Tools.DeepCopy(this, newOne);
  75. return newOne;
  76. }
  77. /**
  78. * Called by the GPUParticleSystem to setup the update shader
  79. * @param effect defines the update shader
  80. */
  81. public applyToShader(effect: Effect): void {
  82. effect.setFloat("radius", this.radius);
  83. effect.setFloat("height", this.height);
  84. effect.setFloat("radiusRange", this.radiusRange);
  85. effect.setFloat("directionRandomizer", this.directionRandomizer);
  86. }
  87. /**
  88. * Returns a string to use to update the GPU particles update shader
  89. * @returns a string containng the defines string
  90. */
  91. public getEffectDefines(): string {
  92. return "#define CYLINDEREMITTER";
  93. }
  94. /**
  95. * Returns the string "CylinderParticleEmitter"
  96. * @returns a string containing the class name
  97. */
  98. public getClassName(): string {
  99. return "CylinderParticleEmitter";
  100. }
  101. /**
  102. * Serializes the particle system to a JSON object.
  103. * @returns the JSON object
  104. */
  105. public serialize(): any {
  106. var serializationObject: any = {};
  107. serializationObject.type = this.getClassName();
  108. serializationObject.radius = this.radius;
  109. serializationObject.height = this.height;
  110. serializationObject.radiusRange = this.radiusRange;
  111. serializationObject.directionRandomizer = this.directionRandomizer;
  112. return serializationObject;
  113. }
  114. /**
  115. * Parse properties from a JSON object
  116. * @param serializationObject defines the JSON object
  117. */
  118. public parse(serializationObject: any): void {
  119. this.radius = serializationObject.radius;
  120. this.height = serializationObject.height;
  121. this.radiusRange = serializationObject.radiusRange;
  122. this.directionRandomizer = serializationObject.directionRandomizer;
  123. }
  124. }
  125. /**
  126. * Particle emitter emitting particles from the inside of a cylinder.
  127. * It emits the particles randomly between two vectors.
  128. */
  129. export class CylinderDirectedParticleEmitter extends CylinderParticleEmitter {
  130. /**
  131. * Creates a new instance CylinderDirectedParticleEmitter
  132. * @param radius the radius of the emission cylinder (1 by default)
  133. * @param height the height of the emission cylinder (1 by default)
  134. * @param radiusRange the range of the emission cylinder [0-1] 0 Surface only, 1 Entire Radius (1 by default)
  135. * @param direction1 the min limit of the emission direction (up vector by default)
  136. * @param direction2 the max limit of the emission direction (up vector by default)
  137. */
  138. constructor(
  139. radius = 1,
  140. height = 1,
  141. radiusRange = 1,
  142. /**
  143. * The min limit of the emission direction.
  144. */
  145. public direction1 = new Vector3(0, 1, 0),
  146. /**
  147. * The max limit of the emission direction.
  148. */
  149. public direction2 = new Vector3(0, 1, 0)) {
  150. super(radius, height, radiusRange);
  151. }
  152. /**
  153. * Called by the particle System when the direction is computed for the created particle.
  154. * @param worldMatrix is the world matrix of the particle system
  155. * @param directionToUpdate is the direction vector to update with the result
  156. * @param particle is the particle we are computed the direction for
  157. */
  158. public startDirectionFunction(worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle): void {
  159. var randX = Scalar.RandomRange(this.direction1.x, this.direction2.x);
  160. var randY = Scalar.RandomRange(this.direction1.y, this.direction2.y);
  161. var randZ = Scalar.RandomRange(this.direction1.z, this.direction2.z);
  162. Vector3.TransformNormalFromFloatsToRef(randX, randY, randZ, worldMatrix, directionToUpdate);
  163. }
  164. /**
  165. * Clones the current emitter and returns a copy of it
  166. * @returns the new emitter
  167. */
  168. public clone(): CylinderDirectedParticleEmitter {
  169. let newOne = new CylinderDirectedParticleEmitter(this.radius, this.height, this.radiusRange, this.direction1, this.direction2);
  170. Tools.DeepCopy(this, newOne);
  171. return newOne;
  172. }
  173. /**
  174. * Called by the GPUParticleSystem to setup the update shader
  175. * @param effect defines the update shader
  176. */
  177. public applyToShader(effect: Effect): void {
  178. effect.setFloat("radius", this.radius);
  179. effect.setFloat("height", this.height);
  180. effect.setFloat("radiusRange", this.radiusRange);
  181. effect.setVector3("direction1", this.direction1);
  182. effect.setVector3("direction2", this.direction2);
  183. }
  184. /**
  185. * Returns a string to use to update the GPU particles update shader
  186. * @returns a string containng the defines string
  187. */
  188. public getEffectDefines(): string {
  189. return "#define CYLINDEREMITTER\n#define DIRECTEDCYLINDEREMITTER";
  190. }
  191. /**
  192. * Returns the string "CylinderDirectedParticleEmitter"
  193. * @returns a string containing the class name
  194. */
  195. public getClassName(): string {
  196. return "CylinderDirectedParticleEmitter";
  197. }
  198. /**
  199. * Serializes the particle system to a JSON object.
  200. * @returns the JSON object
  201. */
  202. public serialize(): any {
  203. var serializationObject = super.serialize();
  204. serializationObject.direction1 = this.direction1.asArray();
  205. serializationObject.direction2 = this.direction2.asArray();
  206. return serializationObject;
  207. }
  208. /**
  209. * Parse properties from a JSON object
  210. * @param serializationObject defines the JSON object
  211. */
  212. public parse(serializationObject: any): void {
  213. super.parse(serializationObject);
  214. this.direction1.copyFrom(serializationObject.direction1);
  215. this.direction2.copyFrom(serializationObject.direction2);
  216. }
  217. }