123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310 |
- import * as THREE from "../../../../libs/three.js/build/three.module.js";
- import { vertexShader, fragmentShader } from './shader.js'
- import Tween from './Tween.js'
- import Particle from './Particle.js'
- import {util} from './Util.js'
- import { Shape } from './const.js'
- let particleTexture
- const getTexture = ()=>{
- if(!particleTexture){
- particleTexture = new THREE.TextureLoader().load( Potree.resourcePath+'/textures/explode.png')
- }
- return particleTexture
- }
- const defaults = {
- position: new THREE.Vector3(0, 0 , 4),
-
- positionShape: Shape.SPHERE,
-
- positionRange : new THREE.Vector3(1,1,1), //cube
-
- positionRadius: 3, //sphere
-
- velocityShape: Shape.SPHERE,
-
- velocity: new THREE.Vector3(0.3,0.3, 2), //cube
- velocityRange: new THREE.Vector3(1, 1, 2),
- speed : 1, //sphere
- speedRange : 10,
-
- size: 0.4,
- sizeRange: 2,
- //sizeTween: new Tween( [0, 0.05, 0.3, 0.45], [0, 1, 3, 0.1] ),
- sizeTween: new Tween( ),
-
-
- color : new THREE.Vector3(1.0, 1.0, 1.0),
- colorRange : new THREE.Vector3(0.0, 0.0, 0.0),
- colorTween : new Tween(),
-
- opacity : 1.0,
- opacityRange : 0.0 ,
- opacityTween: new Tween( [0, 0.05, 0.3, 0.45], [1, 1, 0.5, 0] ),
- blendMode: THREE.AdditiveBlending,
-
- acceleration : 0.1,
- accelerationRange : 0.5,
-
- angle : 0,
- angleRange : 0,
- angleVelocity : 0,
- angleVelocityRange : 0,
- angleAcceleration : 0,
- angleAccelerationRange : 0,
-
- particlesPerSecond: 10,
- particleDeathAge: 1,
-
- }
- class ExplodeParticle extends THREE.Points{
- constructor(params) {
- super()
- this.particles = []
-
-
- this.age = 0
- this.alive = true
- this.deathAge = 60
- this.loop = true
-
-
- viewer.on('pageVisible', (state)=>{
- if(state){//重新一个个放出粒子,否则会一股脑儿全部出来,因为同时大于粒子周期了一起重新生成出现。
- setTimeout(()=>{//会先update一次delta为pageUnvisile的时间才触发
- //归零
- console.log('归零')
- this.age = 0;
-
- this.geometry.dispose()
-
- this.createParticles()
- },1)
- }
- })
-
-
- this.blendMode = THREE.NormalBlending
- this.setParameters(params)
- this.createParticles()
- }
- setParameters(params) {
- for ( var key in defaults ){
- let value = params[key] != void 0 ? params[key] : defaults[ key ]
- if(key == 'position') this.position.copy(value)
- else if(value instanceof Array && value[0] instanceof Array ) this[ key ] = new Tween(...value)
- else this[ key ] = value;
- }
- //Object.assign(this, params)
-
- this.particles = []
- this.age = 0.0
- this.alive = true
- this.particleCount = this.particlesPerSecond * Math.min(this.particleDeathAge, this.deathAge)
- this.geometry = new THREE.BufferGeometry()
- this.material = new THREE.ShaderMaterial({
- uniforms: {
- u_sampler: { value: this.texture || getTexture() }
- },
- vertexShader,
- fragmentShader,
- transparent: true,
- alphaTest: 0.5,
- depthTest: false,
- blending: THREE.AdditiveBlending
- })
-
- }
- createParticles() {
- const count = this.particleCount
- const positionArray = new Float32Array(count * 3)
- const colorArray = new Float32Array(count * 3)
- const sizeArray = new Float32Array(count)
- const angleArray = new Float32Array(count)
- const opacityArray = new Float32Array(count)
- const visibleArray = new Float32Array(count)
-
- for(let i = 0; i < count; i++) {
- const particle = this.createParticle()
- positionArray[i*3] = particle.position.x
- positionArray[i*3+1] = particle.position.y
- positionArray[i*3+2] = particle.position.z
- colorArray[i*3] = particle.color.r
- colorArray[i*3+1] = particle.color.g
- colorArray[i*3+2] = particle.color.b
- sizeArray[i] = particle.size
- angleArray[i] = particle.angel
- opacityArray[i] = particle.opacity
- visibleArray[i] = particle.alive
- this.particles[i] = particle
- }
- this.geometry.setAttribute('position', new THREE.BufferAttribute(positionArray, 3))
- this.geometry.setAttribute('color', new THREE.BufferAttribute(colorArray, 3))
- this.geometry.setAttribute('angle', new THREE.BufferAttribute(angleArray, 1))
- this.geometry.setAttribute('size', new THREE.BufferAttribute(sizeArray, 1))
- this.geometry.setAttribute('visible', new THREE.BufferAttribute(visibleArray, 1))
- this.geometry.setAttribute('opacity', new THREE.BufferAttribute(opacityArray, 1))
- this.material.blending = this.blendMode
- if(this.blendMode != THREE.NormalBlending) {
- this.material.depthTest = false
- }
-
- }
-
- createParticle() {
- const particle = new Particle()
- particle.sizeTween = this.sizeTween
- particle.colorTween = this.colorTween
- particle.opacityTween = this.opacityTween
- particle.deathAge = this.particleDeathAge
- if(this.positionShape == Shape.CUBE) {
- particle.position = util.randomVector3(new THREE.Vector3, this.positionRange)
- }
- if(this.positionShape == Shape.SPHERE) {
- const z = 2 * Math.random() - 1
- const t = Math.PI * 2 * Math.random()
- const r = Math.sqrt(1 - z*z)
- const vec3 = new THREE.Vector3(r * Math.cos(t), r * Math.sin(t), z)
- particle.position = vec3.multiplyScalar(this.positionRadius)
- }
- if(this.velocityShape == Shape.CUBE) {
- particle.velocity = util.randomVector3(this.velocity, this.velocityRange)
-
- }
- if(this.velocityShape == Shape.SPHERE) {
- const direction = particle.position.clone()
- const speed = util.randomValue(this.speed, this.speedRange)
- particle.velocity = direction.normalize().multiplyScalar(speed)
- }
- particle.acceleration = util.randomValue(this.acceleration, this.accelerationRange)
-
- particle.angle = util.randomValue(this.angle, this.angleRange)
- particle.angleVelocity = util.randomValue(this.angleVelocity, this.angleVelocityRange)
- particle.angleAcceleration = util.randomValue(this.angleAcceleration, this.angleAccelerationRange)
- particle.size = util.randomValue(this.size, this.sizeRange)
- const color = util.randomVector3(this.color, this.colorRange)
- particle.color = new THREE.Color().setHSL(color.x, color.y, color.z)
- particle.opacity = util.randomValue(this.opacity, this.opacityRange)
- particle.age = 0
- return particle
- }
- update(dt) {
- dt *= 0.5
-
- const recycleIndices = []
- const positionArray = this.geometry.attributes.position.array
- const opacityArray = this.geometry.attributes.opacity.array
- const visibleArray = this.geometry.attributes.visible.array
- const colorArray = this.geometry.attributes.color.array
- const angleArray = this.geometry.attributes.angle.array
- const sizeArray = this.geometry.attributes.size.array
- for(let i = 0; i < this.particleCount; i++) {
- const particle = this.particles[i]
- if(particle.alive) {
- particle.update(dt)
- if(particle.age > this.particleDeathAge) {
- particle.alive = 0.0
- recycleIndices.push(i)
- }
- positionArray[i*3] = particle.position.x
- positionArray[i*3+1] = particle.position.y
- positionArray[i*3+2] = particle.position.z
- colorArray[i*3] = particle.color.r
- colorArray[i*3+1] = particle.color.g
- colorArray[i*3+2] = particle.color.b
- visibleArray[i] = particle.alive
- opacityArray[i] = particle.opacity
- angleArray[i] = particle.angle
- sizeArray[i] = particle.size
- }
- }
-
- this.geometry.attributes.size.needsUpdate = true
- this.geometry.attributes.color.needsUpdate = true
- this.geometry.attributes.angle.needsUpdate = true
- this.geometry.attributes.visible.needsUpdate = true
- this.geometry.attributes.opacity.needsUpdate = true
- this.geometry.attributes.position.needsUpdate = true
- if(!this.alive) return
- if(this.age < this.particleDeathAge) {
- let startIndex = Math.round(this.particlesPerSecond * (this.age + 0))
- let endIndex = Math.round(this.particlesPerSecond * (this.age + dt))
- if(endIndex > this.particleCount) {
- endIndex = this.particleCount
- }
- for(let i = startIndex; i < endIndex; i++) {
- this.particles[i].alive = 1.0
- }
- }
- for(let j = 0;j < recycleIndices.length; j++) {
- let i = recycleIndices[j]
- this.particles[i] = this.createParticle()
- this.particles[i].alive = 1.0
- positionArray[i*3] = this.particles[i].position.x
- positionArray[i*3+1] = this.particles[i].position.y
- positionArray[i*3+2] = this.particles[i].position.z
- }
- this.geometry.attributes.position.needsUpdate = true
- this.age += dt
- if(this.age > this.deathAge && !this.loop) {
- this.alive = false
- }
- }
- }
- export default ExplodeParticle
|