FireParticle.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. // import { vertexShader, fragmentShader } from './shaders'
  2. // import Tween from './tween'
  3. import * as THREE from "../../../../libs/three.js/build/three.module.js";
  4. import { vertexShader, fragmentShader } from './shader.js'
  5. let ONE_SPRITE_ROW_LENGTH = 0.25 //对应着色器的0.25
  6. let texture
  7. const getTexture = ()=>{
  8. if(!texture){
  9. texture = new THREE.TextureLoader().load( Potree.resourcePath+'/textures/fire.png')
  10. }
  11. return texture
  12. }
  13. class FireParticle extends THREE.Points{
  14. constructor (prop) {
  15. super()
  16. for ( var key in prop ){
  17. this[key] = prop[key]
  18. }
  19. this.density = this.density || 1
  20. this.fireRadius = prop.fireRadius || 1;
  21. this.fireHeight = prop.fireHeight || 5;
  22. this.computeParams()
  23. this.geometry = this.createGeometry( this.fireRadius, this.fireHeight, this.particleCount );
  24. this.material = this.createMaterial( prop.fov, 0xff3200 ); //小蓝火:0x00338f
  25. //---?:
  26. this.velocity = new THREE.Vector3()
  27. this.acceleration = new THREE.Vector3()
  28. this.angle = 0
  29. this.angleVelocity = 0
  30. this.angleAcceleration = 0
  31. this.size = 16
  32. this.color = new THREE.Color()
  33. this.opacity = 1
  34. this.age = 0
  35. this.alive = 0
  36. this.sizeTween = null
  37. this.colorTween = null
  38. this.opacityTween = null
  39. this.setSize({viewport:viewer.mainViewport})
  40. this.setFov(viewer.fov)
  41. viewer.addEventListener('resize',(e)=>{
  42. if(e.viewport.name != "MainView")return
  43. this.setSize(e)
  44. })
  45. viewer.addEventListener('fov_changed',(e)=>{
  46. this.setFov(e.fov)
  47. })
  48. }
  49. computeParams(){
  50. let length = (this.curve ? this.curve.wholeLength : 0) + this.fireRadius * 2 //加上首尾的半径
  51. this.particleCount = Math.ceil( this.fireRadius * this.fireHeight * length * this.density * 5 )
  52. console.log('fire particleCount',this.particleCount)
  53. }
  54. createGeometry( radius, height, particleCount){
  55. let geometry = new THREE.BufferGeometry()
  56. var halfHeight = height * 0.5;
  57. let count , points
  58. if(this.positions.length>1){
  59. const spaceDis = 0.2;//间隔距离
  60. count = Math.ceil(this.curve.wholeLength / spaceDis) + 1
  61. console.log('count', count)
  62. points = this.curve.getSpacedPoints( count ); //得到的数量会比count多一个
  63. count = points.length
  64. //得到的点不太均匀,两端容易点少。
  65. }
  66. var position = new Float32Array(particleCount * 3);
  67. var randam = new Float32Array(particleCount);
  68. var sprite = new Float32Array(particleCount);
  69. var centerHeight = new Float32Array(particleCount);
  70. for (var i = 0; i < particleCount; i++) {
  71. var center = new THREE.Vector3().copy(this.positions.length>1 ? points[Math.floor(i/particleCount * count)] : this.positions[0])
  72. centerHeight[i] = center.z
  73. if (i === 0) {
  74. // to avoid going out of Frustum
  75. position[i * 3 + 0] = center.x;
  76. position[i * 3 + 1] = center.y;
  77. position[i * 3 + 2] = center.z;
  78. }else{
  79. var r = Math.sqrt(Math.random()) * radius;
  80. var angle = Math.random() * 2 * Math.PI;
  81. position[i * 3 + 0] = center.x + Math.cos(angle) * r;
  82. position[i * 3 + 1] = center.y + Math.sin(angle) * r;
  83. position[i * 3 + 2] = center.z + (radius - r) / radius * halfHeight + halfHeight; //不太明白这句为什么能达到height高度
  84. sprite[i] = 0.25 * (Math.random() * 4 | 0);
  85. randam[i] = Math.random();
  86. //center在底部
  87. }
  88. }
  89. geometry.setAttribute('centerHeight', new THREE.BufferAttribute(centerHeight, 1));
  90. geometry.setAttribute('position', new THREE.BufferAttribute(position, 3));
  91. geometry.setAttribute('randam', new THREE.BufferAttribute(randam, 1));
  92. geometry.setAttribute('sprite', new THREE.BufferAttribute(sprite, 1));
  93. return geometry;
  94. }
  95. updateGeometry(){
  96. this.computeParams()
  97. this.geometry.dispose()
  98. this.geometry = this.createGeometry( this.fireRadius, this.fireHeight, this.particleCount )
  99. }
  100. createMaterial(fov, color){
  101. const material = new THREE.ShaderMaterial( {
  102. uniforms:{
  103. color: { type: "c", value: new THREE.Color(color) },
  104. size: { type: "f", value: THREE.Math.clamp(this.fireRadius * 1.2, 0.5, 5)},
  105. u_sampler: { type: "t", value: getTexture() },
  106. time: { type: "f", value: 0.0 },
  107. heightOfNearPlane: { type: "f", value:0}, //相对far ,以确保画面缩放时点的大小也会缩放
  108. fireHeight :{ type: "f", value:this.fireHeight} ,
  109. },
  110. vertexShader,
  111. fragmentShader,
  112. blending: THREE.AdditiveBlending, //加法融合模式 glBlendFunc(GL_ONE, GL_ONE)
  113. depthTest: true,
  114. depthWrite: false,
  115. transparent: true
  116. } );
  117. return material
  118. }
  119. setSize(e){
  120. let viewport = e.viewport
  121. this.screenHeight = viewport.resolution.y
  122. this.setPerspective(this.fov, this.screenHeight)
  123. }
  124. setFov(fov){
  125. this.fov = fov
  126. this.setPerspective(this.fov, this.screenHeight)
  127. }
  128. setPerspective(fov, height){
  129. //this.uniforms.heightOfNearPlane.value = Math.abs(height / (2 * Math.tan(THREE.Math.degToRad(fov * 0.5))));
  130. let far = Math.abs(height / (2 * Math.tan(THREE.Math.degToRad(fov * 0.5))));
  131. this.material.uniforms.heightOfNearPlane.value = far
  132. }
  133. update(delta){
  134. delta *= 1//更改速度
  135. this.material.uniforms.time.value = (this.material.uniforms.time.value + delta) % 1;
  136. }
  137. }
  138. export default FireParticle