babylon.gpuParticleSystem.ts 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. module BABYLON {
  2. export class GPUParticleSystem implements IDisposable, IParticleSystem {
  3. // Members
  4. public id: string;
  5. public emitter: Nullable<AbstractMesh | Vector3> = null;
  6. public renderingGroupId = 0;
  7. public layerMask: number = 0x0FFFFFFF; // TODO
  8. private _capacity: number;
  9. private _renderEffect: Effect;
  10. private _updateEffect: Effect;
  11. private _updateBuffer: Buffer;
  12. private _updateVAO: WebGLVertexArrayObject;
  13. private _updateVertexBuffers: {[key: string]: VertexBuffer} = {};
  14. private _renderBuffer: Buffer;
  15. private _renderVAO: WebGLVertexArrayObject;
  16. private _renderVertexBuffers: {[key: string]: VertexBuffer} = {};
  17. private _sourceVAO: WebGLVertexArrayObject;
  18. private _targetVAO: WebGLVertexArrayObject;
  19. private _sourceBuffer: Buffer;
  20. private _targetBuffer: Buffer;
  21. private _scene: Scene;
  22. private _engine: Engine;
  23. private _currentRenderId = -1;
  24. private _started = true;
  25. /**
  26. * An event triggered when the system is disposed.
  27. * @type {BABYLON.Observable}
  28. */
  29. public onDisposeObservable = new Observable<GPUParticleSystem>();
  30. public isStarted(): boolean {
  31. return this._started;
  32. }
  33. public start(): void {
  34. this._started = true;
  35. }
  36. public stop(): void {
  37. this._started = false;
  38. }
  39. constructor(public name: string, capacity: number, scene: Scene) {
  40. this.id = name;
  41. this._scene = scene || Engine.LastCreatedScene;
  42. this._capacity = capacity;
  43. this._engine = this._scene.getEngine();
  44. this._scene.particleSystems.push(this);
  45. this._renderEffect = new Effect("gpuRenderParticles", ["position", "age", "life", "velocity"], [], [], this._scene.getEngine());
  46. let updateEffectOptions: EffectCreationOptions = {
  47. attributes: ["position", "age", "life", "velocity"],
  48. uniformsNames: [],
  49. uniformBuffersNames: [],
  50. samplers:[],
  51. defines: "",
  52. fallbacks: null,
  53. onCompiled: null,
  54. onError: null,
  55. indexParameters: null,
  56. maxSimultaneousLights: 0,
  57. transformFeedbackVaryings: ["outPosition", "outAge", "outLife", "outVelocity"]
  58. };
  59. this._updateEffect = new Effect("gpuUpdateParticles", updateEffectOptions, this._scene.getEngine());
  60. }
  61. public animate(): void {
  62. // Do nothing
  63. }
  64. private _initialize(): void {
  65. if (this._renderVAO) {
  66. return;
  67. }
  68. var data = new Array<float>();
  69. for (var particleIndex = 0; particleIndex < this._capacity; particleIndex++) {
  70. // position
  71. data.push(0.0);
  72. data.push(0.0);
  73. data.push(0.0);
  74. var life = 1 + Math.random() * 10; // TODO: var
  75. data.push(life + 1); // create the particle as a dead one to create a new one at start
  76. data.push(life);
  77. // velocity
  78. data.push(0.0);
  79. data.push(0.0);
  80. data.push(0.0);
  81. }
  82. // Update VAO
  83. this._updateBuffer = new Buffer(this._scene.getEngine(), data, false, 0);
  84. this._updateVertexBuffers["position"] = this._updateBuffer.createVertexBuffer("position", 0, 3, 3);
  85. this._updateVertexBuffers["age"] = this._updateBuffer.createVertexBuffer("age", 3, 1, 1);
  86. this._updateVertexBuffers["life"] = this._updateBuffer.createVertexBuffer("life", 4, 1, 1);
  87. this._updateVertexBuffers["velocity"] = this._updateBuffer.createVertexBuffer("velocity", 5, 3, 3);
  88. this._updateVAO = this._engine.recordVertexArrayObject(this._updateVertexBuffers, null, this._updateEffect);
  89. this._engine.bindArrayBuffer(null);
  90. // Render VAO
  91. this._renderBuffer = new Buffer(this._scene.getEngine(), data, false, 0);
  92. this._renderVertexBuffers["position"] = this._renderBuffer.createVertexBuffer("position", 0, 3, 3);
  93. this._renderVertexBuffers["age"] = this._renderBuffer.createVertexBuffer("age", 3, 1, 1);
  94. this._renderVertexBuffers["life"] = this._renderBuffer.createVertexBuffer("life", 4, 1, 1);
  95. this._renderVertexBuffers["velocity"] = this._renderBuffer.createVertexBuffer("velocity", 5, 3, 3);
  96. this._renderVAO = this._engine.recordVertexArrayObject(this._renderVertexBuffers, null, this._renderEffect);
  97. this._engine.bindArrayBuffer(null);
  98. // Links
  99. this._sourceVAO = this._updateVAO;
  100. this._targetVAO = this._renderVAO;
  101. this._sourceBuffer = this._updateBuffer;
  102. this._targetBuffer = this._renderBuffer;
  103. }
  104. public render(): number {
  105. if (!this.emitter || !this._updateEffect.isReady() || !this._renderEffect.isReady() ) {
  106. return 0;
  107. }
  108. // Get everything ready to render
  109. this. _initialize();
  110. if (this._currentRenderId === this._scene.getRenderId()) {
  111. return 0;
  112. }
  113. this._currentRenderId = this._scene.getRenderId();
  114. // Enable update effect
  115. this._engine.enableEffect(this._updateEffect);
  116. this._engine.setState(false);
  117. // Bind source VAO
  118. this._engine.bindVertexArrayObject(this._sourceVAO, null);
  119. // Update
  120. this._engine.bindTransformFeedbackBuffer(this._targetBuffer.getBuffer());
  121. this._engine.setRasterizerState(false);
  122. this._engine.beginTransformFeedback();
  123. this._engine.drawArraysType(Material.PointListDrawMode, 0, this._capacity);
  124. this._engine.endTransformFeedback();
  125. this._engine.setRasterizerState(true);
  126. this._engine.bindTransformFeedbackBuffer(null);
  127. // Enable render effect
  128. this._engine.enableEffect(this._renderEffect);
  129. // Bind source VAO
  130. this._engine.bindVertexArrayObject(this._targetVAO, null);
  131. // Render
  132. this._engine.drawArraysType(Material.PointListDrawMode, 0, this._capacity);
  133. // Switch VAOs
  134. let tmpVAO = this._sourceVAO;
  135. this._sourceVAO = this._targetVAO;
  136. this._targetVAO = tmpVAO;
  137. // Switch buffers
  138. let tmpBuffer = this._sourceBuffer;
  139. this._sourceBuffer = this._targetBuffer;
  140. this._targetBuffer = tmpBuffer;
  141. return 0;
  142. }
  143. public rebuild(): void {
  144. }
  145. public dispose(): void {
  146. var index = this._scene.particleSystems.indexOf(this);
  147. if (index > -1) {
  148. this._scene.particleSystems.splice(index, 1);
  149. }
  150. //TODO: this._dataBuffer.dispose();
  151. // Callback
  152. this.onDisposeObservable.notifyObservers(this);
  153. this.onDisposeObservable.clear();
  154. }
  155. //TODO: Clone / Parse / serialize
  156. public clone(name: string, newEmitter: any): Nullable<GPUParticleSystem> {
  157. return null;
  158. }
  159. public serialize(): any {
  160. }
  161. }
  162. }