// import { vertexShader, fragmentShader } from './shaders' // import Tween from './tween' import * as THREE from "../../../../libs/three.js/build/three.module.js"; import { vertexShader, fragmentShader } from './shader.js' let ONE_SPRITE_ROW_LENGTH = 0.25 //对应着色器的0.25 let texture const getTexture = ()=>{ if(!texture){ texture = new THREE.TextureLoader().load( Potree.resourcePath+'/textures/fire.png') } return texture } class FireParticle extends THREE.Points{ constructor (prop) { super() for ( var key in prop ){ this[key] = prop[key] } this.density = this.density || 1 this.fireRadius = prop.fireRadius || 1; this.fireHeight = prop.fireHeight || 5; this.computeParams() this.geometry = this.createGeometry( this.fireRadius, this.fireHeight, this.particleCount ); this.material = this.createMaterial( prop.fov, 0xff3200 ); //小蓝火:0x00338f //---?: this.velocity = new THREE.Vector3() this.acceleration = new THREE.Vector3() this.angle = 0 this.angleVelocity = 0 this.angleAcceleration = 0 this.size = 16 this.color = new THREE.Color() this.opacity = 1 this.age = 0 this.alive = 0 this.sizeTween = null this.colorTween = null this.opacityTween = null this.setSize({viewport:viewer.mainViewport}) this.setFov(viewer.fov) viewer.addEventListener('resize',(e)=>{ if(e.viewport.name != "MainView")return this.setSize(e) }) viewer.addEventListener('fov_changed',(e)=>{ this.setFov(e.fov) }) } computeParams(){ let length = (this.curve ? this.curve.wholeLength : 0) + this.fireRadius * 2 //加上首尾的半径 this.particleCount = Math.ceil( this.fireRadius * this.fireHeight * length * this.density * 5 ) console.log('fire particleCount',this.particleCount) } createGeometry( radius, height, particleCount){ let geometry = new THREE.BufferGeometry() var halfHeight = height * 0.5; let count , points if(this.positions.length>1){ const spaceDis = 0.2;//间隔距离 count = Math.ceil(this.curve.wholeLength / spaceDis) + 1 console.log('count', count) points = this.curve.getSpacedPoints( count ); //得到的数量会比count多一个 count = points.length //得到的点不太均匀,两端容易点少。 } var position = new Float32Array(particleCount * 3); var randam = new Float32Array(particleCount); var sprite = new Float32Array(particleCount); var centerHeight = new Float32Array(particleCount); for (var i = 0; i < particleCount; i++) { var center = new THREE.Vector3().copy(this.positions.length>1 ? points[Math.floor(i/particleCount * count)] : this.positions[0]) centerHeight[i] = center.z if (i === 0) { // to avoid going out of Frustum position[i * 3 + 0] = center.x; position[i * 3 + 1] = center.y; position[i * 3 + 2] = center.z; }else{ var r = Math.sqrt(Math.random()) * radius; var angle = Math.random() * 2 * Math.PI; position[i * 3 + 0] = center.x + Math.cos(angle) * r; position[i * 3 + 1] = center.y + Math.sin(angle) * r; position[i * 3 + 2] = center.z + (radius - r) / radius * halfHeight + halfHeight; //不太明白这句为什么能达到height高度 sprite[i] = 0.25 * (Math.random() * 4 | 0); randam[i] = Math.random(); //center在底部 } } geometry.setAttribute('centerHeight', new THREE.BufferAttribute(centerHeight, 1)); geometry.setAttribute('position', new THREE.BufferAttribute(position, 3)); geometry.setAttribute('randam', new THREE.BufferAttribute(randam, 1)); geometry.setAttribute('sprite', new THREE.BufferAttribute(sprite, 1)); return geometry; } updateGeometry(){ this.computeParams() this.geometry.dispose() this.geometry = this.createGeometry( this.fireRadius, this.fireHeight, this.particleCount ) } createMaterial(fov, color){ const material = new THREE.ShaderMaterial( { uniforms:{ color: { type: "c", value: new THREE.Color(color) }, size: { type: "f", value: THREE.Math.clamp(this.fireRadius * 1.2, 0.5, 5)}, u_sampler: { type: "t", value: getTexture() }, time: { type: "f", value: 0.0 }, heightOfNearPlane: { type: "f", value:0}, //相对far ,以确保画面缩放时点的大小也会缩放 fireHeight :{ type: "f", value:this.fireHeight} , }, vertexShader, fragmentShader, blending: THREE.AdditiveBlending, //加法融合模式 glBlendFunc(GL_ONE, GL_ONE) depthTest: true, depthWrite: false, transparent: true } ); return material } setSize(e){ let viewport = e.viewport this.screenHeight = viewport.resolution.y this.setPerspective(this.fov, this.screenHeight) } setFov(fov){ this.fov = fov this.setPerspective(this.fov, this.screenHeight) } setPerspective(fov, height){ //this.uniforms.heightOfNearPlane.value = Math.abs(height / (2 * Math.tan(THREE.Math.degToRad(fov * 0.5)))); let far = Math.abs(height / (2 * Math.tan(THREE.Math.degToRad(fov * 0.5)))); this.material.uniforms.heightOfNearPlane.value = far } update(delta){ delta *= 1//更改速度 this.material.uniforms.time.value = (this.material.uniforms.time.value + delta) % 1; } } export default FireParticle