12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319 |
-
- import * as THREE from "../../../../libs/three.js/build/three.module.js";
- import cameraLight from '../../utils/cameraLight.js'
- import math from "../../utils/math.js"
- import Common from '../../utils/Common.js'
- import {LineDraw, MeshDraw} from "../../utils/DrawUtil.js";
- import {transitions, easing, lerp} from '../../utils/transitions.js'
- import SplitScreen from "../../utils/SplitScreen.js";
- import InfiniteGridHelper from '../../objects/InfiniteGridHelper.js'
- import Compass from "../../objects/tool/Compass.js";
- import {TransformControls} from "../../objects/tool/TransformControls.js";
- import History from "../../utils/History.js"
- import {Box3Helper} from "../../../utils/Box3Helper.js";
-
- import {TextSprite} from '../../objects/TextSprite.js'
-
-
- const texLoader = new THREE.TextureLoader()
- texLoader.crossOrigin = "anonymous"
-
-
- const edgeStrengths = {
- pointcloud: 4,
- glb: 100
- }
- const viewportProps = [{
- left:0,
- bottom:0,
- width: 0.5,height:1,
- name : 'top',
- axis:["x","y"],
- direction : new THREE.Vector3(0,0,-1), //镜头朝向
- active: true,
- //相机位置在z轴正向
- limitBound: new THREE.Box3(new THREE.Vector3(-Infinity,-Infinity, 1),new THREE.Vector3(Infinity,Infinity,5000)), //在地面以上
- margin:{x:50, y:150} ,
- },
- {
- left:0.5,
- bottom:0,
- width: 0.5,height:1,
- name : 'right',
- axis:["y","z"],
- direction : new THREE.Vector3(1,0,0),
- active: true,
- //相机位置在x轴负向 右下角屏
- viewContainsPoints:[new THREE.Vector3(0,0,0)],
- margin:{x:300, y:250} ,
- } ]
- let cylinderSkyGeo, oldSkyGeo
-
-
- let MergeEditor = {
- bus:new THREE.EventDispatcher(),
-
-
- SplitScreen : new SplitScreen(),
-
- init(){
-
- this.boxHelper = new Box3Helper(new THREE.Box3(new THREE.Vector3(-0.5,-0.5,-0.5), new THREE.Vector3(0.5,0.5,0.5)));
- viewer.scene.scene.add(this.boxHelper)
- Potree.Utils.updateVisible(this.boxHelper,'unselect',false)
-
- this.lastMemoryState = {}
-
-
- this.history = new History({
- applyData: (data)=>{
- if(data.object.parent /* && data.object == this.selected */){
- data = Potree.Common.CloneObject(data) //避免使用后更改数据又被使用
- data.matrix.decompose( data.object.position, data.object.quaternion, data.object.scale );
- data.object.boundCenter.copy(data.boundCenter)
- data.object.dispatchEvent('changeByHistory')
- data.object.dispatchEvent('transformChanged')
- viewer.dispatchEvent('content_changed')
-
- return true
- }
- },
- getData:(object)=>{
- return {
- object,
- matrix: object.matrixWorld.clone(),
- boundCenter: object.boundCenter.clone()
- }
- }
- })
-
-
-
- {
-
- Potree.settings.notAdditiveBlending = true
-
- let ground = this.ground = new InfiniteGridHelper(1, 10000, new THREE.Color('#eee'), 10000, 0.2, 0.3)
- viewer.scene.scene.add(ground)
- //再加两条线否则在正侧边看不到
- let line1 = LineDraw.createLine([new THREE.Vector3(-10000, 0, 0),new THREE.Vector3(10000, 0, 0) ], {color:'#aaa', })
- let line2 = LineDraw.createLine([new THREE.Vector3(0, -10000, 0),new THREE.Vector3(0, 10000, 0) ], {mat:line1.material})
- ground.renderOrder = Potree.config.renderOrders.model + 1//line1.renderOrder + 1 //要比模型低,否则模型透明时效果不对
- ground.add(line1)
- ground.add(line2)
- ground.material.opacity = 0.9 //为了滞后渲染,否则被rt遮住
- ground.material.polygonOffset = true //多边形偏移(视觉上没有移动模型位置),防止闪烁
- ground.material.polygonOffsetFactor = 100 //多边形偏移因子
- ground.material.polygonOffsetUnits = 10 //多边形偏移单位
- ground.material.depthWrite = false
- //ground.material.depthTest = false
- line1.material.polygonOffset = true
- line1.material.polygonOffsetFactor = 130
- line1.material.polygonOffsetUnits = 10
- line1.material.depthWrite = false
- //见笔记:透明物体的材质设置
- }
-
- let oriEdgeStrength = viewer.outlinePass.edgeStrength
- {
-
- this.transformControls = new TransformControls(viewer.mainViewport.camera, viewer.renderArea,{
- //dontHideWhenFaceCamera: true,
- });
- //this.transformControls.space = 'local'//为了在当前方向上平移
- this.transformControls.setSize(1.5)
- viewer.scene.scene.add(this.transformControls)
- this.transformControls._gizmo.hideAxis = {rotate:['e'] ,scale:['x','y','z' ] }
- this.transformControls._gizmo.showAxis = {scale:['XYZY']} //仅显示 等于而非包含
- this.transformControls.setRotateMethod(2)
-
-
- //右屏
- this.transformControls2 = new TransformControls(viewer.mainViewport.camera, viewer.renderArea,{
- //dontHideWhenFaceCamera: true,
- });
- this.transformControls2.setSize(1.5)
- viewer.scene.scene.add(this.transformControls2)
- Potree.Utils.setObjectLayers(this.transformControls2, 'layer2' )
-
-
- let mouseDown = (e)=>{
-
- viewer.outlinePass.edgeStrength = 0//暂时消失线
-
- }
- let mouseUp = (e)=>{
-
- //this.updateEdgeStrength()
- viewer.outlinePass.edgeStrength = oriEdgeStrength
- }
- this.transformControls.addEventListener('mouseDown',mouseDown)
- this.transformControls2.addEventListener('mouseDown',mouseDown)
- this.transformControls.addEventListener('mouseUp',mouseUp)
- this.transformControls2.addEventListener('mouseUp',mouseUp)
-
-
-
-
-
- this.transformControls.addEventListener('mouseDown', ()=>{ //dragstart
- this.history.beforeChange(this.selected)
- })
- this.transformControls.addEventListener('mouseUp',()=>{
- this.history.afterChange(this.selected)
- })
- }
-
-
- {
-
- this.secondCompass = new Compass(null)
-
- }
-
- viewer.setControls(viewer.orbitControls)
- //viewer.mainViewport.view.fixZWhenPan = true
- viewer.orbitControls.constantlyForward = true
-
-
- viewer.addEventListener('global_single_click',(e)=>{
- if(
- e.button != THREE.MOUSE.LEFT
- || this.noNeedSelection //如模型查看页
- || viewer.scene.cameraAnimations.some(c=>c.onUpdate) //正在播放
- || e.drag && e.drag.notPressMouse //在加测量线
- || viewer.mainViewport.view.isFlying() //有其他校准
- || this.split //分屏中
- || e.clickElement //触发别的点击事件,如测量时click marker /* && e.clickElement != e.intersect.object */
- ){
- return
- }
-
- if(e.intersect){
- let object = e.intersect.object || e.intersect.pointcloud
- let objects = this.getAllObjects()
- let posInModel = Potree.Utils.datasetPosTransform({ toDataset: true, position: e.intersect.location.clone(), object })
- if(objects.includes(object) && this.selected != object){
- this.selectModel(object, posInModel)
- }else{
- //if(!viewer.inputHandler.selection[0]){//正在平移和旋转,不允许取消
- if(this.selected == object && this.transformControls.mode == 'translate'){
- this.selectModel(object, posInModel) //update click pos
- }else{
- this.selectModel(null)
- }
- //}
- }
- }else{
- //if(!viewer.inputHandler.selection[0]){
- this.selectModel(null)
- //}
- }
- })
-
- viewer.inputHandler.addEventListener('keydown', (e)=>{
- if((e.event.key).toLowerCase() == "h" ){
- this.fadeOutlineAuto = !this.fadeOutlineAuto
- this.showModelOutline(this.selected,!!this.selected)
- }
- })
- //viewer.fxaaPass.enabled = false//viewer.ssaaRenderPass.enabled = false
- viewer.outlinePass.enabled = true
- //Potree.settings.intersectWhenHover = false
- //Potree.Utils.updateVisible(viewer.reticule, 'force', false)
- viewer.composer.scaleRatio = 1
- viewer.composer.readTarget = false
-
- viewer.addEventListener('updateModelBound', (e)=>{
- if(this.split){
- this.SplitScreen.updateCameraOutOfModel(/* this.selected && [this.selected] */)
- }
- })
-
-
- {//校准页面拖拽
- //左右屏都可以拖拽模型,旋转只能左屏
- let dragInfo
- let drag = (e)=>{
- if(this.split && this.selected && this.transformState && (e.dragViewport.name == 'top' || this.transformState == 'translate') ){
- if(e.type == 'global_mousedown' ){ //开始
- //if((e.intersect.object || e.intersect.pointcloud) == this.selected){
- if(e.intersect.pointclouds.includes(this.selected) || e.intersect.allElements.some(e=>e.object == this.selected)){
-
- dragInfo = {}
- //if(this.selected.isPointcloud){
- viewer.outlinePass.edgeStrength = 0//暂时消失线
- //}
- }
- }
-
- if(e.type == 'global_drag' && dragInfo ){
- if(this.transformState == 'translate'){
-
- let moveVec = Potree.Utils.getOrthoCameraMoveVec(e.drag.pointerDelta, e.dragViewport.camera )//最近一次移动向量
- this.selected.position.add(moveVec)
-
- this.selected.dispatchEvent("position_changed")
- }else if(this.transformState == 'rotate'){
-
- let vec = new THREE.Vector3().subVectors(e.intersect.orthoIntersect || e.intersect.location, this.selected.boundCenter).setZ(0)
- if(dragInfo.lastVec == void 0){//global_mousedown
- dragInfo.lastVec = vec
- return
- }
- let angle = math.getAngle(dragInfo.lastVec, vec, 'z')
- dragInfo.lastVec = vec
-
- //this.selected.rotation.z += angle //局部
-
-
- /* object.quaternion.copy( .setFromAxisAngle( new THREE.Vector3(0,0,1), angle ) );
- object.quaternion.multiply( quaternionStart ).normalize(); */
- let diffQua = new THREE.Quaternion().setFromAxisAngle( new THREE.Vector3(0,0,1), angle )
- this.selected.quaternion.premultiply(diffQua) //世界
-
-
- this.selected.dispatchEvent("rotation_changed")
- }
-
- return {stopContinue:true}
- }
- }
-
- }
-
- viewer.addEventListener('global_mousedown', drag)
- viewer.addEventListener('global_drag', drag, {importance:10})
- viewer.addEventListener('global_mousemove', (e)=>{
- if(this.split && this.transformState && !e.drag && (e.hoverViewport.name == 'top' || this.transformState == 'translate')){
-
- /* if(this.lastHoverViewport != e.hoverViewport){
- this.lastHoverViewport = e.hoverViewport
- this.transformControls.view = e.hoverViewport.view
- this.transformControls.camera = e.hoverViewport.camera
- this.transformControls.hideAxis( this.transformState, e.hoverViewport.name == 'top' ? [z] : [x,y]);
- } */
-
-
-
-
- let mouseover = e.intersect.pointclouds.includes(this.selected) || e.intersect.allElements.some(e=>e.object == this.selected)
- //let mouseover = (e.intersect.object || e.intersect.pointcloud) == this.selected
- if(mouseover){
- if(this.transformState == 'translate'){
- viewer.dispatchEvent({
- type : "CursorChange", action : "add", name:"movePointcloud"
- })
- }else{
- viewer.dispatchEvent({
- type : "CursorChange", action : "add", name:"rotatePointcloud"
- })
- }
- }else{
- this.clearTranCursor()
- }
-
- }
- })
-
- viewer.addEventListener('global_drop', (e)=>{
- dragInfo = null
- this.clearTranCursor()
-
- //this.updateEdgeStrength()
- viewer.outlinePass.edgeStrength = oriEdgeStrength
-
- })
-
- }
-
-
- /* viewer.addEventListener('background_changed',()=>{
-
- }) */
-
-
- viewer.addEventListener('camera_changed',()=>{//其实静止时内存也会变,因为在加载
- this.lastMemoryState.history = [] //clear
- Common.intervalTool.isWaiting('updateMemoryUsage', ()=>{
- return this.updateMemoryUsage()
- }, 1000)
- })
-
-
- viewer.addEventListener('setDisplay',this.updateMemoryUsage.bind(this))
- },
-
-
- clearTranCursor(){
- viewer.dispatchEvent({
- type : "CursorChange", action : "remove", name:"movePointcloud"
- })
- viewer.dispatchEvent({
- type : "CursorChange", action : "remove", name:"rotatePointcloud"
- })
- },
-
- enterSplit(){
- this.split = true
- if(this.selected) this.SplitScreen.focusCenter = this.selected.boundCenter //旋转中心。注意 boundCenter不能直接赋值,否则改变后focusCenter也要改
- else this.SplitScreen.focusCenter = null
-
- this.SplitScreen.splitStart(viewportProps)
-
- this.beforeSplit = {
- pointDensity: Potree.settings.pointDensity,
- }
- Potree.settings.pointDensity = 'fourViewports' //强制降低点云质量
-
-
- viewer.setControls(viewer.fpControls)
-
- let rightViewport = viewer.viewports.find(e=>e.name == 'right')
- let topViewport = viewer.viewports.find(e=>e.name == 'top')
- topViewport.alignment = true
- rightViewport.rotateSide = true
- rightViewport.skyboxFixPos = true
- rightViewport.skyboxMinZoom = 10
- rightViewport.skyboxRenderFun = ()=>{// 使cube的一面永远正向镜头。 因侧视图的camera是ortho类型,需要平视mesh才不会拉伸
- viewer.skybox.scene.children[0].rotation.copy(rightViewport.camera.rotation)
- }
- topViewport.skyboxRenderFun = ()=>{
- viewer.skybox.scene.children[0].rotation.set(0,0,0)
- }
-
-
-
- viewer.viewports[1].layersAdd('layer2')
- viewer.viewports[0].layersAdd('layer1')
- Potree.Utils.setObjectLayers(this.transformControls, 'layer1' )
- this.transformControls.view = viewer.viewports[0].view
- this.transformControls.camera = viewer.viewports[0].camera
- this.transformControls._gizmo.hideAxis = {translate:['z'], rotate:['x','y','z'] }
- this.transformControls2.view = viewer.viewports[1].view
- this.transformControls2.camera = viewer.viewports[1].camera
- this.transformControls2._gizmo.hideAxis = {translate:['x','y'], rotate:['x','y','z'] }
-
- this.secondCompass.changeViewport(viewer.viewports[0])
- this.secondCompass.setDomPos()
- this.secondCompass.setDisplay(true)
- viewer.compass.changeViewport(viewer.viewports[1])
- viewer.compass.setDomPos()
-
-
- //this.changeSkyboxGeo(true)
- },
-
-
- leaveSplit(){
- this.split = false
- this.SplitScreen.unSplit()
- viewer.setControls(viewer.orbitControls)
-
- Potree.settings.pointDensity = this.beforeSplit.pointDensity
- /* if(this.selected && this.selected.isPointcloud){
- this.showModelOutline(this.selected, true)
- this.selected.material.activeAttributeName = "rgba"
- } */
- this.transformControls.camera = viewer.viewports[0].camera
- this.transformControls.view = viewer.viewports[0].view
- this.transformControls._gizmo.hideAxis = {rotate:['e']}
- Potree.Utils.setObjectLayers(this.transformControls, 'sceneObjects' ) //恢复
-
-
- viewer.compass.changeViewport(viewer.viewports[0]) //恢复
- viewer.compass.setDomPos()
- this.secondCompass.setDisplay(false)
-
-
- },
-
- rotateSideCamera(angle){
- this.SplitScreen.rotateSideCamera(viewer.viewports.find(e=>e.name == 'right'), angle)
- },
-
- setTransformState(state){//校准时
- this.transformState = state
- this.clearTranCursor()
- },
-
- //---------------------------
-
- getAllObjects(){
- return viewer.objs.children.concat(viewer.scene.pointclouds)
- },
-
- getModel(id){
- let models = this.getAllObjects()
- return models.find(e=>e.dataset_id == id)
- },
-
- changeModelPointCount(object, type){
- if(object.fileType == '3dTiles' || object.isPointcloud) return
-
- let posCount , texArea
- if(type == 'add'){
- let o = viewer.getObjectPointCount(object)
- posCount = o.posCount, texArea = o.texArea
- object.posCount = posCount, object.texArea = texArea
- }else{
- posCount = -object.posCount, texArea = -object.texArea
- }
-
- viewer.memoryModelCountInfo.otherPosCount += posCount
- viewer.memoryModelCountInfo.otherTexArea += texArea
- },
- modelAdded(model){
- /* model.addEventListener('isVisible',(e)=>{
- if(e.reason == "overlinePass")return
- //console.log(e)
- viewer.addEventListener('update',()=>{ //下一次更新结束后
- this.updateMemoryUsage()
- },{once:true})
- }) */
- let weightUpdate = ()=>{
- this.changeModelPointCount(model,'add')
- this.updateMemoryUsage()
- }
-
- if(model.fileType == 'obj'){//要等待贴图都加载完
- if(viewer.fileManager.loading){
- viewer.addEventListener('managerOnLoad',(e)=>{
- weightUpdate()
- },{once:true}) //如果onError了咋办,暂时无法定位manager加载的哪个模型的
- }
- }else{
- weightUpdate()
- }
-
- },
- removeModel(model){
- if(this.selected == model) this.selectModel(null)
- let dispose = (e)=>{
- e.geometry && e.geometry.dispose()
- e.material && e.material.dispose()
- }
- if(model.isPointcloud){
- dispose(model)
- viewer.scene.removePointCloud(model)
- }else{
- model.traverse(e=>{
- dispose(e)
- })
- viewer.objs.remove(model)
-
- }
-
- model.panos?.slice().forEach(e=>{
- e.dispose()
- })
- viewer.images360.tileDownloader.setPanoData(viewer.images360.panos, [] );
-
- if(model.fileType == '3dTiles'){
- model.traverse(child=>{
- if(child.runtime){
- child.runtime.getTileset().destroy()
- return {stopContinue:true}
- }
- })
-
- }
-
- this.changeModelPointCount(model,'sub')
- this.updateMemoryUsage()
- },
-
- selectModel(model, state=true, fitBound, by2d){
- if(!model) {
- model = this.selected
- state = false
- }
- if(!by2d && model){
- model.dispatchEvent({type:'changeSelect', selected : state, clickPos:state})
- }
- if(state){
- if(this.selected){
- if(this.selected == model) return
- else{
- let transToolAttached = !!this.transformControls.object
- this.selectModel(this.selected, false, fitBound, by2d)
- transToolAttached && this.transformControls.attach(model)
- }
- }
- this.selected = model
-
- MergeEditor.focusOn(model, 500, !!fitBound) //通过在场景里点击模型的话,不focus
-
-
- this.showModelOutline(model)
-
- //this.updateEdgeStrength()
-
- //console.log('selectModel', model)
-
- }else{
- if(this.selected != model)return //model本来就没选中,不需要处理(防止2d先选中新的再取消旧的)
- this.showModelOutline(model, false)
-
- this.selected = null
- this.transformControls.detach() //viewer.transformObject(null);
- //console.log('selectModel', null)
- }
-
-
-
-
-
-
-
-
- },
-
- updateBoxHelper(model){
- let size = new THREE.Vector3
- model.boundingBox.getSize(size)
- size.multiply(model.scale)
- this.boxHelper.scale.copy(size)
-
- let center = new THREE.Vector3
- model.boundingBox.getCenter(center)
- center.applyMatrix4(model.matrixWorld)
- //center.add(model.position)
- this.boxHelper.position.copy(center)
-
- this.boxHelper.quaternion.copy(model.quaternion)
- viewer.dispatchEvent('content_changed')
- },
-
-
-
- showModelOutline(model, state){
- if(Potree.settings.selectShowBox || (model ? model.fileType == '3dgs' : this.boxHelper.visible) ){//高斯很卡
- if(state !== false ){
- this.updateBoxHelper(model)
- Potree.Utils.updateVisible(this.boxHelper,'unselect',true)
- }else{
- Potree.Utils.updateVisible(this.boxHelper,'unselect',false)
- }
- return
- }
-
-
-
- if(this.fadeOutlineAuto){
- if(state === false){
- viewer.outlinePass.selectedObjects = []
- clearTimeout(this.timer)
- return
- }
-
- viewer.outlinePass.selectedObjects = [model]
- if(this.timer){
- clearTimeout(this.timer)
- }
-
- this.timer = setTimeout(()=>{
- viewer.outlinePass.selectedObjects = []
- viewer.dispatchEvent('content_changed')
- }, 1000)
- }else{
- if(state === false){
- viewer.outlinePass.selectedObjects = []
- }else{
- viewer.outlinePass.selectedObjects = [model]
- }
- }
- viewer.dispatchEvent('content_changed')
- },
-
- /*updateEdgeStrength(){
- if(!this.selected)return
- if(this.selected.isPointcloud){
- viewer.outlinePass.edgeStrength = edgeStrengths.pointcloud// / this.selected.material.opacity
- }else{
- viewer.outlinePass.edgeStrength = edgeStrengths.glb
- }
- },*/
- focusOn(objects, duration = 400, fitBound=true, dontLookUp, dir){
- if(!(objects instanceof Array)){
- objects = [objects]
- }
- let boundingBox = new THREE.Box3
- objects.forEach(object=>{
- boundingBox.union(object.boundingBox.clone().applyMatrix4(object.matrixWorld))
- })
-
- let len = boundingBox.getSize(new THREE.Vector3).length()
- Potree.settings.cameraFar = Math.max( Potree.settings.cameraFar, len*3 )
-
- if(fitBound){
- viewer.focusOnObject({boundingBox}, 'boundingBox', duration, {dontLookUp, dontChangeCamDir:dir?false:true, dir})
- }else{
-
- /*
- let position = viewer.inputHandler.intersect ? viewer.inputHandler.intersect.location : boundingBox.getCenter(new THREE.Vector3)
- position && viewer.focusOnObject({position}, 'point', duration, {dontChangePos: true})
- */
- let position = viewer.inputHandler.intersect ? viewer.inputHandler.intersect.location : boundingBox.getCenter(new THREE.Vector3)
- if(!position)return
-
-
- /* let targetOld = viewer.mainViewport.view.getPivot()
-
- let projected1 = targetOld.clone().project(viewer.mainViewport.camera);
- let projected2 = position.clone().project(viewer.mainViewport.camera); //使用其z
- let targetNew = projected1.clone().setZ(projected2.z).unproject(viewer.mainViewport.camera);
- viewer.mainViewport.view.lookAt(targetNew) */
-
-
- viewer.mainViewport.view.radius = viewer.mainViewport.camera.position.distanceTo(position)
- //为了不改画面,不调节方向了,只能调调radius,一定程度将target靠近model
- }
- },
-
-
- moveBoundCenterTo(model,pos){ //使boundCenter在所要的位置
- let diff = new THREE.Vector3().subVectors(pos, model.boundCenter)
- model.position.add(diff);
- },
-
- getBoundCenter(model){
- if(!model.boundCenter) {
- model.boundCenter = new THREE.Vector3
- model.boundSize = new THREE.Vector3
- }
- let bound = model.boundingBox.clone().applyMatrix4(model.matrixWorld)
- bound.getCenter(model.boundCenter)
- bound.getSize(model.boundSize)
- //model.boundingBox.getCenter(model.boundCenter).applyMatrix4(model.matrixWorld)
- },
-
- setModelBtmHeight(model, z ){
- //无论模型怎么缩放、旋转,都使最低点为z
- if(z == void 0) z = model.btmHeight; //维持离地高度
- else model.btmHeight = z;
-
- if(model.btmHeight == void 0)return
- model.updateMatrixWorld()
- this.getBoundCenter(model)
- /* let boundingBox2 = model.boundingBox.clone().applyMatrix4(model.matrixWorld)
- let size = boundingBox2.getSize(new THREE.Vector3);
- let center = boundingBox2.getCenter(new THREE.Vector3); */
- let hopeZ = z + model.boundSize.z / 2
- //model.position.z = z + size.z / 2 - center.z
- model.position.z += (hopeZ - model.boundCenter.z)
- },
-
- computeBtmHeight(model){ //位移之后重新计算btmHeight
- model.updateMatrixWorld()
- /* let boundingBox2 = model.boundingBox.clone().applyMatrix4(model.matrixWorld)
- let size = boundingBox2.getSize(new THREE.Vector3);
- let center = boundingBox2.getCenter(new THREE.Vector3); */
- this.getBoundCenter(model)
- model.btmHeight = model.boundCenter.z - model.boundSize.z / 2
- },
-
-
- maintainBoundXY(model){ //在旋转和缩放后,立即执行这个函数,使boundCenter保持原位
-
- model.updateMatrixWorld()
- let center1 = model.boundCenter.clone();//还未更新的
- this.getBoundCenter(model)//更新
- let center2 = model.boundCenter.clone();
- let diff = new THREE.Vector2().subVectors(center1,center2);
- model.position.x += diff.x;
- model.position.y += diff.y;
- model.boundCenter.copy(center1)
- },
-
-
-
- maintainBoundCenter(model){
- model.updateMatrixWorld()
- let center1 = model.boundCenter.clone();//还未更新的
- this.getBoundCenter(model)//更新
- let center2 = model.boundCenter.clone();
- let diff = new THREE.Vector3().subVectors(center1,center2);
- model.position.add(diff)
- model.boundCenter.copy(center1)
- },
-
- modelTransformCallback(model,force){
-
- model.updateMatrixWorld()
- if(!force && model.matrixWorld.equals(model.lastMatrixWorld))return
- viewer.scene.measurements.forEach(measure=>{
- let changed
- measure.points_datasets.forEach((dataset_id,i)=>{
- if(dataset_id == model.dataset_id){
- changed = true
- measure.points[i] = Potree.Utils.datasetPosTransform({fromDataset:true,datasetId:dataset_id, position:measure.dataset_points[i].clone()})
- measure.updateMarker(measure.markers[i], measure.points[i])
-
- }
- })
- if(changed){//仿transformByPointcloud
- measure.getPoint2dInfo(measure.points)
- measure.update()
- measure.setSelected(false)//隐藏edgelabel
- }
- })
- viewer.tags.children.forEach(tag=>{
- if(tag.root == model){
- tag.titleLabel.updatePose()
- }
- })
-
-
-
- //反向求transformMatrix 参考Alignment.js 移动漫游点
- if(model.isPointcloud && model.transformMatrix){
- model.transformMatrix.multiplyMatrices(model.matrix, model.pos1MatrixInvert)
- model.rotateMatrix = new THREE.Matrix4().makeRotationFromEuler(model.rotation);
- model.panos.forEach(e=>e.transformByPointcloud())
- }else if(model.panos){
- model.rotateMatrix = new THREE.Matrix4().makeRotationFromEuler(model.rotation).multiply(model.rot1MatrixInvert);
- model.transformMatrix.multiplyMatrices(model.matrix, model.posRot1MatrixInvert)
- model.panos.forEach(e=>e.transformByPointcloud())
- model.bound = model.boundingBox.clone().applyMatrix4(model.matrixWorld)
- }
- if(model.panos){
- model.transformInvMatrix.copy(model.transformMatrix).invert()
- model.rotateInvMatrix.copy(model.rotateMatrix).invert()
-
- model.panos.forEach(e=>{
- e.marker.scale.copy(model.scale)
- })
- }
-
-
-
- model.lastMatrixWorld = model.matrixWorld.clone()
- viewer.dispatchEvent('content_changed')
- viewer.mapViewer && Potree.settings.showObjectsOnMap && viewer.mapViewer.dispatchEvent('content_changed')
-
-
- //--------
- this.selected == model && this.updateBoxHelper(model)
-
- },
-
-
- changeOpacity(model, opacity){
-
- let isRoot = model.dataset_id != void 0 //是否是最外层
-
-
- if(model.isPointcloud){
- model.changePointOpacity(opacity)
- //MergeEditor.updateEdgeStrength()
- }else{
- //model.traverse(e=>e.material && setOp(e, opacity))
- model.traverse(mesh=>{
- if(mesh.material){
- let mats = (mesh.material instanceof Array) ? mesh.material : [mesh.material]
- mats.forEach(mat=>{
- if(mat.originOpacity == void 0 ){
- mat.originOpacity = mesh.material.opacity
- }
- mat.opacity = mat.originOpacity * opacity
-
- if(mat.opacity<1){
- mat.transparent = true
- /* if(model.isPointcloud){
- mesh.changePointOpacity(realOpacity)
- }else{
- mesh.material.opacity = realOpacity
- } */
-
- mesh.renderOrder = Potree.config.renderOrders.model+1 //如果是一个mesh多个material咋整? obj的。 暂时默认全部opacity一样吧
- //mesh.material.depthWrite = false
- }else{
- mat.transparent = false
- mesh.renderOrder = Potree.config.renderOrders.model
- //mesh.material.depthWrite = true
- }
- mat.depthWrite = mat.opacity > 0.5 //防止的mesh之间完全遮挡,去掉write。write为true会完全遮挡后排的物体。没有write之后需要对渲染排序(three会排序,但有的角度会错)
- })
- }
- })
- }
-
-
- isRoot && (model.opacity = opacity)//记录在最外层
- viewer.dispatchEvent('content_changed')
-
- },
-
- addTitleForModel(model){
- var titleLabel = new TextSprite({
- startClipDis : 0.5,
- clipDistance : 1,//消失距离
- startOcclusDis: 0.5,
- occlusionDistance: 0.9,//变为backColor距离
- maxOcclusionFactor:0.7,
- maxClipFactor:1,
- text:model.name, sizeInfo:{width2d:150},
- rectBorderThick:1,
- borderColor:{r:200,g:200,b:200,a:0.5},
- textColor:{r:255 ,g:255,b:255,a:1.0},
- textshadowColor:'black',
- backgroundColor:{r: 100,g:100,b:100,a:0.3},
- borderRadius: 6,
- fontsize: 20, fontWeight:'',//thick
- renderOrder : Potree.config.renderOrders.tag.label,
- pickOrder: Potree.config.renderOrders.tag.label,
- useDepth : true ,
- maxLineWidth: 300,
- transform2Dpercent:{x:0,y:1.3}, //向上移动
- textAlign: Potree.settings.isOfficial && 'left'
- })
- model.titleLabel = titleLabel
- viewer.scene.scene.add(titleLabel)
- let updatePos = ()=>{
- titleLabel.position.copy(model.boundCenter)
- titleLabel.position.z += model.boundSize.z / 2 //暂时加载模型顶部,但也可能如果旋转了要在头顶
- titleLabel.updatePose()
- }
- let setVisible = ()=>{
- Potree.Utils.updateVisible(titleLabel,'followModel', model.visible)
- viewer.dispatchEvent('content_changed')
- }
- model.addEventListener('transformChanged',updatePos)
- model.addEventListener('isVisible',setVisible)
-
- titleLabel.addEventListener('isVisible',()=>{
- titleLabel.visible && updatePos()
- })
- setVisible()
- updatePos()
-
- },
-
-
-
-
-
- updateMemoryUsage1(){
-
- //obj暂时不管其贴图大小, 因为顶点造成的不仅是内存还有卡顿所以先只看顶点
- const maxMemory = Potree.config.tiles3DMaxMemory + 100 //M 实际估计是这个的10倍
- const eachObjPosWeight = 100/1000/1000 //M 每个顶点pos是3*4个字节?法线3*4和uv2*4 其实还有贴图
- const eachCloudPointWeight = 12/1000/1000 //M 每个点 pos + 颜色 + 法线 大概
- const eachVisiCPointWeight = eachCloudPointWeight * 5 // 或 maxMemory / (6*1000*1000) 大概值接近 (再除以一个数是因为显示的要比内存中的耗更多资源
- const eachGltfPosWeight = 100/1000/1000 //M 每个顶点pos是3*4个字节?法线3*4和uv2*4 其实还有贴图
- let posCount=0
-
- let eachTexPxWeight = 1 / 10 / 1000 / 1000 //不知道“图片缓存”会不会引起崩溃, 它不在“内存占用空间”中, 所以单位weight值设置小一点
- let panosWeight = viewer.images360.panos.filter(e=>e.depthTex).length * 0.7 + viewer.images360.tileDownloader.tilesCount * 512*512 * eachTexPxWeight //深度图和全景图
- let texArea = 0
-
- viewer.objs.children.forEach(e=>{
- if(!e.visible)return
- if(e.fileType == 'glb' || e.fileType == 'obj'){
- e.traverse((mesh)=>{
- if(mesh.geometry){
- posCount += mesh.geometry.attributes.position.count
- }
- if(mesh.material?.map){
- texArea += mesh.material?.map.image.width * mesh.material?.map.image.height
- }
- })
- }else if(e.fileType == '3dTiles'){
-
- }
- })
-
- //获取点云的内存限制
- let objWeight = posCount*eachObjPosWeight + texArea * eachTexPxWeight
- let laserWeight = Potree.numVisiblePoints * eachCloudPointWeight //点云实际显示所占大小
- let laserMemoryWeight = Potree.lru.numPoints * eachCloudPointWeight //点云所使用内存大小
- let tiles3DWeight = (viewer.visiVertexCount || 0) * eachGltfPosWeight //M 3dTiles所占内存大小
- let tiles3DMemoryWeight = viewer.tiles3dMemoryUsage / 1000 / 1000 //M 3dTiles显示的所占内存大小
-
- /* let min = 0.1, max = 6, minP = 100, maxP = 1000000;
- let ratio = Math.round(math.linearClamp(score, minP, maxP, max, min )); */
- let rest = maxMemory - objWeight - tiles3DWeight - panosWeight
- Potree.pointBudget = THREE.Math.clamp(Math.round(rest/eachVisiCPointWeight), Potree.config.pointDensity.low.pointBudget, 1.5*Potree.config.pointDensity.high.pointBudget)
- //Potree.settings.maxLRUPoints
- //获取3dTiles的内存限制
- let tiles3DMaxMemory = maxMemory - Math.round(objWeight + laserWeight + panosWeight)
-
- window.cesiumViewer && (tiles3DMaxMemory-=30)
-
- Potree.settings.tiles3DMaxMemory = THREE.Math.clamp(tiles3DMaxMemory , 30, Potree.config.tiles3DMaxMemory )
-
-
-
-
- //还存在的问题:仍然有隐患,因为没用到真实缓存的大小: tiles3DMemoryWeight laserMemoryWeight, 它们比真实可见的要多。不使用是因为它们无法反应出实际需要的内存量,缓存是只增不减
- //obj等普通mesh限制不了
-
-
- //console.log('objWeight',objWeight.toFixed(1), 'laserMemoryWeight',laserMemoryWeight.toFixed(1), 'tiles3DWeight',tiles3DWeight.toFixed(1), 'pointBudget',Potree.pointBudget, 'tiles3DMaxMemory',tiles3DMaxMemory)
-
-
- //总内存 = 内存占用空间+图片缓存 , obj的缓存比较多在图片中
-
-
-
- //尽量使任务管理器里的内存占用空间不超过2G
- /*
- 崩溃历史:
-
- cesium容易先崩溃,并弹窗报An error occurred while rendering. Rendering has stopped.
- 体育中心:http://192.168.0.140/index.html?caseId=1&app=1&token=1#/fuseEdit/path
- 罗敏电脑崩溃 ,报了ces的崩溃错误。内存占用空间2196M, memory.usedJSheapSize:1812M 崩溃时正在外部浏览模型(导览崩溃过),可能是3dtiles
-
-
- */
- },
-
-
-
-
- updateMemoryUsage(){//新 注意 模型即使隐藏也不会降低内存占用,只是会降低卡顿。 未支持3dgs
- //疑问:1 在不超过最大内存的前提下会因为显示太多模型崩溃吗? 2如何获知每个浏览器最大内存支持?看了一圈,jsHeapSizeLimit都一样怎么办?
- //3dtiles(或模型)的大小是直接用文件大小还是根据点和贴图尺寸计算呢,感觉它会分成两部分,加载的和显示的,都需要考虑。
- //obj暂时不管其贴图大小, 因为顶点造成的不仅是内存还有卡顿所以先只看顶点
- if(window.stopUpdateM) return
-
- //let start = performance.now();
-
- let old = {
- pointBudget : Potree.pointBudget,
- tiles3DMaxMemory: Potree.settings.tiles3DMaxMemory,
- maxLRUPoints : Potree.settings.maxLRUPoints
- }
-
- const maxMemory = 1500 //1500 //M 整体占用内存限制 (不考虑峰值,要等静止后退下来的值) //什么都不加载可能就占了300M
- const eachObjPosWeight = 100/1000/1000 //M 每个顶点pos是3*4个字节?法线3*4和uv2*4 + faceIndex比较难说
- const eachCloudPointWeight = 70/1000/1000 //M 每个点 pos + 颜色 + 法线 大概 根据测试算出来也是这个值 0.00007
- //const eachVisiCPointWeight = eachCloudPointWeight * 5 // 或 maxMemory / (6*1000*1000) 大概值接近 (再除以一个数是因为显示的要比内存中的耗更多资源
- const eachTexPxWeight = 1 / 10 / 1000 / 1000 //每个模型都不一样只能取个大概
- const eachTexPxWeightTiles = eachTexPxWeight * 1.5 //感觉3dtiles的比glb和obj都高很多,是因为文件还在缓存里吗
-
-
- let posCount=0, posCount3dTiles = 0, visiPosCount = 0
-
-
- let panosWeight = 0.1 * (viewer.images360.panos.filter(e=>e.depthTex).length * 0.7 + viewer.images360.tileDownloader.tilesCount * 512*512 * eachTexPxWeight) //深度图和全景图(但似乎是额外放图片缓存里?因为没有增加tex, panoExit后就dispose了, 所以乘以一个小系数。担心图片缓存也可能导致崩溃)
- //let texArea = 0, texArea3dTiles = 0, visiTexArea = 0
- //texArea = viewer.memoryModelCountInfo.otherTexArea + viewer.memoryModelCountInfo.tileTexArea
- //posCount = viewer.memoryModelCountInfo.otherPosCount + viewer.memoryModelCountInfo.tilePosCount
- //posCount3dTiles = viewer.memoryModelCountInfo.tilePosCount
- //texArea3dTiles = viewer.memoryModelCountInfo.tileTexArea
-
-
-
- let otherModelWeight = viewer.memoryModelCountInfo.otherPosCount*eachObjPosWeight + viewer.memoryModelCountInfo.otherTexArea * eachTexPxWeight
- let tilesWeight = (viewer.memoryModelCountInfo.tilePosCount*eachObjPosWeight + viewer.memoryModelCountInfo.tileTexArea * eachTexPxWeightTiles) * 1.5 //3dtiles太占内存了
- let modelWeight = tilesWeight + otherModelWeight //posCount*eachObjPosWeight + texArea * eachTexPxWeight
- //为何obj、glb过后会降很多,而3dtiles降的很少? 不过考虑到glb更卡,且加载瞬间确实占用高,还是不把otherModelWeight改少了吧
-
- Potree.tilesWeight = tilesWeight
- Potree.modelWeight = modelWeight//所有模型
- //Potree.modelVisiWeight = visiPosCount*eachObjPosWeight + visiTexArea * eachTexPxWeight
-
- //经测试,发现模型并不会因为不可见而降低内存,3dtiles加载满了之后拉远,可见weight下降了但内存没降。
- //so,需要测试崩溃是否只与内存有关,如果内存爆了,但都不可见,非常流畅,还会崩溃吗
-
-
-
-
-
- let laserVisiWeight = Potree.numVisiblePoints * eachCloudPointWeight //点云实际显示所占大小
- let laserWeight = Potree.lru.numPoints * eachCloudPointWeight //点云所使用内存大小
- Potree.laserWeight = laserWeight
- let fixedPart = modelWeight - tilesWeight + panosWeight + (window.cesiumViewer ? 30:0) //ces:刚加载时60,静止一段时间后20
- Potree.allWeight = Potree.laserWeight + fixedPart + tilesWeight
- let tiles3dMemoryUsage = viewer.tiles3dMemoryUsage/1024/1024
-
-
- let overRatio = Potree.allWeight / maxMemory
-
- let visiRatio1 = posCount3dTiles == 0 ? Infinity : viewer.visiVertexCount / posCount3dTiles
- let visiRatio2 = Potree.lru.numPoints == 0 ? Infinity : Potree.numVisiblePoints / Potree.lru.numPoints
- let resolved
-
- let restMemory = maxMemory - fixedPart //去除固定的part后
-
-
- if(overRatio > 1){
-
-
-
- const MinRestMemory = 400
- if(restMemory < MinRestMemory){
- Common.intervalTool.isWaiting('updateMemoryUsage', ()=>{
- let warnText
- if(this.lastMemoryState.restMemory < 0){
- warnText = '固定内存已经超额!没有剩余空间给点云和3dtiles。'
- }else if(this.lastMemoryState.restMemory < MinRestMemory){
- warnText = '固定内存过多!'
- }
- if(warnText){
- warnText += '请减少glb类模型, 当前固定内存占用大小:' + fixedPart
- console.error(warnText)
- }
- }, 10000)
- }
-
-
-
-
- if(visiRatio1 < visiRatio2 || Potree.lru.numPoints <= Potree.config.pointDensity.low.pointBudget / 10 * 1.1 ){//占比小的需要缩减缓存容器
-
- if(Potree.settings.tiles3DMaxMemory < tiles3dMemoryUsage / 2 && this.lastMemoryState.tiles3dMemoryUsage == tiles3dMemoryUsage //已经很难减少了,这时候tiles3DMaxMemory很可能降到个位数
- || Potree.settings.tiles3DMaxMemory < 2){
- resolved = false
- }else{
- Potree.settings.tiles3DMaxMemory = Math.min(tiles3dMemoryUsage, Potree.settings.tiles3DMaxMemory)//先降到已使用的数据量
- Potree.settings.tiles3DMaxMemory > 1 && (Potree.settings.tiles3DMaxMemory *= 0.8 ) //注意,降低该值不一定会降低 tiles3dMemoryUsage,只有后续改变sse才行 viewer.tiles3dMemoryUsage / tiles3DMaxMemory 可能大于1
- resolved = true
- }
- }
- if(!resolved){// visiRatio1 > visiRatio2
-
- if( visiRatio2 > 0.9){//压缩太小了,或者说没什么缓存就超额了,只能继续减少显示个数
- if(Potree.pointBudget < Potree.config.pointDensity.low.pointBudget){
- //console.error('Potree.pointBudget已经很小了!', Potree.pointBudget)
- }else{
- Potree.pointBudget *= 0.85
- resolved = true
- }
- }else{
- Potree.pointBudget = THREE.Math.clamp(Potree.numVisiblePoints, Potree.config.pointDensity.low.pointBudget / 10, Potree.pointBudget*0.8 )//先往降到可见数量方向降 (当画面中可见点确实很少时允许降低到low之下)
-
- Potree.settings.maxLRUPoints = Math.min(Potree.lru.numPoints, Potree.settings.maxLRUPoints);//先降到已使用的数量
- Potree.settings.maxLRUPoints *= 0.8
- resolved = true
- }
- }
-
- }else{//恢复部分好难写
- //优先恢复实际使用(可见)内存,然后是缓存
- //额外缓存少的,实际使用内存被压缩的概率也大
- //visiRatio1 == Infinity && (visiRatio1 = 0) //因这里大的才会被改所以改一下
-
- visiRatio1 *= tiles3dMemoryUsage / Potree.settings.tiles3DMaxMemory //用point数量有时候不准,明明内存不够了不可见的tile还存在,所以×memory的占比
- visiRatio2 = Potree.pointBudget == 0 ? 0 : Potree.numVisiblePoints / Potree.pointBudget //使用率越高,说明越需要内存. 因为恢复时先提高使用内存所以改一下
-
- let r = Math.min(1, visiRatio1 , visiRatio2 ) //如果另一个visiRatio 很小,s就可以再小一些,使内存超过一点,然后朝另一方倾斜,另一方去缩减
- let s = 1 - Math.max(0.8, overRatio * r )
-
- //太难判断是哪个更需要内存了,所以两个都涨吧
-
-
- if(visiRatio2 > visiRatio1){
- let s_ = visiRatio2 / (visiRatio1 + visiRatio2) * s + 1
- const addCount = 500000 * s_
- if(Potree.pointBudget < Potree.config.pointDensity.high.pointBudget*0.9){
- Potree.pointBudget += addCount
- }else{
- Potree.settings.maxLRUPoints += addCount
- }
-
- }
-
-
- if(Potree.settings.tiles3DMaxMemory < Potree.config.tiles3DMaxMemory ){
- let s_ = visiRatio1 / (visiRatio1 + visiRatio2) * s + 1
- const addCount = 20 * s_
- Potree.settings.tiles3DMaxMemory += addCount
- Potree.settings.tiles3DMaxMemory = Math.min(Potree.settings.tiles3DMaxMemory, Potree.config.tiles3DMaxMemory)
- }
-
-
- resolved = true
- }
-
- let min = overRatio > 1 ? 1.1 : 1.5, max = 5;
- Potree.settings.maxLRUPoints = THREE.Math.clamp(Potree.settings.maxLRUPoints , Potree.pointBudget * min, Potree.pointBudget * max)
-
- //压缩时先压缩缓存,然后是使用内存; 恢复时相反。
-
- //3dtiles不像点云那样可以在加载时拦截,使不高于tiles3DMaxMemory,只能自动动态调节maxSSE,所以有可能调节完还是降低不了
-
- //一次只更新一点,一点点调节,因为可能不是一个原因造成
-
-
-
-
- let changed
- if(old.pointBudget != Potree.pointBudget || old.tiles3DMaxMemory != Potree.settings.tiles3DMaxMemory || old.maxLRUPoints != Potree.settings.maxLRUPoints ){
-
- if(old.tiles3DMaxMemory != Potree.settings.tiles3DMaxMemory){
- viewer.setAllTilesets(model=>{
- model.runtime.getTileset().nextForceUpdate = true
- model.runtime.getTileset().needRenderNext = true
- })
- }else{
- viewer.dispatchEvent('content_changed')
- }
- changed = true
- }
-
- {
-
- let mSSE = math.linearClamp(Potree.fpsRendered2, [2, 52], [500, 70]) //有效降低卡顿 和贴图变白概率。越卡越提高msse
- let r = tiles3dMemoryUsage / Potree.settings.tiles3DMaxMemory
- viewer.setAllTilesets(model=>{
- let tileset = model.runtime.getTileset()
- tileset.options.initialMaxSSE = mSSE
- let e = tileset.options.maximumScreenSpaceError * THREE.Math.clamp(r, 0.8, 1.2)
- e = THREE.Math.clamp(e, mSSE, mSSE+400) //如果有很卡的模型可能需要1000,但太高了降回来很慢,就假设模型都正常的吧
- tileset.options.maximumScreenSpaceError = e
-
- })
- }
-
- //针对很卡的设备:(卡的也容易崩溃)
- Potree.config.pointDensity.high.pointBudget = math.linearClamp(Potree.fpsRendered2, [2, 50], [1e6, 6e6])
-
-
-
-
- let history = this.lastMemoryState.history || []
- history.push(overRatio)
- this.lastMemoryState = {
- tiles3dMemoryUsage,
- history,
- restMemory
- }
-
-
-
-
- //console.log('cost', performance.now() - start)
- return changed && ((overRatio > 1.1 || overRatio < 0.9) ||
- history.slice(-7).length < 7 || history.slice(-7).some(overRatio=>overRatio > 1.1 || overRatio < 0.9) //后十个都在最大内存范围左右抖动,则不继续更新,直到相机变化
- )
-
-
-
- //难点:要防止抖动,否则3dtiles的sse变大变小,相机静止时还在清晰和模糊间变来变去。好在点云是可以较精细调节,tile是间接控制的
-
- //模型删除后还会占用一定内存,尤其是3dtile几乎降不了,怎么回事?是否删除的模型还要算进来
- },
-
-
-
-
-
-
-
-
- setGroundPlaneImg(src,scale,angle){//设置地面图
-
- this.goundScale = scale || 1, this.goundAngle = angle || 0
- let oldSrc = this.curGroundImgSrc
- this.curGroundImgSrc = src
- const ratio = 0.03
-
-
- if(src){
- if(oldSrc == src && this.groundPlane.material.map.image){ //仅修改大小
- const s = ratio * this.goundScale
- let {width, height} = this.groundPlane.material.map.image
- this.groundPlane.scale.set(width*s, height*s)
- viewer.dispatchEvent('content_changed')
- this.groundPlane.rotation.z = THREE.Math.degToRad(this.goundAngle)
- return
- }
-
- let map = texLoader.load(src,(tex)=>{
- if(this.curGroundImgSrc == src){
- const s = ratio * this.goundScale
- this.groundPlane.scale.set(tex.image.width*s, tex.image.height*s)
- this.groundPlane.rotation.z = THREE.Math.degToRad(this.goundAngle)
- viewer.dispatchEvent('content_changed')
- }
- })
- Potree.Utils.makeTexDontResize(map)
- if(!this.groundPlane){
- this.groundPlane = new THREE.Mesh(new THREE.PlaneBufferGeometry(1,1,1), new THREE.MeshBasicMaterial({
- map,
- side : 2,
-
- }))
- viewer.scene.scene.add(this.groundPlane)
- this.groundPlane.position.z = 0.1
- }else{
- this.groundPlane.material.map = map
- }
-
- Potree.Utils.updateVisible(this.groundPlane,'show',true )
- }else{
- this.groundPlane && Potree.Utils.updateVisible(this.groundPlane,'show',false )
- }
- }
-
-
-
-
-
-
-
- }
-
- /*
- watch:
- performance.memory.usedJSHeapSize / 1e6
- Potree.settings.tiles3DMaxMemory
- viewer.tiles3dMemoryUsage
- Potree.tilesWeight
- Potree.modelWeight
- Potree.modelVisiWeight
- Potree.allWeight
- Potree.lru.numPoints
- Potree.pointBudget
- Potree.numVisiblePoints
- Potree.settings.maxLRUPoints
-
- */
-
- export default MergeEditor
-
-
-
-
- /* class titleLabel extends THREE.Shim.FollowRootObject{
- constructor(o){
- super(o.root)
- this.l
- }
-
-
-
-
- } */
-
- /*
- note:
- 要注意getHoveredElements只在getIntersect时才使interactables包含加载的model, 也就是model上不能有使之成为interactables的事件,否则在鼠标hover到模型上开始转动的一瞬间很卡。
- 控制台断开完全重合的漫游点的方法
- window.pano1 = viewer.modules.PanoEditor.selectedPano //选中第一个点后输入这行,得到第一个漫游点
- window.pano2 = viewer.modules.PanoEditor.selectedPano //选中第二个点后输入这行,得到第二个漫游点
- viewer.modules.PanoEditor.linkChange(window.pano1, window.pano2, 'remove') //断开链接
- 如果直接刷新,内存管理器中的内存会有之前的残留。不知道是不是真实的加入这次的内存了。
- 并且,如果第一次加载的是几乎不占内存的模型,如glb,内存也会一下子涨30,不过等一会儿会降。4M的3dtiles会涨60. 每次加载模型后都会内存突增,但过后会降。 为何obj、glb过后会降很多,而3dtiles降的很少。?
- 国产系统8192贴图直接出错,4096的贴图过多也出错。texImage: Driver ran out of memory during upload.
- */
|