123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274 |
- // 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
- }
- const boxGeo = new THREE.BoxBufferGeometry(1,1,1,1);
- const boxMat = new THREE.MeshBasicMaterial({wireframe:true, color:"#ffffff"})
- class FireParticle extends THREE.Points{
-
- constructor (prop) {
- super()
-
- for ( var key in prop ){
- this[key] = prop[key]
- }
-
-
-
- this.strength = this.strength || 1
-
-
-
- this.radius = prop.radius || 1;
- this.height = prop.height || 5;
-
- this.computeParams()
- this.geometry = this.createGeometry( this.radius, this.height, this.particleCount );
-
-
- if(this.color == void 0) this.color = 0xff3200
- this.createMaterial( ); //小蓝火:0x00338f
-
-
-
- //---?:
- this.velocity = new THREE.Vector3()
- this.acceleration = new THREE.Vector3()
-
- this.angle = 0
- this.angleVelocity = 0
- this.angleAcceleration = 0
- this.size = 16
-
- 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)
-
- let setSize = (e)=>{
- if(e.viewport.name != "MainView")return
- this.setSize(e)
- }
- let setFov = (e)=>{
- this.setFov(e.fov)
- }
-
- viewer.addEventListener('resize',setSize)
- viewer.addEventListener('fov_changed',setFov)
-
- this.addEventListener('dispose',()=>{
- viewer.removeEventListener('resize',setSize)
- viewer.removeEventListener('fov_changed',setFov)
- })
-
- }
-
- computeParams(){
- let length = (this.curve ? this.curve.wholeLength : 0) + this.radius * 2 //加上首尾的半径
-
-
- const minSize = 0.3, maxSize = 3, minRadiusBound = 0.3, maxRadiusBound = 10;
- this.size = minSize + (maxSize - minSize) * THREE.Math.smoothstep(this.radius, minRadiusBound, maxRadiusBound);
- //console.log('fire material particle size:', size )
-
- this.particleCount = Math.ceil( length * Math.sqrt(this.strength * this.height ) * this.radius / (this.size * this.size) * 25 )
- //console.log('fire particleCount',this.particleCount)
- }
- getPointsForBound(){
- return this.boundPoints; //可以用于expand实时bound的点, 不含particle的size等边距
- }
- getBound(points){ // points为生成点(圆心)
- this.boundPoints = []
- let boundingBox = new THREE.Box3()
-
-
- let margin = this.size * 0.13 + 0.3;
-
- points.forEach(bottom=>{
- let top = bottom.clone()
- top.z += this.height
- boundingBox.expandByPoint(bottom);
- boundingBox.expandByPoint(top);
- this.boundPoints.push(bottom,top)
- })
- let xyExpand = this.radius+margin
- boundingBox.expandByVector(new THREE.Vector3(xyExpand,xyExpand,margin))
- this.boundingBox = boundingBox
-
- /* if(!this.debugBox){
- this.debugBox = new THREE.Mesh(boxGeo, boxMat)
- this.add(this.debugBox)
- }
-
- this.debugBox.scale.copy(boundingBox.getSize(new THREE.Vector3))
- this.debugBox.position.copy(boundingBox.getCenter(new THREE.Vector3)) */
-
- }
- createGeometry( radius, height, particleCount){
- let geometry = new THREE.BufferGeometry()
-
-
- 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
- //得到的点不太均匀,两端容易点少。
- this.getBound(points)
-
- }else{
- this.getBound(this.positions)
- }
-
-
- 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 * height/2 + height/2; //不太明白这句为什么能达到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.radius, this.height, this.particleCount )
- this.material.uniforms.size.value = this.size
- }
- createMaterial(){
-
-
- const material = new THREE.ShaderMaterial( {
- uniforms:{
- color: { type: "c", value: new THREE.Color(this.color) },
- size: { type: "f", value: this.size},
- u_sampler: { type: "t", value: getTexture() },
- time: { type: "f", value: 0.0 },
- heightOfNearPlane: { type: "f", value:0}, //相对far ,以确保画面缩放时点的大小也会缩放
- height :{ type: "f", value:this.height} ,
- },
- vertexShader,
- fragmentShader,
- blending: THREE.AdditiveBlending, //加法融合模式 glBlendFunc(GL_ONE, GL_ONE)
- depthTest: true,
- depthWrite: false,
- transparent: true
- } );
- this.material = material
- this.setPerspective(this.fov, this.screenHeight)
- }
- 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){
- if(!Potree.Utils.getObjVisiByReason(this,'force')){//被手动隐藏了
- return
- }
- if(!Potree.Utils.isInsideFrustum(this.boundingBox, viewer.scene.getActiveCamera())){
- Potree.Utils.updateVisible(this,'isInsideFrustum', false ) //不在视野范围
- //console.log('unvi')
- return
- }else{
- Potree.Utils.updateVisible(this,'isInsideFrustum', true )
- }
- delta *= 1//更改速度
-
- this.material.uniforms.time.value = (this.material.uniforms.time.value + delta) % 1;
- }
-
- dispose(){
- this.geometry.dispose();
- this.material.dispose();
- this.dispatchEvent('dispose')
- }
- }
- export default FireParticle
|