Browse Source

fix: 调整位置

xzw 3 năm trước cách đây
mục cha
commit
274843dc83
72 tập tin đã thay đổi với 1616 bổ sung725 xóa
  1. 20 16
      note笔记笔记笔记.txt
  2. 3 2
      src/PointCloudOctree.js
  3. 15 15
      src/Potree.js
  4. 1 1
      src/Potree_update_visibility.js
  5. 1 1
      src/exporter/DXFExporter.js
  6. 1 1
      src/exporter/GeoJSONExporter.js
  7. 1 1
      src/modules/Images360/Images360.js
  8. 1 1
      src/modules/Images360/Panorama.js
  9. 2 2
      src/modules/clipModel/Clip.js
  10. 3 3
      src/modules/siteModel/BuildingBox.js
  11. 5 5
      src/modules/siteModel/SiteModel.js
  12. 0 584
      src/navigation/RouteGuider.js
  13. 2 2
      src/viewer/Axis.js
  14. 0 0
      src/objects/Label.js
  15. 2 2
      src/utils/Magnifier.js
  16. 0 0
      src/objects/Reticule.js
  17. 0 0
      src/objects/Sprite.js
  18. 2 2
      src/TextSprite.js
  19. 100 0
      src/objects/fireParticle/explode.html
  20. 310 0
      src/objects/fireParticle/explode/ExplodeParticle.js
  21. 56 0
      src/objects/fireParticle/explode/Particle.js
  22. 26 0
      src/objects/fireParticle/explode/Tween.js
  23. 18 0
      src/objects/fireParticle/explode/Util.js
  24. 4 0
      src/objects/fireParticle/explode/const.js
  25. 38 0
      src/objects/fireParticle/explode/shader.js
  26. 96 0
      src/objects/fireParticle/fire.html
  27. 174 0
      src/objects/fireParticle/fire/FireParticle.js
  28. 45 0
      src/objects/fireParticle/fire/shader.js
  29. BIN
      src/objects/fireParticle/images/checkerboard.jpg
  30. BIN
      src/objects/fireParticle/images/circle-particle.png
  31. BIN
      src/objects/fireParticle/images/explode.png
  32. BIN
      src/objects/fireParticle/images/explode1.png
  33. BIN
      src/objects/fireParticle/images/groundcolor.jpg
  34. BIN
      src/objects/fireParticle/images/groundnormal.jpg
  35. BIN
      src/objects/fireParticle/images/plane.png
  36. BIN
      src/objects/fireParticle/images/smoke (1).png
  37. BIN
      src/objects/fireParticle/images/smoke.png
  38. BIN
      src/objects/fireParticle/images/smokeparticle.png
  39. 87 0
      src/objects/fireParticle/smoke.html
  40. 57 0
      src/objects/fireParticle/smoke/Particle.js
  41. 348 0
      src/objects/fireParticle/smoke/SmokeParticle.js
  42. 26 0
      src/objects/fireParticle/smoke/Tween.js
  43. 38 0
      src/objects/fireParticle/smoke/shader.js
  44. 5 5
      src/utils/AnnotationTool.js
  45. 1 1
      src/utils/Box3Helper.js
  46. 1 1
      src/utils/ClipVolume.js
  47. 2 2
      src/utils/ClippingTool.js
  48. 2 2
      src/utils/Compass.js
  49. 8 8
      src/utils/Measure.js
  50. 10 9
      src/utils/MeasuringTool.js
  51. 1 1
      src/utils/PolygonClipVolume.js
  52. 2 2
      src/utils/Profile.js
  53. 3 3
      src/utils/ProfileTool.js
  54. 4 4
      src/utils/ScreenBoxSelectTool.js
  55. 1 1
      src/utils/SpotLightHelper.js
  56. 2 2
      src/utils/TransformationTool.js
  57. 1 1
      src/utils/Volume.js
  58. 3 3
      src/utils/VolumeTool.js
  59. 3 3
      src/utils/ctrlPolygon.js
  60. 5 5
      src/utils/mapClipBox.js
  61. 2 2
      src/settings.js
  62. 45 1
      src/start.js
  63. 4 4
      src/utils.js
  64. 1 1
      src/viewer/EDLRenderer.js
  65. 1 1
      src/viewer/HQSplatRenderer.js
  66. 1 1
      src/viewer/LoadProject.js
  67. 1 1
      src/viewer/PropertyPanels/DistancePanel.js
  68. 3 3
      src/viewer/PropertyPanels/PropertiesPanel.js
  69. 1 1
      src/viewer/PropertyPanels/VolumePanel.js
  70. 1 1
      src/viewer/Scene.js
  71. 5 5
      src/viewer/sidebar.js
  72. 15 13
      src/viewer/viewer.js

+ 20 - 16
note笔记笔记笔记.txt

@@ -18,19 +18,19 @@ http://indoor.popsmart.cn:8084/sxswsw-sx/?vlon=5.25&vlat=0.03&fov=100.0&pc=true&
 
 
 测试服务器可以:
-t-CwfhfqJ 大佛 有平面图 (贴图和点云有微微错位) 
+t-CwfhfqJ 大佛 有平面图 
 t-e2Kb2iU 隧道 
 t-8KbK1JjubE  回家湘
 t-Y22JxCS7sP 小区
 t-8BCqxQAr93 小会议室
-t-AY03FoVZhm 一楼 
+t-AY03FoVZhm 一楼      (编辑完空间模型的)
 t-GusppsiKEC 字节跳动楼外场景
 t-YLZ5XAALl7 燃气管线街景
 SS-t-P6zBR73Gke 燃气站
 t-QaHxu5Nmn3 一楼门口
 	--多楼层漫游点:
 
-
+ 
 
 
 正式服务器:
@@ -54,8 +54,7 @@ Aa123456
 
 ==========================================================================================
 
-待完善:
-
+ 
 
 
 
@@ -85,7 +84,7 @@ moveSpeed 、 地图的自适应缩放
 手机的测量线marker太小很难拖拽
 点击测量线后,或执行了setView后,如果再次移动镜头或再次setView,要取消之前的setView
 
-刚开始加载高质量点云可以在rendertarget内
+刚开始加载高质量点云可以在rendertarget内。或者有没有办法加载了不绘制
 
 地理位置修改了的话,没有绑定到数据集上的测量线怎么办? 要不还是默认放第一个数据集?
 
@@ -179,29 +178,34 @@ sitemodel
 	移除点、结束绘画、去掉最后一个点
 	吸附点、线、90度
 
- 
+  
 
-点击实体后是到哪个漫游点? 如果没有漫游点呢?(找离bounding最近的漫游点吧)  
-	但是为何仿版无论空间模型怎么改都飞到同一个点呢
 
+cursor总感觉应该打开。 但是会比较乱,而且用reticule也可以试探出。target比较重要,而非当前位置
 
-cursor总感觉应该打开
 --------------------
 
 
-出现过marker无法松开的情况(加载的数据),但是再选中房间又可以了
-·是dropMarker时 因为有相同点 return continueDrag了
-·数据里竟然有五个点,后两个相同。应该是添加时没删除
-·是绘制完前删最后一个点后没有发送update
 
 
 
+ 
+
+
+出现过mainViewer中的reticule位置改变特别慢
+
+
+
+
+
+
+
+时间久了烟会成一团?
+
 
-地图上 双击似乎应该 flytopano
 
 
 
 
 
-出现过mainViewer中的reticule位置改变特别慢
   

+ 3 - 2
src/PointCloudOctree.js

@@ -1,4 +1,5 @@
 
+
 import * as THREE from "../libs/three.js/build/three.module.js";
 import {PointCloudTree, PointCloudTreeNode} from "./PointCloudTree.js";
 import {PointCloudOctreeGeometryNode} from "./PointCloudOctreeGeometry.js";
@@ -8,7 +9,7 @@ import math from "./utils/math.js";
 
 import {MeshDraw} from "./utils/DrawUtil.js";
 import searchRings from "./utils/searchRings.js";
-import {TextSprite} from './TextSprite'
+import {TextSprite} from './objects/TextSprite'
 
 
 
@@ -1815,7 +1816,7 @@ export class PointCloudOctree extends PointCloudTree {
         }
         
         
-        console.log('changePointSize  '  + this.dataset_id + '  , num : ' + num + ' , size : ' + this.material.size, this.material.spacing)
+        //console.log('changePointSize  '  + this.dataset_id + '  , num : ' + num + ' , size : ' + this.material.size, this.material.spacing)
 
          
     }  

+ 15 - 15
src/Potree.js

@@ -16,7 +16,7 @@ export * from "./Points.js";
 export * from "./Potree_update_visibility.js";
 export * from "./PotreeRenderer.js";
 export * from "./ProfileRequest.js";
-export * from "./TextSprite.js";
+//export * from "./TextSprite.js";
 export * from "./utils.js";
 export * from "./Version.js";
 export * from "./WorkerPool.js";
@@ -41,23 +41,23 @@ export * from "./loader/PointAttributes.js";
 export * from "./loader/ShapefileLoader.js";
 export * from "./loader/GeoPackageLoader.js";
 
-export * from "./utils/Box3Helper.js";
-export * from "./utils/ClippingTool.js";
-export * from "./utils/ClipVolume.js";
+export * from "./objects/tool/Box3Helper.js";
+export * from "./objects/tool/ClippingTool.js";
+export * from "./objects/tool/ClipVolume.js";
 export * from "./utils/GeoTIFF.js";
-export * from "./utils/Measure.js";
-export * from "./utils/MeasuringTool.js";
+export * from "./objects/tool/Measure.js";
+export * from "./objects/tool/MeasuringTool.js";
 export * from "./utils/Message.js";
 export * from "./utils/PointCloudSM.js";
-export * from "./utils/PolygonClipVolume.js";
-export * from "./utils/Profile.js";
-export * from "./utils/ProfileTool.js";
-export * from "./utils/ScreenBoxSelectTool.js";
-export * from "./utils/SpotLightHelper.js";
-export * from "./utils/TransformationTool.js";
-export * from "./utils/Volume.js";
-export * from "./utils/VolumeTool.js";
-export * from "./utils/Compass.js";
+export * from "./objects/tool/PolygonClipVolume.js";
+export * from "./objects/tool/Profile.js";
+export * from "./objects/tool/ProfileTool.js";
+export * from "./objects/tool/ScreenBoxSelectTool.js";
+export * from "./objects/tool/SpotLightHelper.js";
+export * from "./objects/tool/TransformationTool.js";
+export * from "./objects/tool/Volume.js";
+export * from "./objects/tool/VolumeTool.js";
+export * from "./objects/tool/Compass.js";
 
 export * from "./viewer/viewer.js";
 export * from "./viewer/Scene.js";

+ 1 - 1
src/Potree_update_visibility.js

@@ -1,7 +1,7 @@
 
 import * as THREE from "../libs/three.js/build/three.module.js";
 import {ClipTask, ClipMethod} from "./defines.js";
-import {Box3Helper} from "./utils/Box3Helper.js";
+import {Box3Helper} from "./objects/tool/Box3Helper.js";
 
 export function updatePointClouds(pointclouds,camera, areaSize /* renderer */){
  

+ 1 - 1
src/exporter/DXFExporter.js

@@ -7,7 +7,7 @@
  */
 
 import * as THREE from "../../libs/three.js/build/three.module.js";
-import {Measure} from "../utils/Measure.js";
+import {Measure} from "../objects/tool/Measure.js";
 
 export class DXFExporter {
 

+ 1 - 1
src/exporter/GeoJSONExporter.js

@@ -6,7 +6,7 @@
  *
  */
 
-import {Measure} from "../utils/Measure.js";
+import {Measure} from "../objects/tool/Measure.js";
 
 export class GeoJSONExporter{
 

+ 1 - 1
src/modules/Images360/Images360.js

@@ -1,7 +1,7 @@
 
 import * as THREE from "../../../libs/three.js/build/three.module.js";
 import { EventDispatcher } from "../../EventDispatcher.js";
-import {TextSprite} from "../../TextSprite.js";
+import {TextSprite} from "../../objects/TextSprite.js";
 import ModelTextureMaterial from "./ModelTextureMaterial.js";
 import Common from "../../utils/Common.js";
 import math from "../../utils/math.js";

+ 1 - 1
src/modules/Images360/Panorama.js

@@ -4,7 +4,7 @@ import TileUtils from './tile/TileUtils'
 import { PanoRendererEvents, PanoramaEvents, PanoSizeClass} from '../../defines'
 import math from '../../utils/math'
 import { EventDispatcher } from "../../EventDispatcher.js";
-import {TextSprite} from '../../TextSprite'
+import {TextSprite} from '../../objects/TextSprite'
 
 var texLoader = new THREE.TextureLoader()
 

+ 2 - 2
src/modules/clipModel/Clip.js

@@ -1,7 +1,7 @@
 import * as THREE from "../../../libs/three.js/build/three.module.js";
-import {BoxVolume} from '../../utils/Volume'
+import {BoxVolume} from '../../objects/tool/Volume'
 import {  ClipTask, ClipMethod} from "../../defines.js"
-import {mapClipBox} from '../../utils/mapClipBox'
+import {mapClipBox} from '../../objects/tool/mapClipBox'
 import Common from '../../utils/Common'
 import {Images360} from '../Images360/Images360'
 

+ 3 - 3
src/modules/siteModel/BuildingBox.js

@@ -1,9 +1,9 @@
 
 import * as THREE from "../../../libs/three.js/build/three.module.js";
-import {ctrlPolygon} from '../../utils/ctrlPolygon'
+import {ctrlPolygon} from '../../objects/tool/ctrlPolygon'
 import {LineDraw, MeshDraw } from "../../utils/DrawUtil";  
 import math  from "../../utils/math";
-import Sprite from '../../viewer/Sprite'
+import Sprite from '../../objects/Sprite'
 /* import {config} from '../settings' */
 import searchRings from "../../utils/searchRings.js";
 
@@ -18,7 +18,7 @@ let getFaceMat = (name)=>{
     if(!faceMats){ //navvis材质可以搜gridTexture
         let gridTex = texLoader.load( Potree.resourcePath+'/textures/gridmap.png' ) 
             gridTex.wrapS = gridTex.wrapT = THREE.RepeatWrapping   
-            gridTex.repeat.set(0.5,0.5)//放大一些
+            //gridTex.repeat.set(0.5,0.5)//放大一些
         faceMats = { 
             dataset: new THREE.MeshStandardMaterial({
                 color:812922,   

+ 5 - 5
src/modules/siteModel/SiteModel.js

@@ -373,8 +373,8 @@ var SiteModel = {
         
         
         if(buildType == 'building' ){
-            zMax = zMin //强制变得一样,作为基底。如果有必要,保存时再算真实的zMax
-        } 
+            zMax = zMin //强制变得一样,作为基底。如果有必要,保存时再算真实的zMax。目前zMin没有保存所以数据是错的,会直接根据floor计算
+        }  
         
         
         
@@ -511,11 +511,11 @@ var SiteModel = {
     
     
     updateBuildingZ:function(building){
-        if(!this.editing)return
+         
         building.buildChildren = building.buildChildren.sort((e,a)=>e.zMin-a.zMin)//从低到高排序
-        building.zMin = building.zMax = building.buildChildren[0].zMin  //基底高度
+        building.zMin = building.zMax = building.buildChildren[0].zMin  //基底高度 
         //building.zMax = building.buildChildren[building.buildChildren.length-1].zMax
-        building.update({dontUpdateChildren:true})
+        if(this.editing) building.update({dontUpdateChildren:true})
     },
    
     

+ 0 - 584
src/navigation/RouteGuider.js

@@ -1,584 +0,0 @@
-
-import * as THREE from "../../libs/three.js/build/three.module.js";
-import {Utils} from "../utils.js";
-import { EventDispatcher } from "../EventDispatcher.js";
-import Sprite from '../viewer/Sprite'
-import Common from "../utils/Common.js";
-import browser from '../utils/browser'
-const texLoader = new THREE.TextureLoader()
-const arrowSpacing = 1 //间隔
-const arrowSize = arrowSpacing * 0.5
-const planeGeo = new THREE.PlaneBufferGeometry(1,1);
-
-const sphereSizeInfo = {
-      nearBound : 2, scale:arrowSize, restricMeshScale : true,
-}
-//const arrowsShowingCount = 25; //场景里最多展示多少个箭头
-const arrowShowMinDis = 10
-export class RouteGuider extends EventDispatcher{
-    constructor () {
-		super();
-        
-        this.route = [];
-        this.curve = []
-        this.scenePoints = []
-        this.sceneMeshGroup = new THREE.Object3D;
-        this.mapMeshGroup = new THREE.Object3D;
-        this.generateDeferred;
-        viewer.addEventListener('loadPointCloudDone',this.init.bind(this))
-        
-        this.lastResult;//保存上一个的结果,以便于反向
-    
-    }
-    init(){
-        if(this.inited) return;
-        
-        let zoom;
-        viewer.mapViewer.addEventListener('camera_changed', e => {
-            if(!this.routeStart || !this.routeEnd) return   
-            var camera = e.viewport.camera
-           
-            Common.intervalTool.isWaiting('routeCameraInterval', ()=>{ //延时update,防止卡顿
-                if(camera.zoom != zoom){ 
-                    console.log('updateMapArrows')
-                    this.updateMapArrows(true)
-                    zoom = camera.zoom         
-                    return true 
-                } 
-            }, browser.isMobile()?500:200)
-        })
-        
-   
-        
-       
-        let lastPos = new THREE.Vector3
-        viewer.addEventListener('camera_changed', e => {
-            if(!this.routeStart || !this.routeEnd) return
-            Common.intervalTool.isWaiting('routeCameraInterval', ()=>{ //延时update,防止卡顿
-                let currPos = viewer.scene.getActiveCamera().position
-             
-                if(!currPos.equals(lastPos)){
-                    lastPos.copy(currPos)
-                    this.updateArrowDisplay() 
-                     
-                    return true 
-                }
-            }, 1000)
-            
-            
-                        
-        })
-        
-        
-        
-        var polesMats = {
-            shadowMat: new THREE.MeshBasicMaterial({ 
-                transparent:true, depthTest:false,
-                map: texLoader.load(Potree.resourcePath+'/textures/pano_instruction_bottomMarker.png' )  
-            }),
-            sphereMat : new THREE.MeshBasicMaterial({
-                transparent:true, depthTest:false,
-                map: texLoader.load(Potree.resourcePath+'/textures/whiteCircle.png' )  
-            }), 
-            hatMats:{
-                start:  new THREE.MeshBasicMaterial({
-                    transparent:true, depthTest:false,
-                    map: texLoader.load(Potree.resourcePath+'/textures/pano_instruction_start_route.png' )  
-                }),
-                end:  new THREE.MeshBasicMaterial({
-                    transparent:true, depthTest:false,
-                    map: texLoader.load(Potree.resourcePath+'/textures/pano_instruction_target_reached.png' )  
-                }) 
-            }
-        }
-        polesMats.shadowMat.map.anisotropy = 4 
-        
-        this.poleStart = this.createPole(polesMats, 'start') 
-        this.poleEnd = this.createPole(polesMats, 'end') 
-        
-        this.sceneMeshGroup.add(this.poleStart)
-        this.sceneMeshGroup.add(this.poleEnd)
-        
-        
-        let map = texLoader.load(Potree.resourcePath+'/textures/routePoint_panorama.png' )  
-        map.anisotropy = 4 // 各向异性过滤 .防止倾斜模糊 
-        this.arrow = new THREE.Mesh(planeGeo, new THREE.MeshBasicMaterial({
-            transparent:true,
-            depthTest:false, 
-            map
-        }))
-        this.arrow.scale.set(arrowSize,arrowSize,arrowSize)
-        viewer.setObjectLayers(this.arrow, 'sceneObjects' )
-         
-        
-        this.testArrow = this.arrow.clone();
-        this.testArrow.material = this.arrow.material.clone()
-        this.testArrow.material.color = 'red'
-        
-        this.arrows = new THREE.Object3D;
-        this.sceneMeshGroup.add(this.arrows)
-        
-        viewer.setObjectLayers(this.sceneMeshGroup, 'sceneObjects' )
-        //this.sceneMeshGroup.traverse(e=>e.renderOrder = 90)
-        
-        
-        viewer.scene.scene.add(this.sceneMeshGroup);
-        this.sceneMeshGroup.visible = /* this.poleStart.visibile = this.poleEnd.visibile = */ false
-       
-        //-------------map---------------------
-        
-        /* this.mapMarkStart = new THREE.Mesh( planeGeo, new THREE.MeshBasicMaterial({
-            transparent:true, depthTest:false,
-            map: texLoader.load(Potree.resourcePath+'/textures/map_instruction_start_route.png' )  
-        }))
-        this.mapMarkEnd = new THREE.Mesh( planeGeo, new THREE.MeshBasicMaterial({
-            transparent:true, depthTest:false,
-            map: texLoader.load(Potree.resourcePath+'/textures/map_instruction_target_reached.png' )  
-        }))
-        this.mapMarkStart.renderOrder = this.mapMarkEnd.renderOrder = 2//在箭头之上 */
-        
-        this.mapArrow = new THREE.Mesh( planeGeo, new THREE.MeshBasicMaterial({
-            transparent:true, depthTest:false,
-            map: texLoader.load(Potree.resourcePath+'/textures/routePoint_map_fsna.png' )  
-        }))
-        this.mapArrow.scale.set(arrowSize,arrowSize,arrowSize)
-        this.mapArrows = new THREE.Object3D;
-        this.mapArrows.name = 'mapArrows'
-         
-        
-        
-        this.mapMeshGroup.add(this.mapArrows)
-        this.mapMeshGroup.name = 'mapRouteLayer'
-        this.mapMeshGroup.visible = false
-        
-        viewer.mapViewer.emit('add',{object:this.mapMeshGroup, name:'route'})
-        this.mapArrow.layers.mask = this.mapArrows.layers.mask // 修改成和map中的layer一样的
-        
-        this.inited = true
-    }
-    
-    
-    createPole(polesMats, name){
-        const height = 1.5, sphereCount = 6, shadowSize = sphereSizeInfo.scale,  sphereSize = 0.04
-        
-        var group = new THREE.Object3D;
-            group.name = 'pole_'+name
-        var shadow = new THREE.Mesh(planeGeo,polesMats.shadowMat)
-        shadow.scale.set(shadowSize,shadowSize,shadowSize)
-        var sliceDis = height / (sphereCount+1);
-        group.add(shadow) 
-         
-        for(let i=0;i<sphereCount;i++){
-            var sphere = new Sprite({mat: polesMats.sphereMat}) 
-            sphere.position.set(0,0,sliceDis*(i+1))
-            sphere.scale.set(sphereSize,sphereSize,sphereSize);
-            group.add(sphere)
-        }
-        
-        var hatSphere = new Sprite({mat: polesMats.hatMats[name], sizeInfo:sphereSizeInfo}) 
-        hatSphere.position.set(0,0,height)
-        hatSphere.scale.copy(shadow.scale)
-        group.add(hatSphere)
-        return group
-    }
-    
-    
-    addTestArrow(){
-        
-    }
-    
-    addArrow(position){ 
-        var arrow = this.arrow.clone()
-        arrow.position.copy(position); 
-        this.arrows.add(arrow); 
-    }
-    addMapArrow(position){ 
-        var mapArrow = this.mapArrow.clone()
-        mapArrow.position.copy(position).setZ(0) 
-        this.mapArrows.add(mapArrow);
-    }
-    
-    
-    setArrowDir(arrows,index){
-        let arrow = arrows[index]
-        var nextOne = arrows[index+1];
-        var nextPos = nextOne ? nextOne.position : this.endPolePos //routeEnd
-        var direction = new THREE.Vector3().subVectors(arrow.position, nextPos).setZ(0);
-        //direction.normalize();
-        //console.log(direction.toArray())
-        var angle = Math.atan2(direction.y, direction.x ) + Math.PI/2 //Math.PI/2是因为贴图本身箭头方向不朝x
-        arrow.rotation.z = angle
-        //console.log(angle)
-    }
-    
-    
-     
-    
-    
-    setRouteStart(pos, dealMapZ   ){
-        if(this.routeStart && pos && this.routeStart.equals(pos)) return //可能重复设置
-        this.routeStart = pos && new THREE.Vector3().copy(pos)  
-        if(dealMapZ && this.routeStart) this.routeStart.setZ(viewer.bound.boundingBox.min.z + 0.2) 
-        console.log('setRouteStart',this.routeStart&&this.routeStart.toArray()) 
-        
-        
-        this.generateRoute()
-        
-        
-    }
-    
-    setStartPole(pos){
-        this.startPolePos = pos
-        this.bus && this.bus.emit('reposStartMarker', pos)
-    }
-     
-    
-    setRouteEnd(pos, dealMapZ   ){ 
-        if(this.routeEnd && pos && this.routeEnd.equals(pos)) return 
-        this.routeEnd = pos && new THREE.Vector3().copy(pos)
-        if(dealMapZ && this.routeEnd) this.routeEnd.setZ(viewer.bound.boundingBox.min.z + 0.2) 
-        console.log('setRouteEnd',this.routeEnd&&this.routeEnd.toArray())        
-        
-        
-        this.generateRoute()
-        
-    }
-    setEndPole(pos){
-        this.endPolePos = pos
-        this.bus && this.bus.emit('reposEndMarker', pos)
-    }
-    
-    getSourceProjectionIndex(route) {//真正的起始
-        var e = route.findIndex(function(t) {
-            return t.instruction && t.instruction.type === 'source_projection_to_navgraph'
-        });
-        return e < 0 ? 0 : e
-    }
-    getDestinationProjectionIndex(route) {//真正的终点
-        var e = route.findIndex(function(t) {
-            return t.instruction && t.instruction.type === "destination_projection_to_navgraph"
-        });
-        return e < 0 ? route.length - 1 : e
-    }
-    
-    generateRoute(){
-        if(!this.routeStart || !this.routeEnd){ 
-            
-            return
-        }
-        
-        
-        //array.reduce(function(total, currentValue, currentIndex, arr), initialValue)
-        
-        
-        let create = ()=>{ 
-            this.routeLength = this.route.reduce((total, currentValue, currentIndex, arr)=>{
-                if(currentIndex == 0)return 0
-                return total + currentValue.distanceTo(arr[currentIndex-1]);
-            },0)
-            let count = Math.max(2,Math.round(this.routeLength / arrowSpacing))//点数
-            
-            const curve = new THREE.CatmullRomCurve3( this.route ); 
-            curve.curveType = 'chordal'//'centripetal'  'catmullrom'这个可能会超出路径外
-            this.curve = curve
-            
-            const scenePoints = curve.getSpacedPoints( count );//更平均
-            //const scenePoints = curve.getPoints( count );
-            scenePoints.splice(0,1);//去掉首尾
-            scenePoints.pop()
-            this.scenePoints = scenePoints
-            
-            this.updateMapArrows() 
-            this.displayRoute()
-            
-            {//map focus on this area
-                
-                const minBound = new THREE.Vector2(1,1)//针对垂直线,在地图上只有一个点
-                let bound = new THREE.Box2;
-                this.route.forEach(e=>{
-                    bound.expandByPoint(e)
-                })
-                let size = bound.getSize(new THREE.Vector2)
-                let markerSize = new THREE.Vector2(115,40) //起始和终点的标识呈长方形
-                let areaSize = viewer.mapViewer.viewports[0].resolution2
-                let areaArea = areaSize.x * areaSize.y
-                if(areaArea> 800 * 400){//是放大的 
-                    markerSize.multiplyScalar(areaArea / (800 * 400) /* / (size.x * size.y) */) 
-                }
-                let margin = size.clone().divide(viewer.mapViewer.viewports[0].resolution2).multiply(markerSize) ///边距 重点是起始和终点的标识占据较大
-                size.add(margin)
-                let center = bound.getCenter(new THREE.Vector2)
-                
-                size.x = Math.max(size.x, minBound.x )
-                size.y = Math.max(size.y, minBound.y )
-                let duration = 1000
-                viewer.mapViewer.moveTo(center, size, duration)
-            }
-            
-            this.bus.emit('gotResult', {dis:this.routeLength})
-            /* this.generateDeferred && this.generateDeferred.resolve({dis:this.routeLength})
-            this.generateDeferred = null */
-        }
-        
-        
-        if(Potree.fileServer){
-            let dealData = (data)=>{
-                
-                if(!data.data){
-                    console.log('没有数据')
-                    let result
-                    if(data && data.code == 4002){
-                        result = data;//正被修改数据集
-                    }else if(this.routeStart.distanceTo(this.routeEnd) < 1){
-                        result = { code: 500, msg: '距离太短,无法规划路线' }
-                    }else{
-                        result = { code: 500, msg: '超出数据集范围,无法规划路线' }
-                    }
-                    this.clearRoute() 
-
-
-                    this.setStartPole(this.routeStart) 
-                    this.setEndPole(this.routeEnd) 
-                    
-                    this.displayRoute() //还是要显示一下起始
-                    this.bus && this.bus.emit('gotResult', result )
-                    
-                    return //this.generateDeferred && this.generateDeferred.resolve()
-                }
-                
-                
-                data = data.data 
-                  
-                this.clearRoute()
-                let length = data.length
-                
-                if(length < 2){//可能距离太短 
-                    console.log('路径点数为'+length+',直接取起点和终点连线') 
-                    this.route = [this.routeStart, this.routeEnd];
-                }else{ 
-                    let startIndex = this.getSourceProjectionIndex(data)
-                    let endIndex = this.getDestinationProjectionIndex(data)
-                    
-                    
-                    let effectiveItems = data.slice(startIndex, endIndex + 1 );//只要点云范围内的点
-                    effectiveItems.forEach((item,i)=>{ 
-                        let pos = viewer.transform.lonlatToLocal.forward(item.location.slice(0))
-                        pos = new THREE.Vector3().fromArray(pos)
-                        this.route.push(pos)
-                    })
-                    
-                    console.log(this.route)
-                    
-                    
-                }
-                this.setStartPole(this.route[0]) 
-                this.setEndPole(this.route[this.route.length-1]) 
-                
-                create()
-                /*
-                    distance: 0.17581000000000116
-                    distance_to_previous: 0.17581000000000116
-                    id: 567
-                    instruction: {type: 'source_projection_to_navgraph'}
-                    latitude: 22.366605927999238
-                    location: (3) [113.5957510575092, 22.366605927999238, -1.12419]
-                    longitude: 113.5957510575092
-                    z: -1.12419
-                */
-            }
-            
-            
-            
-            
-            if(this.lastResult && (this.lastResult.data || this.lastResult.data.code != 4002)){//正被修改数据集的话要重新计算
-                let data = Common.CloneObject(this.lastResult.data) ,  use;  //直接用上次的结果
-                if(this.lastResult.routeStart.equals(this.routeStart) &&  this.lastResult.routeEnd.equals(this.routeEnd)){//和上次请求相同
-                    use = true 
-                }else if(this.lastResult.routeStart.equals(this.routeEnd) &&  this.lastResult.routeEnd.equals(this.routeStart)){//..反向
-                    use = true
-                    if(data.data){
-                        data.data = this.lastResult.data.data.slice(0).reverse()
-                    }    
-                }
-                if(use){
-                    console.log('直接用上次的结果')
-                    return setTimeout(()=>{dealData(data)}, 1)//延迟是为了等待获得 RouteGuider.generateDeferred
-                       
-                }
-                
-            }
-            
-            
-            
-            
-            let start = this.routeStart.clone();
-            let end = this.routeEnd.clone();
-            let startLonlat = viewer.transform.lonlatToLocal.inverse(start)
-            let endLonlat = viewer.transform.lonlatToLocal.inverse(end)
-            
-            var query = {
-                source_longitude: startLonlat.x,
-                source_latitude: startLonlat.y,
-                source_z: start.z,
-                destination_longitude: endLonlat.x,
-                destination_latitude: endLonlat.y,
-                destination_z: end.z
-            };
-            let url = `/laser/route/${Potree.settings.number}/getRoute?`
-            for(let i in query){
-                url+= (i + '='+ query[i] +'&')
-            }
-            
-            Potree.fileServer.get(url).then((data)=>{
-                console.log(data.data)
-                if(!this.routeStart || !this.routeEnd)return 
-                
-                this.lastResult = {//保存数据
-                    routeStart : this.routeStart.clone(),
-                    routeEnd: this.routeEnd.clone(),
-                    data,
-                     
-                }
-                
-                dealData(data)
-                
-            })
-            
-            
-        }else{
-            //创个直线
-            /* const sliceDis = 1
-            let dis = this.routeStart.distanceTo(this.routeEnd);
-            let count = Math.max(2,Math.round(dis / sliceDis))//点数
-            let realSlideDis = dis / (count-1);
-            let dir = new THREE.Vector3().subVectors(this.routeEnd, this.routeStart).normalize().multiplyScalar(realSlideDis);
-            this.route = [this.routeStart];
-            for(let i=0;i<count-1;i++){
-                let lastOne = this.route[i];
-                this.route.push(new THREE.Vector3().addVectors(lastOne,dir))
-            }
-            this.route.splice(0,1) //route不用包含收尾 */
-            this.clearRoute()
-            this.route = [this.routeStart, this.routeEnd]
-            create()
-            
-        }
-          
-    }
-    
-    updateMapArrows(ifReset){
-        if(this.route.length == 0)return  
-        var zoom = viewer.mapViewer.camera.zoom
-        let count = Math.max(2,Math.round(this.routeLength * zoom  / arrowSpacing / 25))//点数
-        
-        if(count == this.mapPoints.length+1)return//没变
-
-        const mapPoints = this.curve.getSpacedPoints( count ); 
-        mapPoints.splice(0,1);//去掉首尾
-        mapPoints.pop() 
-        this.mapPoints = mapPoints
-        
-        
-        var scale = 25/zoom
-        this.mapArrow.scale.set(scale*0.6,scale*0.6,scale*0.6) 
-        /* this.mapMarkStart.scale.set(scale,scale,scale) 
-        this.mapMarkEnd.scale.set(scale,scale,scale)  */
-         
-        
-        if(ifReset){//因为缩放而重新排布箭头
-            this.clearRoute({resetMap:true})
-            this.displayRoute({resetMap:true}) 
-        }
-    }
-    
-    
-    updateArrowDisplay(){//根据当前位置更新显示一定范围内的箭头'
-    
-        if(this.scenePoints.length == 0)return
-        
-        /* var a = Common.sortByScore(this.scenePoints , null, [(point)=>{   //是否还要再requires里限制最远距离?
-            var playerPos = viewer.scene.getActiveCamera().position.clone().setZ(0)
-            
-            var pos = point.clone().setZ(0) 
-            
-            return -pos.distanceTo(playerPos);
-            
-        }]);
-        //获得展示的起始点 
-        let start = a[0].item
-        let startIndex = this.scenePoints.indexOf(start)
-        this.arrows.children.forEach((e,i)=>{
-            if(i<startIndex || i>startIndex+arrowsShowingCount)e.visible = false
-            else e.visible = true
-        }) */
-        
-        let cameraPos = viewer.scene.getActiveCamera().position
-        this.arrows.children.forEach((e,i)=>{
-            if(e.position.distanceTo(cameraPos) < arrowShowMinDis) e.visible = true
-            else e.visible = false
-        })
-        
-        
-    }
-    
-    
-    displayRoute(o={}){
-        if(!o.resetMap){ 
-            
-            this.poleStart.position.copy(this.startPolePos || this.routeStart)
-            this.poleEnd.position.copy(this.endPolePos || this.routeEnd)
-            /* this.mapMarkStart.position.copy(this.routeStart).setZ(0)
-            this.mapMarkEnd.position.copy(this.routeEnd).setZ(0) */
-            this.scenePoints.forEach(e=>this.addArrow(e))
-            this.arrows.children.forEach((e,i)=>this.setArrowDir(this.arrows.children,i));
-        }
-        this.sceneMeshGroup.visible = true 
-        this.mapMeshGroup.visible = true   
-        this.mapPoints.forEach(e=>this.addMapArrow(e))
-        this.mapArrows.children.forEach((e,i)=>this.setArrowDir(this.mapArrows.children,i));
-        viewer.mapViewer.dispatchEvent({'type':'content_changed'})
-        this.updateArrowDisplay()
-    }
-    
-    clearRoute(o={}){
-        if(!o.resetMap){
-            this.routeLength = 0
-            this.route = []
-            this.scenePoints = []
-            this.mapPoints = []
-            let arrows = this.arrows.children.slice(0)
-            arrows.forEach(e=>{
-                this.arrows.remove(e)
-            })
-        } 
-        
-        let mapArrows = this.mapArrows.children.slice(0) 
-        mapArrows.forEach(e=>{
-            this.mapArrows.remove(e)
-        })
-        
-        this.sceneMeshGroup.visible = false 
-        this.mapMeshGroup.visible = false
-        viewer.mapViewer.dispatchEvent({'type':'content_changed'})
-    }
-    
-    clear(){//退出
-        console.log('导航clear') 
-        this.routeStart = null
-        this.routeEnd = null
-        this.clearRoute()
-        
-    }
-}
-
-//大概每十米要花一秒
-
-
-
-/* 
-
-    存在的问题:
-    路径不准确。起始点和终点偏移。
-
-
- */

+ 2 - 2
src/viewer/Axis.js

@@ -71,9 +71,9 @@ export default class Axis extends THREE.Object3D {// 坐标轴
         
 
             if(axisText == 'y'){
-                group.rotation.x = Math.PI / 2
+                group.rotation.x = -Math.PI / 2
             }else if(axisText == 'x'){
-                group.rotation.y = -Math.PI / 2
+                group.rotation.y = Math.PI / 2
             } 
             
             this.add(group)

src/utils/Label.js → src/objects/Label.js


+ 2 - 2
src/utils/Magnifier.js

@@ -1,7 +1,7 @@
 
 import * as THREE from "../../libs/three.js/build/three.module.js";
-import math from './math'
-import browser from './browser'
+import math from '../utils/math'
+import browser from '../utils/browser'
 import Viewport from '../viewer/Viewport'
  
 const texLoader = new THREE.TextureLoader() 

src/navigation/Reticule.js → src/objects/Reticule.js


src/viewer/Sprite.js → src/objects/Sprite.js


+ 2 - 2
src/TextSprite.js

@@ -4,8 +4,8 @@
 //  * adapted from http://stemkoski.github.io/Three.js/Sprite-Text-Labels.html
 //  */
 
-import * as THREE from "../libs/three.js/build/three.module.js";
-import Sprite from './viewer/Sprite' 
+import * as THREE from "../../libs/three.js/build/three.module.js";
+import Sprite from './Sprite' 
 
 
 //可能还是要用html写,因为要加按钮和图片

+ 100 - 0
src/objects/fireParticle/explode.html

@@ -0,0 +1,100 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js webgl - custom attributes [particles]</title>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+		<link type="text/css" rel="stylesheet" href="../main.css">
+	</head>
+
+	<body>
+		<div id="info"><a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - custom attributes example - particles</div>
+		<div id="container"></div>
+		<script type="module">
+			import * as THREE from '../../build/three.module.js';
+            
+			import { OrbitControls } from '../jsm/controls/OrbitControls.js';
+			import Stats from '../jsm/libs/stats.module.js';
+			import { GUI } from '../jsm/libs/dat.gui.module.js';
+            import ExplodeParticleSystem from './explode/ExplodeParticleSystem.js';
+			import ExplodeEmitter from './explode/ExplodeEmitter.js'
+
+			let renderer, scene, camera, light,stats,clock;
+			let explode;
+
+			const width = window.innerWidth;
+			const height = window.innerHeight;
+
+			init();
+			animate();
+
+			function init() {
+				stats = new Stats();
+				clock = new THREE.Clock(),
+				scene  = new THREE.Scene();
+
+                var VIEW_ANGLE = 45, ASPECT = width / height, NEAR = 0.1, FAR = 10000;
+	            camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR);
+				camera.position.set(0, 50, 200);
+	            camera.lookAt(new THREE.Vector3())	
+
+				//https://github.com/imokya/ParticleSystem
+				// const light = new THREE.PointLight(0xffffff, 2, 100)
+				// light.position.set(0, 30, 10)
+				// this.scene.add(light)
+
+				renderer = new THREE.WebGLRenderer( { antialias: true } );
+				renderer.setSize( width, height );
+				renderer.setClearColor( 0x333333 );
+				document.body.appendChild( renderer.domElement );
+
+				const controls = new OrbitControls( camera, renderer.domElement );
+				controls.update();
+
+				scene.add( new THREE.DirectionalLight( 0xffffff ) );
+				scene.add( new THREE.AmbientLight( 0x666666 ) );
+
+				initParticles()
+			}
+
+			function initParticles() {
+				explode = new ExplodeParticleSystem({
+					emitter: new ExplodeEmitter()
+				})
+				scene.add(explode.mesh)
+				explode.start()
+			}
+
+			function updateExplode(){
+				var delta = clock.getDelta();
+	            explode.update( delta * 0.5 );	
+			}
+
+			function onWindowResize() {
+
+				camera.aspect = window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+			}
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+				render();
+				stats.update();
+
+			}
+
+			function render() {
+                updateExplode()
+				renderer.render( scene, camera );
+
+			}
+
+		</script>
+
+</body>
+
+</html>

+ 310 - 0
src/objects/fireParticle/explode/ExplodeParticle.js

@@ -0,0 +1,310 @@
+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

+ 56 - 0
src/objects/fireParticle/explode/Particle.js

@@ -0,0 +1,56 @@
+// import { vertexShader, fragmentShader } from './shader'
+// import Tween from './tween'
+import * as THREE from "../../../../libs/three.js/build/three.module.js";
+
+const DEG2RAD = Math.PI / 180
+
+class Particle {
+  
+  constructor() {
+    
+    this.position = new THREE.Vector3()
+    this.velocity = 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
+  }
+
+  update(dt) { 
+    //s = s0 + (v0 + at) * t 或 lastS + delta(vt)
+  
+    this.position.add(this.velocity.clone().multiplyScalar(dt))
+    this.velocity.multiplyScalar( 1+this.acceleration*dt )
+    
+    this.angle += this.angleVelocity * DEG2RAD * dt
+    this.angleVelocity += this.angleAcceleration * DEG2RAD * dt
+    this.age += dt
+
+    if(this.sizeTween.times.length > 0) {
+      this.size = this.sizeTween.lerp(this.age/this.deathAge)
+    }
+
+    if(this.colorTween.times.length > 0) {
+      const colorHSL = this.colorTween.lerp(this.age/this.deathAge)
+      this.color = new THREE.Color().setHSL(colorHSL.x, colorHSL.y, colorHSL.z)
+    }
+
+    if(this.opacityTween.times.length > 0) {
+      this.opacity = this.opacityTween.lerp(this.age/this.deathAge)
+    }
+  }
+
+}
+
+export default Particle

+ 26 - 0
src/objects/fireParticle/explode/Tween.js

@@ -0,0 +1,26 @@
+import * as THREE from "../../../../libs/three.js/build/three.module.js";
+class Tween {
+
+    constructor(times, values) {
+      this.times = times || []
+      this.values = values || []
+    }
+  
+    lerp(t) {
+      if(this.times.length == 0) return
+      let i = 0, n = this.times.length
+      while(i < n && t > this.times[i]) i++
+      if(i == 0) return this.values[0]
+      if(i == n) return this.values[n-1]
+      const ratio = (t - this.times[i-1]) / (this.times[i] - this.times[i-1])
+      if(this.values[0] instanceof THREE.Vector3) {
+        return this.values[i-1].clone().lerp(this.values[i], ratio)
+      } else {
+        return this.values[i-1] + ratio * (this.values[i] - this.values[i-1])
+      }
+      
+    }
+  
+  }
+  
+  export default Tween

+ 18 - 0
src/objects/fireParticle/explode/Util.js

@@ -0,0 +1,18 @@
+import * as THREE from "../../../../libs/three.js/build/three.module.js";
+export class Util {
+    constructor() {}
+
+    randomValue(min, max) {
+        //return min + max * (Math.random() - 0.5)
+        let p = Math.random()
+        return min * p + max * (1-p)
+    }
+
+    randomVector3(min, max) {
+        const rand3 = new THREE.Vector3(Math.random() - 0.5, Math.random() - 0.5, Math.random() - 0.5)
+        return new THREE.Vector3().addVectors(min, new THREE.Vector3().multiplyVectors(max, rand3))
+    }
+}
+
+const util = new Util();
+export { util };

+ 4 - 0
src/objects/fireParticle/explode/const.js

@@ -0,0 +1,4 @@
+export const Shape = {
+    CUBE: 1,
+    SPHERE: 2
+  }

+ 38 - 0
src/objects/fireParticle/explode/shader.js

@@ -0,0 +1,38 @@
+export const vertexShader = `
+  attribute vec3 color;
+  attribute float size;
+  attribute float angle;
+  attribute float opacity;
+  attribute float visible;
+  varying vec4 vColor;
+  varying float vAngle;
+  
+  void main() {
+    if(visible > 0.5) {
+      vColor = vec4(color, opacity);
+    } else {
+      vColor = vec4(0.0, 0.0, 0.0, 0.0);
+    }
+    vAngle = angle;
+    vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
+    gl_PointSize = size * (300.0 / length(mvPosition.xyz));
+    gl_Position = projectionMatrix * mvPosition;
+  }
+` 
+
+export const fragmentShader = `
+  uniform sampler2D u_sampler;
+  varying vec4 vColor;
+  varying float vAngle;
+  void main() {
+    gl_FragColor = vColor;
+    float u = cos(vAngle);
+    float v = sin(vAngle);
+    vec2 uv = vec2(
+      u * (gl_PointCoord.x - 0.5) + v * (gl_PointCoord.y - 0.5) + 0.5, 
+      u * (gl_PointCoord.y - 0.5) - v * (gl_PointCoord.x - 0.5) + 0.5
+    );
+    vec4 texture = texture2D(u_sampler, uv);
+    gl_FragColor = gl_FragColor * texture;
+  }
+`

+ 96 - 0
src/objects/fireParticle/fire.html

@@ -0,0 +1,96 @@
+
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js webgl - custom attributes [particles]</title>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+		<link type="text/css" rel="stylesheet" href="../main.css">
+	</head>
+
+	<body>
+		<div id="info"><a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - custom attributes example - particles</div>
+		<div id="container"></div>
+
+		<script type="module">
+			import * as THREE from '../../build/three.module.js';
+			import { OrbitControls } from '../jsm/controls/OrbitControls.js';
+			import Stats from '../jsm/libs/stats.module.js';
+			import { GUI } from '../jsm/libs/dat.gui.module.js';
+			import FireParticleSystem from './fire/FireParticleSystem.js';
+
+			let renderer, scene, camera, stats,clock;
+
+			let sphere;
+			let fireParticleSystem;
+			const width = window.innerWidth;
+			const height = window.innerHeight;
+
+			init();
+			animate();
+
+			function init() {
+				stats = new Stats();
+				clock = new THREE.Clock(),
+				scene  = new THREE.Scene();
+				scene.fog = new THREE.Fog( 0x333333, 8, 20 );
+				camera = new THREE.PerspectiveCamera( 40, width / height, 0.1, 100 );
+				camera.position.z = 5;
+               
+				renderer = new THREE.WebGLRenderer( { antialias: true } );
+				renderer.setSize( width, height );
+				renderer.setClearColor( 0x333333 );
+				document.body.appendChild( renderer.domElement );
+
+				const controls = new OrbitControls( camera, renderer.domElement );
+				controls.maxPolarAngle = 2*Math.PI;
+				controls.minDistance = 1;
+				controls.maxDistance = 100;
+				controls.update();
+
+				scene.add( new THREE.DirectionalLight( 0xffffff ) );
+				scene.add( new THREE.AmbientLight( 0x666666 ) );
+				//https://yomotsu.github.io/three-particle-fire/examples/basic.html
+				initParticles()
+			}
+
+			function initParticles() {
+				let fireRadius = 1;
+				let fireHeight = 3;
+				let particleCount = 400;
+				fireParticleSystem = new FireParticleSystem()
+				let geometry = fireParticleSystem.createGeometry( fireRadius, fireHeight, particleCount );
+				let material = fireParticleSystem.createMaterial(  camera.fov, height, 0x00338f );//0xff2200
+				fireParticleSystem.mesh = new THREE.Points( geometry, material );
+                fireParticleSystem.mesh.position.y = -0.6//add
+                
+				scene.add( fireParticleSystem.mesh );
+			}
+
+			function updateFire(){
+				let delta = clock.getDelta();
+				let elapsed = clock.getElapsedTime();
+				fireParticleSystem.updateMaterial(delta * 0.75) //更改速度
+			}
+
+			function onWindowResize() {
+
+				camera.aspect = window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+				renderer.setSize( window.innerWidth, window.innerHeight );
+			}
+
+			function animate() {
+				requestAnimationFrame( animate );
+				updateFire()
+				render();
+				stats.update();
+			}
+
+			function render() {
+				renderer.render( scene, camera );
+			}
+		</script>
+</body>
+
+</html>

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 174 - 0
src/objects/fireParticle/fire/FireParticle.js


+ 45 - 0
src/objects/fireParticle/fire/shader.js

@@ -0,0 +1,45 @@
+export const vertexShader = `
+    attribute float randam;
+    attribute float sprite;
+
+    uniform float time;
+    uniform float size;
+    uniform float heightOfNearPlane;
+
+    varying float vSprite;
+    varying float vOpacity; 
+    float PI = 3.14;
+
+    float quadraticIn( float t ) 
+    { 
+        float tt = t * t;
+        return tt * tt; 
+        //变化曲线  越来越快
+    } 
+    
+    void main() {
+        float progress = fract( time + ( 2.0 * randam - 1.0 ) );
+        float progressNeg = 1.0 - progress;
+        float ease = quadraticIn( progress );
+        float influence = sin( PI * ease );
+        vec3 newPosition = position * vec3( 1.0,  1.0 , ease);
+        gl_Position = projectionMatrix * modelViewMatrix * vec4( newPosition, 1.0 );
+        gl_PointSize = ( heightOfNearPlane * size ) / gl_Position.w;
+        vOpacity = min( influence * 4.0, 1.0 ) * progressNeg;
+        vSprite = sprite;
+    }
+` 
+
+export const fragmentShader = `
+    uniform vec3 color;
+    uniform sampler2D u_sampler;
+
+    varying float vSprite;
+    varying float vOpacity;
+
+    void main() 
+    {
+        vec2 texCoord = vec2(gl_PointCoord.x * 0.25 + vSprite, gl_PointCoord.y);
+        gl_FragColor = vec4( texture2D( u_sampler, texCoord ).xyz * color * vOpacity, 1.0 );
+    }
+`

BIN
src/objects/fireParticle/images/checkerboard.jpg


BIN
src/objects/fireParticle/images/circle-particle.png


BIN
src/objects/fireParticle/images/explode.png


BIN
src/objects/fireParticle/images/explode1.png


BIN
src/objects/fireParticle/images/groundcolor.jpg


BIN
src/objects/fireParticle/images/groundnormal.jpg


BIN
src/objects/fireParticle/images/plane.png


BIN
src/objects/fireParticle/images/smoke (1).png


BIN
src/objects/fireParticle/images/smoke.png


BIN
src/objects/fireParticle/images/smokeparticle.png


+ 87 - 0
src/objects/fireParticle/smoke.html

@@ -0,0 +1,87 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js webgl - custom attributes [particles]</title>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+		<link type="text/css" rel="stylesheet" href="../main.css">
+	</head>
+
+	<body>
+		<div id="info"><a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - custom attributes example - particles</div>
+		<div id="container"></div>
+		<script type="module">
+			import * as THREE from '../../build/three.module.js';
+            
+			import { OrbitControls } from '../jsm/controls/OrbitControls.js';
+			import Stats from '../jsm/libs/stats.module.js';
+			import { GUI } from '../jsm/libs/dat.gui.module.js';
+            import SmokeParticle from './smoke/SmokeParticle.js';
+             
+			let renderer, scene, camera, stats,clock;
+			let smoke;
+
+			const width = window.innerWidth;
+			const height = window.innerHeight;
+
+			init();
+			animate();
+
+			function init() {
+				stats = new Stats();
+				clock = new THREE.Clock()
+				scene  = new THREE.Scene();
+                var VIEW_ANGLE = 45, ASPECT = width / height, NEAR = 0.1, FAR = 20000;
+	            camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR);
+				camera.position.set(0,200,400);
+	            camera.lookAt(scene.position);	
+
+				renderer = new THREE.WebGLRenderer( { antialias: true } );
+				renderer.setSize( width, height );
+				renderer.setClearColor( 0x333333 );
+				document.body.appendChild( renderer.domElement );
+
+				const controls = new OrbitControls( camera, renderer.domElement );
+				controls.update();
+
+				scene.add( new THREE.DirectionalLight( 0xffffff ) );
+				scene.add( new THREE.AmbientLight( 0x666666 ) );
+				
+				initParticles()
+				//http://stemkoski.github.io/Three.js/Particle-Engine.html
+			}
+
+			function initParticles() {
+                let position = new THREE.Vector3(0,-100,0)
+				smoke = new SmokeParticle(position)
+                smoke.init()
+                smoke.createMesh() 
+				scene.add( smoke.particleMesh );
+			}
+
+			function updateSmoke(){
+				var delta = clock.getDelta();
+	            smoke.update( delta * 0.5 );	
+			}
+
+			function onWindowResize() {
+				camera.aspect = window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+				renderer.setSize( window.innerWidth, window.innerHeight );
+			}
+
+			function animate() {
+				requestAnimationFrame( animate );
+				updateSmoke()
+				render();
+				stats.update();
+			}
+
+			function render() {
+				renderer.render( scene, camera );
+			}
+		</script>
+
+</body>
+
+</html>

+ 57 - 0
src/objects/fireParticle/smoke/Particle.js

@@ -0,0 +1,57 @@
+import * as THREE from "../../../../libs/three.js/build/three.module.js";
+import Tween from './Tween.js'
+export default class Particle{
+    constructor(prop={}){
+        this.position     = new THREE.Vector3();
+        this.velocity     = new THREE.Vector3(); // units per second
+         
+        this.angle             = 0;
+        this.angleVelocity     = 0; // degrees per second
+        this.angleAcceleration = 0; // degrees per second, per second
+        this.size = 16.0;
+    
+        this.color   = new THREE.Color();
+        this.opacity = 1.0;
+                
+        this.age   = 0;
+        this.alive = 0; // use float instead of boolean for shader purposes	
+        this.lastChangeVage = 0 //add
+
+
+        this.sizeTween    = prop.sizeTween || new Tween( [0, 1], [32, 128] );
+		this.opacityTween = prop.opacityTween || new Tween( [0.8, 2], [0.5, 0] );
+		this.colorTween   = prop.colorTween || new Tween( [0.4, 1], [ new THREE.Vector3(0,0,0.2), new THREE.Vector3(0, 0, 0.5) ] );
+   
+   
+   
+   }
+
+    update(dt)
+    {
+        this.position.add(this.velocity.clone().multiplyScalar(dt))
+        this.velocity.multiplyScalar( 1+this.acceleration*dt )
+        
+        // convert from degrees to radians: 0.01745329251 = Math.PI/180
+        this.angle         += this.angleVelocity     * 0.01745329251 * dt;
+        this.angleVelocity += this.angleAcceleration * 0.01745329251 * dt;
+
+        this.age += dt;
+        
+        // if the tween for a given attribute is nonempty,
+        //  then use it to update the attribute's value
+
+        if ( this.sizeTween.times.length > 0 )
+            this.size = this.sizeTween.lerp( this.age/this.deathAge );
+                    
+        if ( this.colorTween.times.length > 0 )
+        {
+            var colorHSL = this.colorTween.lerp( this.age/this.deathAge );
+            this.color = new THREE.Color().setHSL( colorHSL.x, colorHSL.y, colorHSL.z );
+        }
+        
+        if ( this.opacityTween.times.length > 0 )
+        {
+            this.opacity = this.opacityTween.lerp( this.age/this.deathAge);
+        }
+    }
+}

+ 348 - 0
src/objects/fireParticle/smoke/SmokeParticle.js

@@ -0,0 +1,348 @@
+import * as THREE from "../../../../libs/three.js/build/three.module.js";
+import Particle from './Particle.js'
+import Tween from './Tween.js'
+import { vertexShader, fragmentShader } from './shader.js'
+
+const Type = Object.freeze({ "CUBE":1, "SPHERE":2 });
+let particleTexture  
+
+const getTexture = ()=>{
+    if(!particleTexture){
+        particleTexture = new THREE.TextureLoader().load( Potree.resourcePath+'/textures/smokeparticle.png')
+    }
+    return particleTexture
+}
+
+
+
+
+
+const defaults = 
+{
+    positionStyle    : Type.CUBE,
+    positionBase     : new THREE.Vector3( 0, 0, 0 ),
+     
+    positionSpread   : new THREE.Vector3( 1, 1, 0), //cube
+     
+    positionRadius   :     0,       // sphere
+        
+    velocityStyle    : Type.CUBE,
+     
+    velocityBase     : new THREE.Vector3( 0,  0,  15),     // cube
+    velocitySpread   : new THREE.Vector3( 0.8, 0.8, 0.5), 
+    
+    accelerationBase : 0.1,
+    accelerationSpread : 0.5,	
+    
+    
+    speedBase  : 0.1,       //sphere
+    speedSpread : 0.5,
+          
+    
+
+    angleBase               : 0,
+    angleSpread             : 720,
+    angleVelocityBase       : 0,
+    angleVelocitySpread     : 720,
+    angleAccelerationBase   : 0,
+    angleAccelerationSpread : 0,
+        
+    sizeBase    :   0,  
+    sizeSpread  :   0,
+    sizeTween    : new Tween( [0, 1], [3.2, 12.8] ),
+    
+    
+    colorBase   :   new THREE.Vector3(0.0, 1.0, 0.5), 
+    colorSpread :   new THREE.Vector3(0.0, 0.0, 0.0),
+    colorTween   : new Tween( [0.4, 1], [ new THREE.Vector3(0,0,0.4), new THREE.Vector3(0, 0, 0.7) ] ),
+
+    opacityBase     :   0.1,//1.0,
+    opacitySpread   :   0.3,
+    opacityTween : new Tween( [0.8, 2], [0.5, 0] ),
+    
+    
+     
+
+    particlesPerSecond : 20,
+    particleDeathAge   : 2.0,		
+    emitterDeathAge    : 60 // time (seconds) at which to stop creating particles.
+};
+
+const positions = [];
+const colors = [];
+const alives = [];
+const opacitys = [];
+const sizes = [];
+const angles = [];
+
+export default class SmokeParticle extends THREE.Points{
+    constructor(prop={}) {
+        super()
+        
+        this.particleArray = [];   
+        this.blendStyle = THREE.NormalBlending; // false; 
+        this.emitterAge = 0.0;
+        this.emitterAlive = true;
+       
+        
+        for ( var key in defaults ){
+            let value = prop[key] != void 0 ? prop[key] : defaults[ key ];	
+            if(value instanceof Array && value[0] instanceof Array ) this[ key ] = new Tween(...value)
+            else this[ key ] = value
+        }
+          
+        // How many particles could be active at any time?
+        this.particleCount = this.particlesPerSecond * Math.min( this.particleDeathAge, this.emitterDeathAge );
+    
+        
+        this.createMaterial()
+        this.createGeometry()
+        
+        this.dynamic = true;
+        this.sortParticles = true; 
+        this.frustumCulled = false//似乎是禁止相机裁剪,否则会在某些角度消失。但是会不会更耗性能呢?
+       
+        prop.position && this.position.copy(prop.position)
+        
+        
+        
+        viewer.on('pageVisible', (state)=>{   
+            if(state){//重新一个个放出粒子,否则会一股脑儿全部出来,因为同时大于粒子周期了一起重新生成出现。
+                setTimeout(()=>{//会先update一次delta为pageUnvisile的时间才触发
+                    //归零
+                    console.log('归零')
+                    this.emitterAge = 0;
+                    
+                    this.geometry.dispose()
+                    
+                    this.createGeometry()
+                    
+
+                    
+                },1) 
+            }  
+        }) 
+        
+        
+        
+        
+        
+        
+        
+        
+    }
+
+   
+
+    createMaterial(){
+        this.material = new THREE.ShaderMaterial( 
+        {
+            uniforms: 
+            {
+                u_sampler:   { type: "t", value: getTexture() },
+            },
+            vertexShader:   vertexShader,vertexShader,
+            fragmentShader: fragmentShader,
+            transparent: true,
+            alphaTest: 0.5, // if having transparency issues, try including: alphaTest: 0.5, 
+            blending: this.blendStyle,
+            depthTest: this.blendStyle != THREE.NormalBlending
+        });
+        
+        
+        
+        
+    }
+
+    createParticle()
+    {
+        var particle = new Particle({
+            sizeTween : this.sizeTween,
+            opacityTween : this.opacityTween,
+            colorTween : this.colorTween,
+        });
+        particle.deathAge = this.particleDeathAge
+        
+        
+        if (this.positionStyle == Type.CUBE)
+            particle.position = this.randomVector3( this.positionBase, this.positionSpread ); 
+        if (this.positionStyle == Type.SPHERE)
+        {
+            var z = 2 * Math.random() - 1;
+            var t = 6.2832 * Math.random();
+            var r = Math.sqrt( 1 - z*z );
+            var vec3 = new THREE.Vector3( r * Math.cos(t), r * Math.sin(t), z );
+            particle.position = new THREE.Vector3().addVectors( this.positionBase, vec3.multiplyScalar( this.positionRadius ) );
+        }
+            
+        if ( this.velocityStyle == Type.CUBE )
+        {
+            particle.velocity     = this.randomVector3( this.velocityBase,     this.velocitySpread ); 
+        }
+        if ( this.velocityStyle == Type.SPHERE )  
+        {
+            //var direction = particle.position.clone()
+            var direction = new THREE.Vector3(0,0,1) //烟应该都是向上的
+            var speed     = this.randomValue( this.speedBase, this.speedSpread );
+            particle.velocity  = direction.normalize().multiplyScalar( speed );
+        }
+        
+        particle.acceleration = this.randomValue( this.accelerationBase, this.accelerationSpread ); 
+
+        particle.angle             = this.randomValue( this.angleBase,             this.angleSpread );
+        particle.angleVelocity     = this.randomValue( this.angleVelocityBase,     this.angleVelocitySpread );
+        particle.angleAcceleration = this.randomValue( this.angleAccelerationBase, this.angleAccelerationSpread );
+
+        particle.size = this.randomValue( this.sizeBase, this.sizeSpread );
+
+        var color = this.randomVector3( this.colorBase, this.colorSpread );
+        particle.color = new THREE.Color().setHSL( color.x, color.y, color.z );
+        
+        particle.opacity = this.randomValue( this.opacityBase, this.opacitySpread );
+
+        particle.age   = 0;
+        particle.alive = 0; // particles initialize as inactive
+        return particle;
+    }			
+
+    createGeometry(){
+        this.geometry = new THREE.BufferGeometry()
+        for (var i = 0; i < this.particleCount; i++)
+        {
+            // remove duplicate code somehow, here and in update function below.
+            this.particleArray[i] = this.createParticle();
+            positions[3*i] = this.particleArray[i].position.x
+            positions[3*i+1] = this.particleArray[i].position.y
+            positions[3*i+2] = this.particleArray[i].position.z
+
+            colors[3*i] = this.particleArray[i].color.r 
+            colors[3*i+1] = this.particleArray[i].color.g
+            colors[3*i+2] = this.particleArray[i].color.b
+
+            alives[i] = this.particleArray[i].alive
+            opacitys[i] = this.particleArray[i].opacity
+            sizes[i] = this.particleArray[i].size
+            angles[i] = this.particleArray[i].angle
+        }
+
+        this.geometry.setAttribute( 'position', new THREE.BufferAttribute( new Float32Array(positions), 3  ));
+        this.geometry.setAttribute( 'customColor', new THREE.BufferAttribute( new Float32Array(colors), 3 ) );
+        this.geometry.setAttribute( 'customVisible', new THREE.BufferAttribute( new Float32Array(alives), 1 ) );
+        this.geometry.setAttribute( 'customOpacity', new THREE.BufferAttribute( new Float32Array(opacitys), 1 ) );
+        this.geometry.setAttribute( 'customSize', new THREE.BufferAttribute( new Float32Array(sizes), 1 ) );
+        this.geometry.setAttribute( 'customAngle', new THREE.BufferAttribute( new Float32Array(angles), 1 ) );
+    }
+
+    
+
+    update(dt){
+         
+        dt *= 0.5;
+        
+        var recycleIndices = [];
+        // update particle data
+        for (var i = 0; i < this.particleCount; i++)
+        {
+            if ( this.particleArray[i].alive )
+            {
+                  
+                if ( this.velocityStyle == Type.CUBE )
+                {    
+                    if(this.particleArray[i].age - this.particleArray[i].lastChangeVage > this.particleDeathAge*0.4  ){
+                        if( Math.random()>0.3){//一定几率改变下方向
+                            this.particleArray[i].velocity = this.randomVector3( this.velocityBase,     this.velocitySpread ); 
+                        }
+                        this.particleArray[i].lastChangeVage = this.particleArray[i].age
+                    }
+                }
+                 
+                
+                this.particleArray[i].update(dt);
+
+                // check if particle should expire
+                // could also use: death by size<0 or alpha<0.
+                if ( this.particleArray[i].age > this.particleDeathAge ) 
+                {
+                    this.particleArray[i].alive = 0.0;
+                    recycleIndices.push(i);
+                } 
+                
+                
+                // update particle properties in shader
+                positions[3*i] = this.particleArray[i].position.x
+                positions[3*i+1] = this.particleArray[i].position.y
+                positions[3*i+2] = this.particleArray[i].position.z
+
+                colors[3*i] = this.particleArray[i].color.r 
+                colors[3*i+1] = this.particleArray[i].color.g
+                colors[3*i+2] = this.particleArray[i].color.b
+
+                alives[i] = this.particleArray[i].alive
+                opacitys[i] = this.particleArray[i].opacity
+                sizes[i] = this.particleArray[i].size
+                angles[i] = this.particleArray[i].angle
+            }		
+        }
+
+        // check if particle emitter is still running
+        //if ( !this.emitterAlive ) return;
+
+        this.geometry.setAttribute( 'position', new THREE.BufferAttribute( new Float32Array(positions), 3 ) );
+        this.geometry.setAttribute( 'customColor', new THREE.BufferAttribute( new Float32Array(colors), 3 ) );
+        this.geometry.setAttribute( 'customVisible', new THREE.BufferAttribute( new Float32Array(alives), 1 ) );
+        this.geometry.setAttribute( 'customOpacity', new THREE.BufferAttribute( new Float32Array(opacitys), 1 ) );
+        this.geometry.setAttribute( 'customSize', new THREE.BufferAttribute( new Float32Array(sizes), 1 ) );
+        this.geometry.setAttribute( 'customAngle', new THREE.BufferAttribute( new Float32Array(angles), 1 ) );
+
+        this.geometry.attributes.customColor.needsUpdate = true;
+        this.geometry.attributes.customVisible.needsUpdate = true;
+        this.geometry.attributes.customOpacity.needsUpdate = true;
+        this.geometry.attributes.customSize.needsUpdate = true;
+        this.geometry.attributes.customAngle.needsUpdate = true;
+
+        // if no particles have died yet, then there are still particles to activate
+        if ( this.emitterAge < this.particleDeathAge ) //开始时一个个放出来
+        {
+            // determine indices of particles to activate
+            var startIndex = Math.round( this.particlesPerSecond * (this.emitterAge +  0) );
+            var endIndex = Math.round( this.particlesPerSecond * (this.emitterAge + dt) );
+            if  ( endIndex > this.particleCount ) 
+                endIndex = this.particleCount; 
+                
+            for (var i = startIndex; i < endIndex; i++)
+                this.particleArray[i].alive = 1.0;		
+        }
+
+        // if any particles have died while the emitter is still running, we imediately recycle them
+        for (var j = 0; j < recycleIndices.length; j++)
+        {
+            var i = recycleIndices[j];
+            this.particleArray[i] = this.createParticle();
+            this.particleArray[i].alive = 1.0; // activate right away
+
+            positions[3*i] = this.particleArray[i].position.x
+            positions[3*i+1] = this.particleArray[i].position.y
+            positions[3*i+2] = this.particleArray[i].position.z
+        }
+        this.geometry.setAttribute( 'position', new THREE.BufferAttribute( new Float32Array(positions), 3 ) );
+        this.geometry.attributes.position.needsUpdate = true;
+
+        // stop emitter?
+        this.emitterAge += dt;
+        if ( this.emitterAge > this.emitterDeathAge )  this.emitterAlive = false;
+    }
+
+    randomValue(base, spread)
+    {
+        //return base + spread * (Math.random() - 0.5);
+        let p = Math.random()
+        return base * p + spread * (1-p)
+        
+    }
+
+    randomVector3(base, spread)
+    {
+        var rand3 = new THREE.Vector3( Math.random() - 0.5, Math.random() - 0.5, Math.random() - 0.5 );
+        return new THREE.Vector3().addVectors( base, new THREE.Vector3().multiplyVectors( spread, rand3 ) );
+    }
+}

+ 26 - 0
src/objects/fireParticle/smoke/Tween.js

@@ -0,0 +1,26 @@
+import * as THREE from "../../../../libs/three.js/build/three.module.js";
+export default class Tween{
+    constructor(timeArray, valueArray){
+        this.times  = timeArray || [];
+        this.values = valueArray || [];
+    }
+
+    lerp(t)
+    {
+        var i = 0;
+        var n = this.times.length;
+        while (i < n && t > this.times[i])  
+            i++;
+        if (i == 0) {
+            return this.values[0];
+        }
+        if (i == n)	{
+            return this.values[n-1];
+        }
+        var p = (t - this.times[i-1]) / (this.times[i] - this.times[i-1]);
+        if (this.values[0] instanceof THREE.Vector3)
+            return this.values[i-1].clone().lerp( this.values[i], p );
+        else // its a float
+            return this.values[i-1] + p * (this.values[i] - this.values[i-1]);
+    }
+}

+ 38 - 0
src/objects/fireParticle/smoke/shader.js

@@ -0,0 +1,38 @@
+export const vertexShader = `
+    attribute vec3  customColor;
+    attribute float customOpacity;
+    attribute float customSize;
+    attribute float customAngle;
+    attribute float customVisible;  
+    varying vec4  vColor;
+    varying float vAngle;
+    void main()
+    {
+        if ( customVisible > 0.5 ) 				
+            vColor = vec4( customColor, customOpacity ); 
+        else							
+            vColor = vec4(0.0, 0.0, 0.0, 0.0);		
+            
+        vAngle = customAngle;
+
+        vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
+        gl_PointSize = customSize * ( 300.0 / length( mvPosition.xyz ) );     
+        gl_Position = projectionMatrix * mvPosition;
+    }
+` 
+
+export const fragmentShader = `
+    uniform sampler2D u_sampler;
+    varying vec4 vColor;	
+    varying float vAngle;  
+    void main()
+    {
+        gl_FragColor = vColor;
+        
+        float c = cos(vAngle);
+        float s = sin(vAngle);
+        vec2 rotatedUV = vec2(c * (gl_PointCoord.x - 0.5) + s * (gl_PointCoord.y - 0.5) + 0.5, c * (gl_PointCoord.y - 0.5) - s * (gl_PointCoord.x - 0.5) + 0.5);  
+        vec4 rotatedTexture = texture2D( u_sampler,  rotatedUV );
+        gl_FragColor = gl_FragColor * rotatedTexture;   
+    }
+`

+ 5 - 5
src/utils/AnnotationTool.js

@@ -1,9 +1,9 @@
 
-import * as THREE from "../../libs/three.js/build/three.module.js";
-import {Annotation} from "../Annotation.js";
-import {Utils} from "../utils.js";
-import {CameraMode} from "../defines.js";
-import {EventDispatcher} from "../EventDispatcher.js";
+import * as THREE from "../../../libs/three.js/build/three.module.js";
+import {Annotation} from "../../Annotation.js";
+import {Utils} from "../../utils.js";
+import {CameraMode} from "../../defines.js";
+import {EventDispatcher} from "../../EventDispatcher.js";
 
 export class AnnotationTool extends EventDispatcher{
 	constructor (viewer) {

+ 1 - 1
src/utils/Box3Helper.js

@@ -8,7 +8,7 @@
  * @author mschuetz / http://potree.org
  */
 
-import * as THREE from "../../libs/three.js/build/three.module.js";
+import * as THREE from "../../../libs/three.js/build/three.module.js";
 
 export class Box3Helper extends THREE.LineSegments {
 	constructor (box, color) {

+ 1 - 1
src/utils/ClipVolume.js

@@ -1,5 +1,5 @@
 
-import * as THREE from "../../libs/three.js/build/three.module.js";
+import * as THREE from "../../../libs/three.js/build/three.module.js";
 
 export class ClipVolume extends THREE.Object3D{
 	

+ 2 - 2
src/utils/ClippingTool.js

@@ -1,9 +1,9 @@
 
 
-import * as THREE from "../../libs/three.js/build/three.module.js";
+import * as THREE from "../../../libs/three.js/build/three.module.js";
 import {ClipVolume} from "./ClipVolume.js";
 import {PolygonClipVolume} from "./PolygonClipVolume.js";
-import { EventDispatcher } from "../EventDispatcher.js";
+import { EventDispatcher } from "../../EventDispatcher.js";
 
 export class ClippingTool extends EventDispatcher{
 

+ 2 - 2
src/utils/Compass.js

@@ -1,7 +1,7 @@
 
-import * as THREE from "../../libs/three.js/build/three.module.js";
+import * as THREE from "../../../libs/three.js/build/three.module.js";
 
-import {Utils} from "../utils.js";
+import {Utils} from "../../utils.js";
 
 export class Compass{
 

+ 8 - 8
src/utils/Measure.js

@@ -1,13 +1,13 @@
 
-import * as THREE from "../../libs/three.js/build/three.module.js";
+import * as THREE from "../../../libs/three.js/build/three.module.js";
 import {TextSprite} from "../TextSprite.js"; 
-import {Utils} from "../utils.js";
-import  Label  from "./Label.js";
-import {LineDraw} from "../utils/DrawUtil";
-import math from "./math.js"; 
-import DepthBasicMaterial from "../materials/DepthBasicMaterial.js";
-import Sprite from '../viewer/Sprite'
-import {config} from '../settings'
+import {Utils} from "../../utils.js";
+import  Label  from "../Label.js";
+import {LineDraw} from "../../utils/DrawUtil";
+import math from "../../utils/math.js"; 
+import DepthBasicMaterial from "../../materials/DepthBasicMaterial.js";
+import Sprite from '../Sprite'
+import {config} from '../../settings'
 
 import {ctrlPolygon} from './ctrlPolygon'
 

+ 10 - 9
src/utils/MeasuringTool.js

@@ -1,10 +1,10 @@
 
-import * as THREE from "../../libs/three.js/build/three.module.js";
+import * as THREE from "../../../libs/three.js/build/three.module.js";
 import {Measure} from "./Measure.js";
-import {Utils} from "../utils.js"; 
-import math from "./math.js";
-import {CameraMode} from "../defines.js";
-import { EventDispatcher } from "../EventDispatcher.js";
+import {Utils} from "../../utils.js"; 
+import math from "../../utils/math.js";
+import {CameraMode} from "../../defines.js";
+import { EventDispatcher } from "../../EventDispatcher.js";
  
 function updateAzimuth(viewer, measure){
     if(!measure.showAzimuth)return
@@ -517,7 +517,7 @@ export class MeasuringTool extends EventDispatcher{
             
             if(e.button === THREE.MOUSE.RIGHT)return 
             
-            console.log('measure clicked33', !!e.intersectPoint)
+            //console.log('measure clicked33', !!e.intersectPoint)
              
             var I = e.intersectPoint && (e.intersectPoint.orthoIntersect || e.intersectPoint.location)
             if(!I)return
@@ -536,9 +536,10 @@ export class MeasuringTool extends EventDispatcher{
             measure.dragMarker(e) 
             measure.dropMarker(e)
             
-            measure.markers[1].visible = false
-            measure.edges[1].visible = false
-            
+            if(measure.maxMarkers > 1 ){
+                measure.markers[1].visible = false
+                measure.edges[1].visible = false
+            }
             if(measure.maxMarkers>2 && !measure.isRect){ 
                 measure.markers[0].addEventListener('mouseover', mouseover);
                 measure.markers[0].addEventListener('mouseleave', mouseleave);

+ 1 - 1
src/utils/PolygonClipVolume.js

@@ -1,5 +1,5 @@
 
-import * as THREE from "../../libs/three.js/build/three.module.js";
+import * as THREE from "../../../libs/three.js/build/three.module.js";
 
 export class PolygonClipVolume extends THREE.Object3D{
 	

+ 2 - 2
src/utils/Profile.js

@@ -1,6 +1,6 @@
 
-import * as THREE from "../../libs/three.js/build/three.module.js";
-import {Utils} from "../utils.js";
+import * as THREE from "../../../libs/three.js/build/three.module.js";
+import {Utils} from "../../utils.js";
 
 export class Profile extends THREE.Object3D{
 

+ 3 - 3
src/utils/ProfileTool.js

@@ -1,8 +1,8 @@
 
-import * as THREE from "../../libs/three.js/build/three.module.js";
+import * as THREE from "../../../libs/three.js/build/three.module.js";
 import {Profile} from "./Profile.js";
-import {Utils} from "../utils.js";
-import { EventDispatcher } from "../EventDispatcher.js";
+import {Utils} from "../../utils.js";
+import { EventDispatcher } from "../../EventDispatcher.js";
 
 
 export class ProfileTool extends EventDispatcher {

+ 4 - 4
src/utils/ScreenBoxSelectTool.js

@@ -1,9 +1,9 @@
 
-import * as THREE from "../../libs/three.js/build/three.module.js";
+import * as THREE from "../../../libs/three.js/build/three.module.js";
 import {BoxVolume} from "./Volume.js";
-import {Utils} from "../utils.js";
-import {PointSizeType} from "../defines.js";
-import { EventDispatcher } from "../EventDispatcher.js";
+import {Utils} from "../../utils.js";
+import {PointSizeType} from "../../defines.js";
+import { EventDispatcher } from "../../EventDispatcher.js";
 
 
 export class ScreenBoxSelectTool extends EventDispatcher{

+ 1 - 1
src/utils/SpotLightHelper.js

@@ -1,5 +1,5 @@
 
-import * as THREE from "../../libs/three.js/build/three.module.js";
+import * as THREE from "../../../libs/three.js/build/three.module.js";
 
 export class SpotLightHelper extends THREE.Object3D{
 

+ 2 - 2
src/utils/TransformationTool.js

@@ -1,6 +1,6 @@
 
-import * as THREE from "../../libs/three.js/build/three.module.js";
-import {Utils} from "../utils.js";
+import * as THREE from "../../../libs/three.js/build/three.module.js";
+import {Utils} from "../../utils.js";
 
 
 

+ 1 - 1
src/utils/Volume.js

@@ -1,5 +1,5 @@
 
-import * as THREE from "../../libs/three.js/build/three.module.js";
+import * as THREE from "../../../libs/three.js/build/three.module.js";
 import {TextSprite} from "../TextSprite.js";
 
 export class Volume extends THREE.Object3D {

+ 3 - 3
src/utils/VolumeTool.js

@@ -1,8 +1,8 @@
 
-import * as THREE from "../../libs/three.js/build/three.module.js";
+import * as THREE from "../../../libs/three.js/build/three.module.js";
 import {Volume, BoxVolume} from "./Volume.js";
-import {Utils} from "../utils.js";
-import { EventDispatcher } from "../EventDispatcher.js";
+import {Utils} from "../../utils.js";
+import { EventDispatcher } from "../../EventDispatcher.js";
 
 export class VolumeTool extends EventDispatcher{
 	constructor (viewer) {

+ 3 - 3
src/utils/ctrlPolygon.js

@@ -1,6 +1,6 @@
-import * as THREE from "../../libs/three.js/build/three.module.js";
-import {LineDraw, MeshDraw} from "../utils/DrawUtil";
-import math from "./math.js";
+import * as THREE from "../../../libs/three.js/build/three.module.js";
+import {LineDraw, MeshDraw} from "../../utils/DrawUtil";
+import math from "../../utils/math.js";
 
 
 

+ 5 - 5
src/utils/mapClipBox.js

@@ -1,11 +1,11 @@
 
-import * as THREE from "../../libs/three.js/build/three.module.js";
+import * as THREE from "../../../libs/three.js/build/three.module.js";
 import {ctrlPolygon} from './ctrlPolygon'
-import {LineDraw } from "../utils/DrawUtil";
-import Sprite from '../viewer/Sprite'
-import {config} from '../settings'
+import {LineDraw } from "../../utils/DrawUtil";
+import Sprite from '../../objects/Sprite'
+import {config} from '../../settings'
 
-import math from "../utils/math";
+import math from "../../utils/math";
 let texLoader = new THREE.TextureLoader() 
 
 let color = new THREE.Color(config.clip.color)

+ 2 - 2
src/settings.js

@@ -87,7 +87,7 @@ const config = {//配置参数   不可修改
     moveSpeedAdujust : 0.5  //越小越慢
     ,
     view:{
-        fov:50,  //navvis:50 
+        fov:70,  //navvis:50 
         near:0.1,
         far: 10000,
     },
@@ -346,7 +346,7 @@ let settings = {//设置   可修改
     loadPointsWhenUnfocus:true, //页面unfocus时也仍在加载点云 */
    
     //initialShowPano:true
-    drawEntityData: true,
+    drawEntityData: false,
     
     zoomFromPointert:{//定点缩放(包括点云模式、全景模式、地图)
         whenPanos:true,

+ 45 - 1
src/start.js

@@ -110,7 +110,51 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
                             })
                         } 
                     },1000) */
-                    
+                    if(number == 't-CwfhfqJ'){
+                        let position = Potree.Utils.datasetPosTransform({
+                            pointcloud:viewer.scene.pointclouds[0], 
+                            position: new THREE.Vector3(4.4318,-0.580291847759, -0.78),
+                            fromDataset:true 
+                        }) 
+                        
+                        viewer.modules.ParticleEditor.addParticle( {
+                             type:'fire',
+                             position,
+                             fireRadius:0.42, 
+                        })
+                        viewer.modules.ParticleEditor.addParticle( {
+                             type:'smoke',
+                             position: new THREE.Vector3().addVectors(position,new THREE.Vector3(0,0,0.3)),
+                             positionStyle : 2 ,  /* velocityStyle:2,  */
+                             positionRadius : 0.3,                        
+                             sizeTween: [[0, 0.3, 0.9, 1], [0.1, 0.2,  2,   1]],
+                             opacityBase : 0.2,
+                             opacityTween :[ [0, 0.3,  0.7, 0.95], [0, 0.2, 1 , 0.1, 0] ], 
+                             velocityBase     : new THREE.Vector3( 0,  0,  1),
+                             velocitySpread   : new THREE.Vector3( 0.2, 0.2, -0.3), 
+                             accelerationBase : 0.1,
+                             accelerationSpread : 0.5,	
+                             
+                             particlesPerSecond : 40,
+                             particleDeathAge   : 3.0,                         
+                        })
+                        
+                        viewer.modules.ParticleEditor.addParticle( {
+                             type:'explode',
+                             name:'fire splash',
+                             position: new THREE.Vector3().addVectors(position,new THREE.Vector3(0,0,0.3)), 
+                             size: 0.1,
+                            sizeRange: 0.3,
+                            sizeTween:[[0, 0.05, 0.3, 0.45], [0, 0.05, 0.2, 0.1] ],
+                            speed : 1,            //sphere
+                            speedRange : 4,
+                            positionRadius: 0.1,
+                            acceleration : 0.3,         
+                            accelerationRange : 1,
+                            
+                            particlesPerSecond:40,
+                        })
+                    }
                     
                     viewer.emit('allLoaded')
                 });

+ 4 - 4
src/utils.js

@@ -1,10 +1,10 @@
 
 import * as THREE from "../libs/three.js/build/three.module.js";
 import {XHRFactory} from "./XHRFactory.js";
-import {Volume} from "./utils/Volume.js";
-import {Profile} from "./utils/Profile.js";
-import {Measure} from "./utils/Measure.js";
-import {PolygonClipVolume} from "./utils/PolygonClipVolume.js";
+import {Volume} from "./objects/tool/Volume.js";
+import {Profile} from "./objects/tool/Profile.js";
+import {Measure} from "./objects/tool/Measure.js";
+import {PolygonClipVolume} from "./objects/tool/PolygonClipVolume.js";
 
 export class Utils {
 	static async loadShapefileFeatures (file, callback) {

+ 1 - 1
src/viewer/EDLRenderer.js

@@ -2,7 +2,7 @@
 import * as THREE from "../../libs/three.js/build/three.module.js";
 import {PointCloudSM} from "../utils/PointCloudSM.js";
 import {EyeDomeLightingMaterial} from "../materials/EyeDomeLightingMaterial.js";
-import {SphereVolume} from "../utils/Volume.js";
+import {SphereVolume} from "../objects/tool/Volume.js";
 import {Utils} from "../utils.js";
 import {copyShader} from '../materials/shaders/otherShaders'
 import {Features} from "../Features.js";

+ 1 - 1
src/viewer/HQSplatRenderer.js

@@ -4,7 +4,7 @@ import {NormalizationMaterial} from "../materials/NormalizationMaterial.js";
 import {NormalizationEDLMaterial} from "../materials/NormalizationEDLMaterial.js";
 import {PointCloudMaterial} from "../materials/PointCloudMaterial.js";
 import {PointShape} from "../defines.js";
-import {SphereVolume} from "../utils/Volume.js";
+import {SphereVolume} from "../objects/tool/Volume.js";
 import {Utils} from "../utils.js";
 
 

+ 1 - 1
src/viewer/LoadProject.js

@@ -1,7 +1,7 @@
 
 import * as THREE from "../../libs/three.js/build/three.module.js";
 import {Annotation} from "../Annotation.js";
-import {Measure} from "../utils/Measure.js";
+import {Measure} from "../objects/tool/Measure.js";
 import {CameraAnimation} from "../modules/CameraAnimation/CameraAnimation.js";
 import {Utils} from "../utils.js";
 import {PointSizeType} from "../defines.js";

+ 1 - 1
src/viewer/PropertyPanels/DistancePanel.js

@@ -1,7 +1,7 @@
 
 
 import {MeasurePanel} from "./MeasurePanel.js";
-import {Profile} from "./../../utils/Profile.js";
+import {Profile} from "./../../objects/tool/Profile.js";
 
 export class DistancePanel extends MeasurePanel{
 	constructor(viewer, measurement, propertiesPanel){

+ 3 - 3
src/viewer/PropertyPanels/PropertiesPanel.js

@@ -3,9 +3,9 @@ import * as THREE from "../../../libs/three.js/build/three.module.js";
 import {Utils} from "../../utils.js";
 import {PointCloudTree} from "../../PointCloudTree.js";
 import {Annotation} from "../../Annotation.js";
-import {Measure} from "../../utils/Measure.js";
-import {Profile} from "../../utils/Profile.js";
-import {Volume, BoxVolume, SphereVolume} from "../../utils/Volume.js";
+import {Measure} from "../../objects/tool/Measure.js";
+import {Profile} from "../../objects/tool/Profile.js";
+import {Volume, BoxVolume, SphereVolume} from "../../objects/tool/Volume.js";
 import {CameraAnimation} from "../../modules/CameraAnimation/CameraAnimation.js";
 import {PointSizeType, PointShape, ElevationGradientRepeat} from "../../defines.js";
 import {Gradients} from "../../materials/Gradients.js";

+ 1 - 1
src/viewer/PropertyPanels/VolumePanel.js

@@ -1,7 +1,7 @@
 
 import * as THREE from "../../../libs/three.js/build/three.module.js";
 import {Utils} from "../../utils.js";
-import {Volume, BoxVolume, SphereVolume} from "../../utils/Volume.js";
+import {Volume, BoxVolume, SphereVolume} from "../../objects/tool/Volume.js";
 
 import {MeasurePanel} from "./MeasurePanel.js";
 

+ 1 - 1
src/viewer/Scene.js

@@ -5,7 +5,7 @@ import {CameraMode} from "../defines.js";
 import {View} from "./View.js";
 import {Utils} from "../utils.js";
 import {EventDispatcher} from "../EventDispatcher.js";
-import Axis from './Axis'
+import Axis from '../objects/Axis'
 
 export class Scene extends EventDispatcher{
 

+ 5 - 5
src/viewer/sidebar.js

@@ -2,15 +2,15 @@
 import * as THREE from "../../libs/three.js/build/three.module.js";
 import {GeoJSONExporter} from "../exporter/GeoJSONExporter.js"
 import {DXFExporter} from "../exporter/DXFExporter.js"
-import {Volume, SphereVolume} from "../utils/Volume.js"
-import {PolygonClipVolume} from "../utils/PolygonClipVolume.js"
+import {Volume, SphereVolume} from "../objects/tool/Volume.js"
+import {PolygonClipVolume} from "../objects/tool/PolygonClipVolume.js"
 import {PropertiesPanel} from "./PropertyPanels/PropertiesPanel.js"
 import {PointCloudTree} from "../PointCloudTree.js"
-import {Profile} from "../utils/Profile.js"
-import {Measure} from "../utils/Measure.js"
+import {Profile} from "../objects/tool/Profile.js"
+import {Measure} from "../objects/tool/Measure.js"
 import {Annotation} from "../Annotation.js"
 import {CameraMode, ClipTask, ClipMethod} from "../defines.js"
-import {ScreenBoxSelectTool} from "../utils/ScreenBoxSelectTool.js"
+import {ScreenBoxSelectTool} from "../objects/tool/ScreenBoxSelectTool.js"
 import {Utils} from "../utils.js"
 import {CameraAnimation} from "../modules/CameraAnimation/CameraAnimation.js"
 import {HierarchicalSlider} from "./HierarchicalSlider.js"

+ 15 - 13
src/viewer/viewer.js

@@ -6,25 +6,25 @@ import {PotreeRenderer} from "./PotreeRenderer.js";
 import {EDLRenderer} from "./EDLRenderer.js";
 import {HQSplatRenderer} from "./HQSplatRenderer.js";
 import {Scene} from "./Scene.js";
-import {ClippingTool} from "../utils/ClippingTool.js";
-import {TransformationTool} from "../utils/TransformationTool.js";
+import {ClippingTool} from "../objects/tool/ClippingTool.js";
+import {TransformationTool} from "../objects/tool/TransformationTool.js";
 import {Utils} from "../utils.js";
 import {MapView} from "./map.js";
 import {MapViewer} from "./map/MapViewer.js";
 import {ProfileWindow, ProfileWindowController} from "./profile.js";
-import {BoxVolume} from "../utils/Volume.js";
+import {BoxVolume} from "../objects/tool/Volume.js";
 import {Features} from "../Features.js";
 import {Message} from "../utils/Message.js";
 import {Sidebar} from "./sidebar.js";
 
-import {AnnotationTool} from "../utils/AnnotationTool.js";
-import {MeasuringTool} from "../utils/MeasuringTool.js";
-import {ProfileTool} from "../utils/ProfileTool.js";
-import {VolumeTool} from "../utils/VolumeTool.js";
+import {AnnotationTool} from "../objects/tool/AnnotationTool.js";
+import {MeasuringTool} from "../objects/tool/MeasuringTool.js";
+import {ProfileTool} from "../objects/tool/ProfileTool.js";
+import {VolumeTool} from "../objects/tool/VolumeTool.js";
 
 import {InputHandler} from "../navigation/InputHandler.js";
 import {NavigationCube} from "./NavigationCube.js";
-import {Compass} from "../utils/Compass.js";
+import {Compass} from "../objects/tool/Compass.js";
 import {OrbitControls} from "../navigation/OrbitControls.js";
 import {FirstPersonControls} from "../navigation/FirstPersonControls.js";
 import {EarthControls} from "../navigation/EarthControls.js";
@@ -46,8 +46,8 @@ import {Images360} from "../modules/Images360/Images360.js";
   
  
 
-import Magnifier from "../utils/Magnifier.js";
-import Reticule from "../navigation/Reticule.js";
+import Magnifier from "../objects/Magnifier.js";
+import Reticule from "../objects/Reticule.js";
 import Viewport from "./Viewport.js"
 import {ViewerBase} from "./viewerBase.js"
  
@@ -56,7 +56,8 @@ import cameraLight from "../utils/cameraLight.js";
 import math from "../utils/math.js";
  
 import {UoMService}  from '../utils/UnitConvert'
-import {RouteGuider}  from '../navigation/RouteGuider'
+import {RouteGuider}  from '../modules/route/RouteGuider'
+import ParticleEditor from '../modules/Particles/ParticleEditor'
 import {MeshDraw}  from '../utils/DrawUtil'
 
 
@@ -78,7 +79,7 @@ export class Viewer extends ViewerBase{
             Alignment : Alignment,
             SiteModel : SiteModel,
             RouteGuider : new RouteGuider,
-            
+            ParticleEditor,
         }
         
         this.testingMaxLevel = true
@@ -438,6 +439,7 @@ export class Viewer extends ViewerBase{
             
             this.modules.SiteModel.init()
             this.modules.Alignment.init()
+            this.modules.ParticleEditor.init()
             //-----------
             
             
@@ -2134,7 +2136,7 @@ export class Viewer extends ViewerBase{
 		TWEEN.update(timestamp);
         transitions.update(delta);
         this.transformationTool.update();
-             
+        this.modules.ParticleEditor.update(delta)   
 
 		this.dispatchEvent({
 			type: 'update',