123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218 |
- 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") texture
- @RE.Prop("Color") color = new Color(255, 255, 255)
- @RE.Prop("Number") alpha = 1
- @RE.Prop("Select") blending = 0
- blendingOptions = ["Additive", "Normal", "Multiply", "None", "Subtractive"]
- //this is the "mesh" that we draw the particle textures into
- //it's a THREE.Points object that I added underneath the GameLogic Object3d
- @RE.Prop("Object3D") globalPointsObject
- @RE.Prop("Number") max = 500
- @RE.Prop("Number") spawnPerTick = 1
- @RE.Prop("Number") lifespan = 2
- //This is the Object3d where we spawn particles from. It uses the worldPosition
- //so things like rotations are accounted for
- @RE.Prop("Object3D") initialLocation
-
- @RE.Prop("Vector3") initialVelocity = new THREE.Vector3(0,0,0)
- //this is the "mesh" that we draw the particle textures into
- //it's a THREE.Points object that I added underneath the GameLogic Object3d
- @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)
- start() {
- const bounds = RE.Runtime.rogueDOMContainer.getBoundingClientRect();
- const uniforms = {
- diffuseTexture: {
- value: this.texture
- },
- pointMultiplier: {
- value: bounds.width - bounds.left
- }
- }
- this.material = new THREE.ShaderMaterial({
- uniforms: uniforms,
- vertexShader: this.vertexShader,
- fragmentShader: this.fragmentShader,
- blending: this.convertBlending(this.blending),
- 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.globalPointsObject.geometry = this.geometry
- this.globalPointsObject.material = this.material
- this.particles = []
- this.ship = RE.getComponent(Player, this.object3d)
- this.updateGeometry()
- }
- convertBlending(selectIndex) {
- console.log(selectIndex)
- switch(this.blendingOptions[selectIndex]) {
- case "Additive":
- return THREE.AdditiveBlending
- case "Normal":
- return THREE.NormalBlending
- case "Multiply":
- return THREE.MultiplyBlending
- case "None":
- return THREE.NoBlending
- case "Subtractive":
- return THREE.SubtractiveBlending
- default:
- return THREE.AdditiveBlending
- }
- }
- awake() {
- }
- update() {
- if(this.ship.isThrusting) {
- this.addParticles();
- }
- this.updateParticles(RE.Runtime.deltaTime);
- this.updateGeometry();
- }
- addParticles() {
- if(this.particles.length >= this.max) {
- return
- }
- for (let i = 0; i < this.spawnPerTick; i++) {
- const life = this.lifespan;
- const newPosition = new THREE.Vector3()
- this.initialLocation.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)
- .multiplyScalar(this.thrustScalar))
- }
- newVelocity.add(new THREE.Vector3(
- 1 * Math.random() - 0.5,
- 1 * Math.random() - 0.5,
- 1 * Math.random() - 0.5
- ).multiply(this.velocityRandomBounds)
- )
- this.particles.push({
- position: newPosition,
- life: life,
- maxLife: life,
- velocity: newVelocity,
- color: this.color,
- alpha: this.alpha,
- });
- }
- }
-
- 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)
|