import * as RE from 'rogue-engine' import * as THREE from 'three' import { Color } from 'three'; // import Player from './Player.re'; //https://www.youtube.com/watch?v=OFqENgtqRAY export default class ParticleSystem extends RE.Component { vertexShader = ` uniform float pointMultiplier; varying vec4 vColor; void main() { vec4 mvPosition = modelViewMatrix * vec4(position, 1.0); gl_Position = projectionMatrix * mvPosition; gl_PointSize = pointMultiplier / gl_Position.w; vColor = color; }`; fragmentShader = ` uniform sampler2D diffuseTexture; varying vec4 vColor; void main() { gl_FragColor = texture2D(diffuseTexture, gl_PointCoord) * vColor; }`; @RE.Prop("Texture") particleTexture @RE.Prop("Number") maxParticles = 1 @RE.Prop("Number") particleLifespan = 50 @RE.Prop("Vector3") initialPosition = new THREE.Vector3(0,0,0) @RE.Prop("Vector3") initialVelocity = new THREE.Vector3(0,0,0) @RE.Prop("Object3D") points @RE.Prop("Number") thrustScalar = 0.01 @RE.Prop("Vector3") positionRandomBounds = new THREE.Vector3(1,1,1) @RE.Prop("Vector3") velocityRandomBounds = new THREE.Vector3(1,1,1) @RE.Prop("Color") particleColor = new Color(255, 255, 255) @RE.Prop("Number") particleAlpha = 1 @RE.Prop("Object3D") spawnLocation start() { const bounds = RE.Runtime.rogueDOMContainer.getBoundingClientRect(); const uniforms = { diffuseTexture: { value: this.particleTexture }, pointMultiplier: { value: bounds.width - bounds.left } } this.material = new THREE.ShaderMaterial({ uniforms: uniforms, vertexShader: this.vertexShader, fragmentShader: this.fragmentShader, blending: THREE.AdditiveBlending, depthTest: true, depthWrite: false, transparent: true, vertexColors: true, }) this.geometry = new THREE.BufferGeometry() this.geometry.setAttribute('position', new THREE.Float32BufferAttribute([], 3)); this.geometry.setAttribute('color', new THREE.Float32BufferAttribute([], 4)); this.points.geometry = this.geometry this.points.material = this.material this.particles = [] // this.ship = RE.getComponent(Player, this.object3d) this.updateGeometry() } awake() { } update() { // if(this.ship.isThrusting) { // this.addParticles(); // } this.updateParticles(RE.Runtime.deltaTime); this.updateGeometry(); } addParticles() { if(this.particles.length >= this.maxParticles) { return } for (let i = 0; i < 1; i++) { const life = this.particleLifespan; const newPosition = new THREE.Vector3() this.spawnLocation.getWorldPosition(newPosition) newPosition.add(new THREE.Vector3( 1 * Math.random() - 0.5, 1 * Math.random() - 0.5, 1 * Math.random() - 0.5 ).multiply(this.positionRandomBounds)) const newVelocity = this.initialVelocity.clone() // if(this.ship) { // newVelocity.add(new THREE.Vector3( // -this.ship.bodyComponent.body.force.x, // -this.ship.bodyComponent.body.force.y, // -this.ship.bodyComponent.body.force.z)) // } newVelocity.add(new THREE.Vector3( 1 * Math.random() - 0.5, 1 * Math.random() - 0.5, 1 * Math.random() - 0.5 ).multiply(this.velocityRandomBounds)) newVelocity.multiplyScalar(this.thrustScalar) // const thrustVelocity = new THREE.Vector3( // -this.ship.bodyComponent.body.force.x, // -this.ship.bodyComponent.body.force.y, // -this.ship.bodyComponent.body.force.z) // thrustVelocity.multiply(this.velocityRandomBounds) // thrustVelocity.multiplyScalar(this.thrustScalar) this.particles.push({ position: newPosition, life: life, maxLife: life, velocity: newVelocity, color: this.particleColor, alpha: this.particleAlpha, }); } } updateGeometry() { const positions = []; const colors = [] for (let p of this.particles) { positions.push(p.position.x, p.position.y, p.position.z); colors.push(p.color.r, p.color.g, p.color.b, p.alpha); } this.geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3)); this.geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 4)); this.geometry.attributes.position.needsUpdate = true; this.geometry.attributes.color.needsUpdate = true; } updateParticles(deltaTime) { for (let p of this.particles) { p.life -= deltaTime; } this.particles = this.particles.filter(p => { return p.life > 0.0; }); for (let p of this.particles) { p.position.add(p.velocity.clone()); } // RE.Debug.log(JSON.stringify(this.particles[0].position)) let camera = RE.App.currentScene.getObjectByProperty('uuid', RE.App.activeCamera) this.particles.sort((a, b) => { const d1 = camera.position.distanceTo(a.position); const d2 = camera.position.distanceTo(b.position); if (d1 > d2) { return -1; } if (d1 < d2) { return 1; } return 0; }); } } RE.registerComponent(ParticleSystem)