ParticleSystem.re.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. import * as RE from 'rogue-engine'
  2. import * as THREE from 'three'
  3. import { Color } from 'three';
  4. // import Player from './Player.re';
  5. //https://www.youtube.com/watch?v=OFqENgtqRAY
  6. export default class ParticleSystem extends RE.Component {
  7. vertexShader = `
  8. uniform float pointMultiplier;
  9. varying vec4 vColor;
  10. void main() {
  11. vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
  12. gl_Position = projectionMatrix * mvPosition;
  13. gl_PointSize = pointMultiplier / gl_Position.w;
  14. vColor = color;
  15. }`;
  16. fragmentShader = `
  17. uniform sampler2D diffuseTexture;
  18. varying vec4 vColor;
  19. void main() {
  20. gl_FragColor = texture2D(diffuseTexture, gl_PointCoord) * vColor;
  21. }`;
  22. @RE.Prop("Texture") particleTexture
  23. @RE.Prop("Number") maxParticles = 1
  24. @RE.Prop("Number") particleLifespan = 50
  25. @RE.Prop("Vector3") initialPosition = new THREE.Vector3(0,0,0)
  26. @RE.Prop("Vector3") initialVelocity = new THREE.Vector3(0,0,0)
  27. @RE.Prop("Object3D") points
  28. @RE.Prop("Number") thrustScalar = 0.01
  29. @RE.Prop("Vector3") positionRandomBounds = new THREE.Vector3(1,1,1)
  30. @RE.Prop("Vector3") velocityRandomBounds = new THREE.Vector3(1,1,1)
  31. @RE.Prop("Color") particleColor = new Color(255, 255, 255)
  32. @RE.Prop("Number") particleAlpha = 1
  33. @RE.Prop("Object3D") spawnLocation
  34. start() {
  35. const bounds = RE.Runtime.rogueDOMContainer.getBoundingClientRect();
  36. const uniforms = {
  37. diffuseTexture: {
  38. value: this.particleTexture
  39. },
  40. pointMultiplier: {
  41. value: bounds.width - bounds.left
  42. }
  43. }
  44. this.material = new THREE.ShaderMaterial({
  45. uniforms: uniforms,
  46. vertexShader: this.vertexShader,
  47. fragmentShader: this.fragmentShader,
  48. blending: THREE.AdditiveBlending,
  49. depthTest: true,
  50. depthWrite: false,
  51. transparent: true,
  52. vertexColors: true,
  53. })
  54. this.geometry = new THREE.BufferGeometry()
  55. this.geometry.setAttribute('position', new THREE.Float32BufferAttribute([], 3));
  56. this.geometry.setAttribute('color', new THREE.Float32BufferAttribute([], 4));
  57. this.points.geometry = this.geometry
  58. this.points.material = this.material
  59. this.particles = []
  60. // this.ship = RE.getComponent(Player, this.object3d)
  61. this.updateGeometry()
  62. }
  63. awake() {
  64. }
  65. update() {
  66. // if(this.ship.isThrusting) {
  67. // this.addParticles();
  68. // }
  69. this.updateParticles(RE.Runtime.deltaTime);
  70. this.updateGeometry();
  71. }
  72. addParticles() {
  73. if(this.particles.length >= this.maxParticles) {
  74. return
  75. }
  76. for (let i = 0; i < 1; i++) {
  77. const life = this.particleLifespan;
  78. const newPosition = new THREE.Vector3()
  79. this.spawnLocation.getWorldPosition(newPosition)
  80. newPosition.add(new THREE.Vector3(
  81. 1 * Math.random() - 0.5,
  82. 1 * Math.random() - 0.5,
  83. 1 * Math.random() - 0.5
  84. ).multiply(this.positionRandomBounds))
  85. const newVelocity = this.initialVelocity.clone()
  86. // if(this.ship) {
  87. // newVelocity.add(new THREE.Vector3(
  88. // -this.ship.bodyComponent.body.force.x,
  89. // -this.ship.bodyComponent.body.force.y,
  90. // -this.ship.bodyComponent.body.force.z))
  91. // }
  92. newVelocity.add(new THREE.Vector3(
  93. 1 * Math.random() - 0.5,
  94. 1 * Math.random() - 0.5,
  95. 1 * Math.random() - 0.5
  96. ).multiply(this.velocityRandomBounds))
  97. newVelocity.multiplyScalar(this.thrustScalar)
  98. // const thrustVelocity = new THREE.Vector3(
  99. // -this.ship.bodyComponent.body.force.x,
  100. // -this.ship.bodyComponent.body.force.y,
  101. // -this.ship.bodyComponent.body.force.z)
  102. // thrustVelocity.multiply(this.velocityRandomBounds)
  103. // thrustVelocity.multiplyScalar(this.thrustScalar)
  104. this.particles.push({
  105. position: newPosition,
  106. life: life,
  107. maxLife: life,
  108. velocity: newVelocity,
  109. color: this.particleColor,
  110. alpha: this.particleAlpha,
  111. });
  112. }
  113. }
  114. updateGeometry() {
  115. const positions = [];
  116. const colors = []
  117. for (let p of this.particles) {
  118. positions.push(p.position.x, p.position.y, p.position.z);
  119. colors.push(p.color.r, p.color.g, p.color.b, p.alpha);
  120. }
  121. this.geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
  122. this.geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 4));
  123. this.geometry.attributes.position.needsUpdate = true;
  124. this.geometry.attributes.color.needsUpdate = true;
  125. }
  126. updateParticles(deltaTime) {
  127. for (let p of this.particles) {
  128. p.life -= deltaTime;
  129. }
  130. this.particles = this.particles.filter(p => {
  131. return p.life > 0.0;
  132. });
  133. for (let p of this.particles) {
  134. p.position.add(p.velocity.clone());
  135. }
  136. // RE.Debug.log(JSON.stringify(this.particles[0].position))
  137. let camera = RE.App.currentScene.getObjectByProperty('uuid', RE.App.activeCamera)
  138. this.particles.sort((a, b) => {
  139. const d1 = camera.position.distanceTo(a.position);
  140. const d2 = camera.position.distanceTo(b.position);
  141. if (d1 > d2) {
  142. return -1;
  143. }
  144. if (d1 < d2) {
  145. return 1;
  146. }
  147. return 0;
  148. });
  149. }
  150. }
  151. RE.registerComponent(ParticleSystem)