|
@@ -1427,7 +1427,7 @@ export class Viewer extends ViewerBase{
|
|
|
let camera = e.camera || this.scene.getActiveCamera()
|
|
|
|
|
|
Common.intervalTool.isWaiting('testPointcloudsMaxLevel', ()=>{
|
|
|
- if(!camera_changed && count>50 || Potree.settings.displayMode == 'showPanos' )return //只有当camera_changed后才继续循环, 除了最开始几次需要连续加载下
|
|
|
+ if(!camera_changed && count>50 || Potree.settings.displayMode == 'showPanos' || this.pauseTestMaxLevel )return //只有当camera_changed后才继续循环, 除了最开始几次需要连续加载下
|
|
|
camera_changed = false
|
|
|
count ++;
|
|
|
//console.log('testPointcloudsMaxLevel中', camera.type /* count */)
|
|
@@ -1915,7 +1915,7 @@ export class Viewer extends ViewerBase{
|
|
|
};
|
|
|
|
|
|
zoomTo(node, factor, animationDuration = 0){
|
|
|
- let view = this.scene.view;
|
|
|
+ let view = this.mainViewport.view;
|
|
|
|
|
|
let camera = this.scene.cameraP.clone();
|
|
|
camera.rotation.copy(this.scene.cameraP.rotation);
|
|
@@ -3172,9 +3172,12 @@ export class Viewer extends ViewerBase{
|
|
|
return buffer
|
|
|
}
|
|
|
|
|
|
- renderDefault(params_={}){
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ async renderDefault(params_={}){
|
|
|
|
|
|
- if(!this.visible )return
|
|
|
+ if(!this.visible ) return
|
|
|
|
|
|
|
|
|
let pRenderer = this.getPRenderer();
|
|
@@ -3198,34 +3201,36 @@ export class Viewer extends ViewerBase{
|
|
|
|
|
|
///let needsResize = viewports.length > 1 || params_.resize //去掉原因:因为不需要渲染的viewport不在此中所以无法判断几个viewport
|
|
|
|
|
|
-
|
|
|
-
|
|
|
- viewports.forEach(view=>{
|
|
|
+ for(let i=0; i<viewports.length; i++){
|
|
|
+ let viewport = viewports[i]
|
|
|
|
|
|
let params = $.extend({},params_);
|
|
|
- params.viewport = view
|
|
|
+ params.viewport = viewport
|
|
|
//if(!params.target){
|
|
|
- params.camera = params.camera || view.camera;
|
|
|
- params.extraEnableLayers = view.extraEnableLayers
|
|
|
- params.cameraLayers = view.cameraLayers
|
|
|
+ params.camera = params.camera || viewport.camera;
|
|
|
+ params.extraEnableLayers = viewport.extraEnableLayers
|
|
|
+ params.cameraLayers = viewport.cameraLayers
|
|
|
//}
|
|
|
|
|
|
|
|
|
var left,bottom,width,height
|
|
|
{
|
|
|
- left = Math.ceil(renderSize.x * view.left)
|
|
|
- bottom = Math.ceil(renderSize.y * view.bottom)
|
|
|
+ left = Math.ceil(renderSize.x * viewport.left)
|
|
|
+ bottom = Math.ceil(renderSize.y * viewport.bottom)
|
|
|
|
|
|
if(params_.target){//有target时最好viewport是专门建出来的
|
|
|
- width = Math.ceil(renderSize.x * view.width) //target的大小可能和viewport不同,比如截图,这时会更改viewport大小
|
|
|
- height = Math.ceil(renderSize.y * view.height)
|
|
|
+ width = renderSize.x * viewport.width //target的大小可能和viewport不同,比如截图,这时会更改viewport大小
|
|
|
+ height = renderSize.y * viewport.height
|
|
|
}else{
|
|
|
- width = view.resolution.x // 用的是client的width和height
|
|
|
- height = view.resolution.y
|
|
|
- }
|
|
|
- if(width == 0 || height == 0)return
|
|
|
+ width = viewport.resolution.x // 用的是client的width和height
|
|
|
+ height = viewport.resolution.y
|
|
|
+ }
|
|
|
+ if(width == 0 || height == 0)continue;//return
|
|
|
+
|
|
|
+ width = Math.ceil(width) //使用ceil,当原本有小数时,会重叠一个像素,无所谓
|
|
|
+ height = Math.ceil(height)
|
|
|
|
|
|
- let scissorTest = view.width<1 || view.height<1
|
|
|
+ let scissorTest = viewport.width<1 || viewport.height<1
|
|
|
if(params_.target){
|
|
|
params_.target.viewport.set(left, bottom, width, height);
|
|
|
scissorTest && params_.target.scissor.set(left, bottom, width, height);
|
|
@@ -3233,13 +3238,21 @@ export class Viewer extends ViewerBase{
|
|
|
this.renderer.setRenderTarget(params_.target)
|
|
|
}else{
|
|
|
/* if(viewports.length == 1 && left == 0 && bottom == 0){
|
|
|
- left = 1 , width-=1 //这种情况下渲染也会有问题,只有鼠标的地方刷新
|
|
|
+ left = 1 , width-=1 //这种情况下渲染也会有问题,只有鼠标的地方刷新 估计是pick那影响的
|
|
|
} */
|
|
|
- if(scissorTest && left == 0 && bottom == 0){
|
|
|
+
|
|
|
+ /* if(scissorTest && left == 0 && bottom == 0){
|
|
|
left = 1 , width-=1
|
|
|
+ } */
|
|
|
+ if(viewport.forViewOffset){ //分块渲染,渲染时的camera还是原来的,但加载点云时的camera是分块中的
|
|
|
+ viewport.forViewOffset.camera.setViewOffset(renderSize.x, renderSize.y, left, renderSize.y - bottom - height, width, height)
|
|
|
+ this.renderer.setViewport(0,0,renderSize.x, renderSize.y)
|
|
|
+ viewport.resolution.copy(viewport.forViewOffset.originViewport.resolution)
|
|
|
+ viewport.resolution2.copy(viewport.forViewOffset.originViewport.resolution2) //后续渲染都当做原先的viewport
|
|
|
+ }else{
|
|
|
+ this.renderer.setViewport(left, bottom, width, height) //规定视口,影响图形变换(画布的使用范围)
|
|
|
}
|
|
|
-
|
|
|
- this.renderer.setViewport(left, bottom, width, height) //规定视口,影响图形变换(画布的使用范围)
|
|
|
+ scissorTest && console.log('setScissor', left, bottom, width, height)
|
|
|
scissorTest && this.renderer.setScissor( left, bottom, width, height );//规定渲染范围
|
|
|
this.renderer.setScissorTest( scissorTest );//开启WebGL剪裁测试功能,如果不开启,.setScissor方法设置的范围不起作用 | width==1且height==1时开启会只有鼠标的地方刷新,很奇怪
|
|
|
|
|
@@ -3247,25 +3260,25 @@ export class Viewer extends ViewerBase{
|
|
|
}
|
|
|
|
|
|
//if(needsResize){
|
|
|
- this.ifEmitResize( { viewport:view} )
|
|
|
+ this.ifEmitResize( { viewport} )
|
|
|
//}
|
|
|
|
|
|
- viewer.dispatchEvent({type: "render.begin", viewer: viewer, viewport:view, params });
|
|
|
+ viewer.dispatchEvent({type: "render.begin", viewer: viewer, viewport, params });
|
|
|
|
|
|
|
|
|
- view.beforeRender && view.beforeRender()
|
|
|
+ viewport.beforeRender && viewport.beforeRender()
|
|
|
|
|
|
- if(view.render){
|
|
|
- if(!view.render($.extend({}, params, {
|
|
|
+ if(viewport.render){
|
|
|
+ if(!viewport.render($.extend({}, params, {
|
|
|
renderer:this.renderer, clear:this.clear.bind(this), resize:null,
|
|
|
- renderBG:this.renderBG.bind(this), force:true //viewer content_change时map也直接渲染吧 //!view.noPointcloud //如果要渲染点云,必须也一直渲染地图,否则地图会被覆盖(点云目前未能获取是否改变,也可能有其他动态物体,所以还是一直渲染的好)
|
|
|
- })))return
|
|
|
+ renderBG:this.renderBG.bind(this), force:true //viewer content_change时map也直接渲染吧 //!viewport.noPointcloud //如果要渲染点云,必须也一直渲染地图,否则地图会被覆盖(点云目前未能获取是否改变,也可能有其他动态物体,所以还是一直渲染的好)
|
|
|
+ }))) continue//return
|
|
|
}else{
|
|
|
this.clear(params)
|
|
|
pRenderer.clearTargets(params);
|
|
|
|
|
|
|
|
|
- this.renderBG(view)
|
|
|
+ this.renderBG(viewport)
|
|
|
|
|
|
if(Potree.settings.notAdditiveBlending){
|
|
|
params.renderBeforeCloud = true
|
|
@@ -3274,8 +3287,16 @@ export class Viewer extends ViewerBase{
|
|
|
}
|
|
|
|
|
|
|
|
|
- if(!view.noPointcloud ){
|
|
|
- this.updateViewPointcloud(params.camera, view.resolution, true)
|
|
|
+ if(!viewport.noPointcloud ){
|
|
|
+
|
|
|
+ if(params_.needWaitLoadPoint){
|
|
|
+ await this.waitPointLoad(null, params_.maxTimeForPointLoad, viewport ) //resolution得用split前整个的viewport的
|
|
|
+ }else{
|
|
|
+ this.updateViewPointcloud(params.camera, viewport.resolution, true)
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
|
|
|
pRenderer.render(params); //渲染点云 skybox
|
|
|
|
|
@@ -3289,13 +3310,14 @@ export class Viewer extends ViewerBase{
|
|
|
this.renderOverlay(params)
|
|
|
}
|
|
|
|
|
|
- view.afterRender && view.afterRender()
|
|
|
+ viewport.afterRender && viewport.afterRender()
|
|
|
|
|
|
- this.dispatchEvent({type: "render.end", viewer: this, viewport:view });
|
|
|
- view.needRender = false
|
|
|
- view.lastRenderTime = Date.now()
|
|
|
- })
|
|
|
-
|
|
|
+ this.dispatchEvent({type: "render.end", viewer: this, viewport });
|
|
|
+ viewport.needRender = false
|
|
|
+ viewport.lastRenderTime = Date.now()
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
|
|
|
|
|
@@ -3313,17 +3335,17 @@ export class Viewer extends ViewerBase{
|
|
|
viewer.addTimeMark('renderDefault','end')
|
|
|
}
|
|
|
|
|
|
- renderBG(view){
|
|
|
- let background = view.background || viewer.background;
|
|
|
- let backgroundOpacity = view.backgroundOpacity == void 0 ? viewer.backgroundOpacity : view.backgroundOpacity//如果想完全透明,只需要backgroundOpacity为0
|
|
|
+ renderBG(viewport){
|
|
|
+ let background = viewport.background || viewer.background;
|
|
|
+ let backgroundOpacity = viewport.backgroundOpacity == void 0 ? viewer.backgroundOpacity : viewport.backgroundOpacity//如果想完全透明,只需要backgroundOpacity为0
|
|
|
if(backgroundOpacity != 0){//绘制背景
|
|
|
if(background === "skybox"){
|
|
|
//限制相机到原点的距离。
|
|
|
- let skyCamera = view.camera.type == "OrthographicCamera" ? viewer.skybox.cameraOrtho : viewer.skybox.camera
|
|
|
+ let skyCamera = viewport.camera.type == "OrthographicCamera" ? viewer.skybox.cameraOrtho : viewer.skybox.camera
|
|
|
let safeRatio = 0.02;
|
|
|
let safeWidth = Potree.config.skyboxBgWidth * safeRatio / 2; //相机只能在这个范围内移动
|
|
|
- if(!view.skyboxFixPos){ //允许不在全景图中心,允许位移造成一定程度畸变
|
|
|
- let dir = new THREE.Vector3().subVectors(view.camera.position, viewer.bound.center);
|
|
|
+ if(!viewport.skyboxFixPos){ //允许不在全景图中心,允许位移造成一定程度畸变
|
|
|
+ let dir = new THREE.Vector3().subVectors(viewport.camera.position, viewer.bound.center);
|
|
|
let length = dir.length()
|
|
|
const moveMax = 100;
|
|
|
let aimRadius = easing.easeOutQuart(Math.min(length, moveMax) , 0, safeWidth, moveMax) //(x, startY, wholeY, maxX) 当自变量为0-moveMax时,相机位移量为0-safeWidth
|
|
@@ -3333,29 +3355,29 @@ export class Viewer extends ViewerBase{
|
|
|
skyCamera.position.set(0,0,0)
|
|
|
}
|
|
|
|
|
|
- skyCamera.rotation.copy(view.camera.rotation);
|
|
|
- skyCamera.aspect = view.camera.aspect;
|
|
|
+ skyCamera.rotation.copy(viewport.camera.rotation);
|
|
|
+ skyCamera.aspect = viewport.camera.aspect;
|
|
|
|
|
|
- if(view.camera.type == "OrthographicCamera"){ //调节zoom
|
|
|
- skyCamera.left = view.camera.left; skyCamera.right = view.camera.right; skyCamera.top = view.camera.top; skyCamera.bottom = view.camera.bottom
|
|
|
+ if(viewport.camera.type == "OrthographicCamera"){ //调节zoom
|
|
|
+ skyCamera.left = viewport.camera.left; skyCamera.right = viewport.camera.right; skyCamera.top = viewport.camera.top; skyCamera.bottom = viewport.camera.bottom
|
|
|
|
|
|
let a = Potree.config.skyboxBgWidth / 2 - safeWidth
|
|
|
- let minY = Math.max(skyCamera.right / a, skyCamera.top / a, view.skyboxMinZoom||0); //能够使skybox铺满画布的最小zoom. 提示:越远zoom越小
|
|
|
+ let minY = Math.max(skyCamera.right / a, skyCamera.top / a, viewport.skyboxMinZoom||0); //能够使skybox铺满画布的最小zoom. 提示:越远zoom越小
|
|
|
let maxY = Math.max(20, minY) ;//自定义一个 不会超过的最大实际zoom
|
|
|
- //view.camera.zoom自变量的变化范围:
|
|
|
+ //viewport.camera.zoom自变量的变化范围:
|
|
|
let minX = 1
|
|
|
let maxX = 80
|
|
|
- let x = THREE.Math.clamp(view.camera.zoom - minX, minX, maxX)
|
|
|
+ let x = THREE.Math.clamp(viewport.camera.zoom - minX, minX, maxX)
|
|
|
skyCamera.zoom = easing.easeOutCubic(x-minX, minY, maxY-minY, maxX-minX) //自变量范围从0开始,所以减去minX
|
|
|
|
|
|
//pos的范围先不管了 其实aimRadius是有误的,但效果还行
|
|
|
}else{
|
|
|
- skyCamera.fov = view.camera.fov;
|
|
|
+ skyCamera.fov = viewport.camera.fov;
|
|
|
skyCamera.zoom = 1
|
|
|
}
|
|
|
|
|
|
|
|
|
- view.skyboxRenderFun && view.skyboxRenderFun()
|
|
|
+ viewport.skyboxRenderFun && viewport.skyboxRenderFun()
|
|
|
|
|
|
skyCamera.updateProjectionMatrix();
|
|
|
skyCamera.updateMatrixWorld()
|
|
@@ -3364,8 +3386,8 @@ export class Viewer extends ViewerBase{
|
|
|
viewer.scene.cameraBG.layers.set(Potree.config.renderLayers.bg);
|
|
|
viewer.renderer.render(viewer.scene.scene, viewer.scene.cameraBG);
|
|
|
}else if(background === 'overlayColor'){//在不clear的前提下加一层背景色
|
|
|
- viewer.scene.bg2.material.color.copy(view.backgroundColor)
|
|
|
- viewer.scene.bg2.material.opacity = view.backgroundOpacity
|
|
|
+ viewer.scene.bg2.material.color.copy(viewport.backgroundColor)
|
|
|
+ viewer.scene.bg2.material.opacity = viewport.backgroundOpacity
|
|
|
viewer.scene.cameraBG.layers.set(Potree.config.renderLayers.bg2);
|
|
|
viewer.renderer.render(viewer.scene.scene, viewer.scene.cameraBG);
|
|
|
|
|
@@ -3512,11 +3534,12 @@ export class Viewer extends ViewerBase{
|
|
|
/* 大规模WebGL应用引发浏览器崩溃的几种情况及解决办法
|
|
|
https://blog.csdn.net/weixin_30378311/article/details/94846947 */
|
|
|
|
|
|
- render(params={}){//add params
|
|
|
+ async render(params={}){//add params
|
|
|
viewer.addTimeMark('render','start')
|
|
|
const vrActive = this.renderer.xr.isPresenting;
|
|
|
let SiteModel = viewer.modules.SiteModel
|
|
|
|
|
|
+ if(this.screenshoting && !params.screenshot)return //正在截图
|
|
|
|
|
|
let s = SiteModel.editing && SiteModel.selected && (SiteModel.selected.buildType == 'room' || SiteModel.selected.buildType == 'floor') //空间模型的房间选中材质是需要depth的,这时候需要绘制两次点云
|
|
|
|
|
@@ -3539,7 +3562,7 @@ export class Viewer extends ViewerBase{
|
|
|
let scenes = this.inputHandler.interactiveScenes.concat(this.scene.scene).concat(viewer.scene.scenePointCloud)
|
|
|
this.composer.render(scenes, null, this.viewports, this.renderDefault.bind(this));
|
|
|
}else{
|
|
|
- this.renderDefault(params);
|
|
|
+ await this.renderDefault(params);
|
|
|
}
|
|
|
}
|
|
|
if(!specialRender) this.needRender = false
|
|
@@ -3560,25 +3583,28 @@ export class Viewer extends ViewerBase{
|
|
|
let useMap = info.map || info.type == 'measure' || info.type.includes('prism2d')
|
|
|
|
|
|
|
|
|
- if(Potree.settings.displayMode == 'showPanos' && viewer.scene.view.isFlying('pos')){//如果在飞,飞完再截图
|
|
|
+
|
|
|
+ if(Potree.settings.displayMode == 'showPanos' && viewer.mainViewport.view.isFlying('pos')){//如果在飞,飞完再截图
|
|
|
info.getImageDeferred = getImageDeferred , info.finishDeferred = finishDeferred
|
|
|
let f = ()=>{
|
|
|
this.startScreenshot(info, width, height, compressRatio)
|
|
|
}
|
|
|
- viewer.scene.view.addEventListener('flyingDone', f, {once:true})
|
|
|
+ viewer.mainViewport.view.addEventListener('flyingDone', f, {once:true})
|
|
|
|
|
|
return {getImagePromise:getImageDeferred.promise(), finishPromise:finishDeferred.promise()}
|
|
|
}
|
|
|
|
|
|
- var sid = Date.now()
|
|
|
+ var startTime = Date.now()
|
|
|
//抗锯齿待加 1 post处理 2截图大张再抗锯齿缩小
|
|
|
+ this.pauseTestMaxLevel = true
|
|
|
+
|
|
|
|
|
|
- console.log('startScreenshot: '+sid)
|
|
|
+ console.log('startScreenshot: '+startTime)
|
|
|
|
|
|
let updateCamera = ()=>{
|
|
|
viewports.forEach(e=>{
|
|
|
e.view.applyToCamera(e.camera) //因为fly时只更新了view所以要强制更新下camera
|
|
|
-
|
|
|
+
|
|
|
this.dispatchEvent({ //update map and sprite, mapChanged
|
|
|
type: "camera_changed",
|
|
|
camera: e.camera,
|
|
@@ -3588,32 +3614,74 @@ export class Viewer extends ViewerBase{
|
|
|
})
|
|
|
}
|
|
|
|
|
|
- let screenshot = ()=>{
|
|
|
+ let screenshot = async ()=>{
|
|
|
let pose
|
|
|
- //console.log('screenshot',sid, Date.now())
|
|
|
+
|
|
|
useMap && (viewer.mapViewer.needRender = true)
|
|
|
|
|
|
- this.needRender = true
|
|
|
|
|
|
- if(info.useRenderTarget){
|
|
|
- //离屏渲染 有抗锯齿问题、在手机上速度慢 主视图一样会变内容,还是不用这个了
|
|
|
- var { dataUrl } = viewerMaster.makeScreenshot( new THREE.Vector2(width,height), null, compressRatio );
|
|
|
-
|
|
|
- }else{
|
|
|
-
|
|
|
- //直接渲染 会改变canvas大小
|
|
|
- let canvas = viewerMaster.renderer.domElement
|
|
|
- //canvas.width = width, canvas.height = height //不需要改canvas大小, 只需要 this.renderer.setSize(width, height ); 前面updateScreenSize已经执行
|
|
|
- viewerMaster.render({ screenshot : true, width , height, resize :true }); //需要resize
|
|
|
-
|
|
|
- /* if(info.type.includes('prism2d')){//o.map要为true
|
|
|
- viewer.dispatchEvent({type:'resize', viewport:viewer.mapViewer.viewports[0]}) //借用viewer通知lineMaterial resize
|
|
|
- viewerMaster.renderOverlay()
|
|
|
- } */
|
|
|
+
|
|
|
+ info.beforeScreenshot && info.beforeScreenshot()
|
|
|
+
|
|
|
+ let render = async ()=>{
|
|
|
+
|
|
|
+ this.needRender = true
|
|
|
+ viewports.forEach(e=>e.active = true)
|
|
|
+
|
|
|
+ if(info.useRenderTarget){
|
|
|
+ //离屏渲染 有抗锯齿问题、在手机上速度慢 主视图一样会变内容,还是不用这个了
|
|
|
+ var { dataUrl } = viewerMaster.makeScreenshot( new THREE.Vector2(width,height), null, compressRatio );
|
|
|
+
|
|
|
+ }else{
|
|
|
+
|
|
|
+ //直接渲染 会改变canvas大小
|
|
|
+ let canvas = viewerMaster.renderer.domElement
|
|
|
+ //canvas.width = width, canvas.height = height //不需要改canvas大小, 只需要 this.renderer.setSize(width, height ); 前面updateScreenSize已经执行
|
|
|
+ await viewerMaster.render({ screenshot : true, width , height, resize :true, needWaitLoadPoint:!!info.splitRenderInfo, maxTimeForPointLoad:info.maxTimeForPointLoad }); //需要resize
|
|
|
+
|
|
|
+ /* if(info.type.includes('prism2d')){//o.map要为true
|
|
|
+ viewer.dispatchEvent({type:'resize', viewport:viewer.mapViewer.viewports[0]}) //借用viewer通知lineMaterial resize
|
|
|
+ viewerMaster.renderOverlay()
|
|
|
+ } */
|
|
|
+ var dataUrl = canvas.toDataURL('image/png',compressRatio)
|
|
|
+ }
|
|
|
+ return dataUrl
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ let dataUrl
|
|
|
+ if(info.splitRenderInfo){//为了防崩溃,分区域批次渲染
|
|
|
+ let {wc , hc} = info.splitRenderInfo
|
|
|
+ let camera = viewer.mainViewport.camera
|
|
|
+ let dataUrls = []
|
|
|
+ let width_ = Math.ceil(1/wc * width) , height_ = Math.ceil(1/hc * height) //可能加起来比原图大,没事到时候边界会重合
|
|
|
+ viewer.updateScreenSize({forceUpdateSize:true, width:width_, height:height_, forTarget:info.useRenderTarget}) //更新viewports相机透视 使focusOnObject在此窗口大小下
|
|
|
+ for(let i=0;i<wc;i++){
|
|
|
+ let col = []
|
|
|
+ for(let j=0;j<hc;j++){
|
|
|
+ let left = Math.ceil((-wc/2+0.5+i)*width_), top = Math.ceil((-hc/2+0.5+j)*height_)
|
|
|
+ camera.setViewOffset(width_, height_, left, top , width_, height_) //顺序从上到下从左到右
|
|
|
+ let dataUrl = await render()
|
|
|
+ //Common.downloadFile(dataUrl, 'screenshot'+ i+':'+j+'.png')
|
|
|
+ col.push({dataUrl, width:width_, height:height_})
|
|
|
+ }
|
|
|
+ dataUrls.push(col)
|
|
|
+ }
|
|
|
+ camera.clearViewOffset()
|
|
|
|
|
|
- var dataUrl = canvas.toDataURL('image/png',compressRatio)
|
|
|
+ dataUrl = await Utils.combineImgs(dataUrls, compressRatio, width, height)
|
|
|
+
|
|
|
+ }else{
|
|
|
+ dataUrl = await render()
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ if(info.splitRenderInfo){
|
|
|
+ viewer.viewports = [viewer.mainViewport]
|
|
|
+ }
|
|
|
|
|
|
if(!Potree.settings.isOfficial){
|
|
|
Common.downloadFile(dataUrl, 'screenshot.png')
|
|
@@ -3629,6 +3697,9 @@ export class Viewer extends ViewerBase{
|
|
|
viewport.width = old.width; viewport.height = old.height
|
|
|
viewport.view.copy(old.view)
|
|
|
//viewport.view.applyToCamera(viewport.camera);
|
|
|
+ if(viewport.camera.isOrthographicCamera){
|
|
|
+ viewport.camera.zoom = viewport.view.zoom
|
|
|
+ }
|
|
|
})
|
|
|
|
|
|
viewerMaster.updateScreenSize({forceUpdateSize:true})//更新像素
|
|
@@ -3642,7 +3713,7 @@ export class Viewer extends ViewerBase{
|
|
|
})
|
|
|
}) */
|
|
|
updateCamera()
|
|
|
-
|
|
|
+
|
|
|
finishDeferred.resolve({dataUrl, pose})
|
|
|
|
|
|
|
|
@@ -3659,12 +3730,14 @@ export class Viewer extends ViewerBase{
|
|
|
},500) //延迟:避免连续多次截图时释放点云
|
|
|
this.screenshoting = false
|
|
|
|
|
|
- console.log('screenshot done: '+sid)
|
|
|
+ console.log('screenshot done: ' + startTime, 'costTime', (Date.now() - startTime) + 'ms')
|
|
|
}
|
|
|
|
|
|
{//恢复:
|
|
|
|
|
|
this.backgroundOpacity = oldStates.bgOpacity;
|
|
|
+ this.pauseTestMaxLevel = false
|
|
|
+
|
|
|
|
|
|
if(info.type == 'measure' || info.type.includes('prism2d')){
|
|
|
this.modules.SiteModel.pauseUpdateEntity = false
|
|
@@ -3680,7 +3753,7 @@ export class Viewer extends ViewerBase{
|
|
|
prism.changeStyleForScreenshot(false)
|
|
|
})
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
|
|
|
this.images360.panos.forEach(pano=>{
|
|
|
Potree.Utils.updateVisible(pano, 'screenshot', true)
|
|
@@ -3703,8 +3776,6 @@ export class Viewer extends ViewerBase{
|
|
|
|
|
|
|
|
|
|
|
|
- mapViewport.camera.zoom = oldStates.mapZoom
|
|
|
- mapViewport.camera.updateProjectionMatrix()
|
|
|
|
|
|
|
|
|
Potree.Utils.updateVisible(viewer.mapViewer.mapLayer.sceneGroup, 'screenshot-prism', true)
|
|
@@ -3749,19 +3820,22 @@ export class Viewer extends ViewerBase{
|
|
|
}
|
|
|
if(!info.type.includes('prism2d')){
|
|
|
viewports.push(mainViewport)
|
|
|
+ mainViewport.camera.isOrthographicCamera && (mainViewport.view.zoom = mainViewport.camera.zoom)
|
|
|
oldStates.viewports.push(mainViewport.clone())
|
|
|
}
|
|
|
if(useMap){
|
|
|
mapViewport = this.mapViewer.viewports[0]
|
|
|
+ mapViewport.view.zoom = mapViewport.camera.zoom
|
|
|
viewports.push(mapViewport)
|
|
|
oldStates.viewports.push(mapViewport.clone())
|
|
|
oldStates.attachedToViewer = this.mapViewer.attachedToViewer
|
|
|
- oldStates.mapZoom = mapViewport.camera.zoom
|
|
|
+
|
|
|
+
|
|
|
|
|
|
Potree.Utils.updateVisible(this.mapViewer.cursor, 'screenshot', false)//令mapCursor不可见
|
|
|
}
|
|
|
|
|
|
-
|
|
|
+ viewports.forEach(e=>e.active = false) //暂停渲染
|
|
|
|
|
|
if(info.hideMarkers){
|
|
|
this.images360.panos.forEach(pano=>{//令漫游点不可见
|
|
@@ -3776,54 +3850,11 @@ export class Viewer extends ViewerBase{
|
|
|
this.backgroundOpacity = info.bgOpacity
|
|
|
}
|
|
|
|
|
|
- Potree.settings.pointDensity = 'screenshot'
|
|
|
+ Potree.settings.pointDensity = info.pointDensity || 'screenshot'
|
|
|
+
|
|
|
|
|
|
|
|
|
|
|
|
- let waitPointLoad = (done)=>{
|
|
|
- let finish
|
|
|
- done = done || screenshot
|
|
|
- let dealDone = ()=>{
|
|
|
- //viewer.removeEventListener('overPointBudget',decreaseLevel)
|
|
|
- finish || done()
|
|
|
- finish = true
|
|
|
- }
|
|
|
- let decreaseLevel = ()=>{ //降点云level
|
|
|
- let levels = viewer.scene.pointclouds[0].visibleNodes.map(e=>e.getLevel())
|
|
|
- //console.log(levels)
|
|
|
- let actMaxLevel = Math.max.apply(null, levels) //实际加载到的最高的node level
|
|
|
- //console.warn('decreaseLevel, 新maxLevel', actMaxLevel - 1, '原maxlevel', viewer.scene.pointclouds[0].maxLevel, 'numVisiblePoints', Potree.numVisiblePoints)
|
|
|
-
|
|
|
- }
|
|
|
- if(Potree.settings.displayMode == 'showPointCloud'){
|
|
|
- viewer.updateScreenSize({forceUpdateSize:true, width, height, forTarget:info.useRenderTarget})//需要先setSize才能加载范围内的点云
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- let maxTime = document.hidden ? 6000 : 1000 //离开页面后会变成1秒1帧
|
|
|
-
|
|
|
- setTimeout(()=>{
|
|
|
- if(Potree.pointsLoading && Potree.settings.displayMode == 'showPointCloud'){//如果还在加载
|
|
|
-
|
|
|
- viewer.addEventListener('pointsLoaded',()=>{ //点云加载完时(不一定准确)
|
|
|
- if(!finish)console.warn('加载完毕', ' numVisiblePoints', Potree.numVisiblePoints)
|
|
|
- dealDone()
|
|
|
- },{once:true})
|
|
|
-
|
|
|
- let overTime = ()=>{//超时不候(其实之后等待地图还会再加载几秒)
|
|
|
- if(document.hidden){
|
|
|
- return setTimeout(overTime, maxTime)
|
|
|
- }
|
|
|
- if(!finish)console.warn('超时, numVisiblePoints', Potree.numVisiblePoints)
|
|
|
- dealDone()
|
|
|
- }
|
|
|
-
|
|
|
- setTimeout(overTime, maxTime)
|
|
|
- }else{
|
|
|
- dealDone()
|
|
|
- }
|
|
|
- },200)//先加载一段时间
|
|
|
- }
|
|
|
|
|
|
|
|
|
let focusDatasets = (measurements)=>{
|
|
@@ -3860,15 +3891,15 @@ export class Viewer extends ViewerBase{
|
|
|
console.log('waitMap: '+sid, Date.now(), this.mapViewer.mapLayer.loadingInProgress )
|
|
|
this.mapViewer.waitLoadDone(screenshot.bind(this))//等待地图所有加载完
|
|
|
}
|
|
|
- waitPointLoad(waitMap)
|
|
|
+ this.waitPointLoad(waitMap,info.maxTimeForPointLoad)
|
|
|
}else{
|
|
|
- waitPointLoad()
|
|
|
+ this.waitPointLoad(screenshot,info.maxTimeForPointLoad)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
let {promise} = this.focusOnObject(info.measurement, 'measure', 0, {
|
|
|
basePanoSize:1024, gotoBestView:true,
|
|
|
- minMapWidth: this.mapViewer.mapLayer.maps.find(e=>e.name == 'map').disabled ? 10 : 20 //有地图的话为了显示出名字需要更大范围
|
|
|
+ minMapWidth: THREE.Math.clamp(Math.min(viewer.bound.boundSize.x, viewer.bound.boundSize.y) / (this.mapViewer.mapLayer.maps.find(e=>e.name == 'map').disabled ? 6 : 3), 2, 25) //有地图的话为了显示出名字需要更大范围
|
|
|
})//注意:不同角度截图 得到三维的会不一样,因为focusOnObject是根据方向的
|
|
|
promise.done(()=>{
|
|
|
//console.log('promise.done')
|
|
@@ -3941,9 +3972,28 @@ export class Viewer extends ViewerBase{
|
|
|
}
|
|
|
})
|
|
|
|
|
|
- }else{
|
|
|
+ }else{//default
|
|
|
+
|
|
|
+ let done = ()=>{
|
|
|
+ updateCamera()
|
|
|
+ if(info.splitRenderInfo){
|
|
|
+ screenshot()
|
|
|
+ }else{
|
|
|
+ this.waitPointLoad(screenshot, info.maxTimeForPointLoad)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(info.focusObjectInfo){
|
|
|
+ viewer.updateScreenSize({forceUpdateSize:true, width, height, forTarget:info.useRenderTarget}) //更新viewports相机透视 使focusOnObject在此窗口大小下
|
|
|
|
|
|
- waitPointLoad()
|
|
|
+ let {promise} = this.focusOnObject( ...info.focusObjectInfo)
|
|
|
+ promise.done(()=>{
|
|
|
+ done()
|
|
|
+ })
|
|
|
+ }else{
|
|
|
+ done()
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -3956,6 +4006,82 @@ export class Viewer extends ViewerBase{
|
|
|
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ async waitPointLoad(done, maxTimeForPointLoad, viewport = viewer.mainViewport, resolution ){
|
|
|
+
|
|
|
+ return new Promise((resolve,reject)=>{
|
|
|
+ let finish
|
|
|
+ let dealDone = ()=>{
|
|
|
+ viewer.removeEventListener('update',update)
|
|
|
+ viewer.removeEventListener('overPointBudget',decreaseLevel)
|
|
|
+ finish || done && done()
|
|
|
+ finish = true
|
|
|
+ resolve()
|
|
|
+ }
|
|
|
+ let decreaseLevel = (e)=>{ //降点云level 但基本降完也不会再加载低等级的点云了,所以是否直接不降?即使质量不平均
|
|
|
+ if(e.restQueueSize < 10)return ;//差不多完成了
|
|
|
+ let pointclouds = viewer.scene.pointclouds.filter(e=>e.visibleNodes.length)
|
|
|
+ console.log('准备decreaseLevel, numVisiblePoints', e.numVisiblePoints, '最小numVisiblePoints占比', 1/pointclouds.length )
|
|
|
+
|
|
|
+ pointclouds.forEach(pointcloud=>{
|
|
|
+ let percent = pointcloud.numVisiblePoints / e.numVisiblePoints
|
|
|
+ //console.log('numVisiblePoints占总比', pointcloud.dataset_id, percent )
|
|
|
+ if(percent < 1/pointclouds.length)return
|
|
|
+
|
|
|
+ let old = pointcloud.maxLevel
|
|
|
+ let levels = pointcloud.visibleNodes.map(e=>e.getLevel())
|
|
|
+ let actMaxLevel = Math.max.apply(null, levels) //实际加载到的最高的node level
|
|
|
+ pointcloud.maxLevel = actMaxLevel - 1
|
|
|
+ console.warn(pointcloud.dataset_id,'decreaseLevel,新maxLevel', actMaxLevel - 1, '原maxlevel', old )
|
|
|
+
|
|
|
+ })
|
|
|
+ }
|
|
|
+ /* if(Potree.settings.displayMode == 'showPointCloud'){
|
|
|
+ viewer.updateScreenSize({forceUpdateSize:true, width, height, forTarget:info.useRenderTarget})//需要先setSize才能加载范围内的点云
|
|
|
+ } */
|
|
|
+ //updateCamera()
|
|
|
+ //viewer.addEventListener('overPointBudget',decreaseLevel)
|
|
|
+
|
|
|
+ let update = ()=>{ //前提:已经禁止渲染,仅加载点云
|
|
|
+ let camera = viewport.forViewOffset ? viewport.forViewOffset.camera : viewport.camera
|
|
|
+ Potree.updatePointClouds(viewer.scene.pointclouds, camera , resolution || viewport.resolution );
|
|
|
+ }
|
|
|
+ viewer.addEventListener('update',update)
|
|
|
+ update()
|
|
|
+
|
|
|
+ let maxTime = maxTimeForPointLoad || 2000
|
|
|
+ document.hidden && (maxTime *= 6) //离开页面后会变成1秒1帧
|
|
|
+
|
|
|
+ setTimeout(()=>{
|
|
|
+ if(Potree.pointsLoading && Potree.settings.displayMode == 'showPointCloud'){//如果还在加载
|
|
|
+
|
|
|
+ viewer.addEventListener('pointsLoaded',()=>{ //点云加载完时(不一定准确)
|
|
|
+ if(!finish)console.log('加载完毕', ' numVisiblePoints', Potree.numVisiblePoints)
|
|
|
+ dealDone()
|
|
|
+ },{once:true})
|
|
|
+
|
|
|
+ let overTime = ()=>{//超时不候(其实之后等待地图还会再加载几秒)
|
|
|
+ if(document.hidden){
|
|
|
+ return setTimeout(overTime, maxTime)
|
|
|
+ }
|
|
|
+ if(!finish)console.warn('超时, numVisiblePoints', Potree.numVisiblePoints)
|
|
|
+ dealDone()
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ setTimeout(overTime, maxTime)
|
|
|
+ }else{
|
|
|
+ console.log('已经加载完,无需再加载点云 numVisiblePoints', Potree.numVisiblePoints)
|
|
|
+ dealDone()
|
|
|
+ }
|
|
|
+ },200)//先加载一段时间
|
|
|
+
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
|
|
|
focusOnObject(object, type, duration, o={} ) {
|
|
|
//飞向热点、测量线等 。
|
|
@@ -3973,7 +4099,7 @@ export class Viewer extends ViewerBase{
|
|
|
|
|
|
|
|
|
let moveMap = (done)=>{
|
|
|
- if(this.mapViewer){
|
|
|
+ if(this.mapViewer && !o.dontMoveMap){
|
|
|
//console.log('mapFocusOn: '+target.toArray())
|
|
|
const minMapWidth = o.minMapWidth || 2 //截图的时候要显示的地图范围较大,为了显示出地区名字
|
|
|
const minBound = new THREE.Vector2(minMapWidth,minMapWidth)//针对垂直线,在地图上只有一个点
|
|
@@ -4034,16 +4160,19 @@ export class Viewer extends ViewerBase{
|
|
|
var p = e.clone().applyMatrix4(inv);
|
|
|
bound.expandByPoint(p)
|
|
|
})
|
|
|
- scale = 1.3;
|
|
|
+ scale = 1.2;
|
|
|
}else{
|
|
|
bound = boundingBox.applyMatrix4(inv);
|
|
|
- scale = 0.9;
|
|
|
+ scale = 1 //0.9;
|
|
|
}
|
|
|
boundSize = bound.getSize(new THREE.Vector3)
|
|
|
|
|
|
+ if(o.boundScale){
|
|
|
+ scale = o.boundScale
|
|
|
+ }
|
|
|
|
|
|
{
|
|
|
-
|
|
|
+
|
|
|
boundSize.x *= scale //稍微放大一些,不然会靠到屏幕边缘
|
|
|
boundSize.y *= scale
|
|
|
let min = 0.0001
|
|
@@ -4137,7 +4266,7 @@ export class Viewer extends ViewerBase{
|
|
|
if(object.points.length>2){
|
|
|
let facePlane = object.getFacePlane(target)
|
|
|
let normal = facePlane.normal.clone()
|
|
|
- let angle = this.scene.view.direction.angleTo(normal)
|
|
|
+ let angle = this.mainViewport.view.direction.angleTo(normal)
|
|
|
let minDiff = THREE.Math.degToRad(60)
|
|
|
//console.log('angle',angle)
|
|
|
if(angle>minDiff && angle<Math.PI-minDiff){//当几乎正对时就不执行
|
|
@@ -4150,7 +4279,7 @@ export class Viewer extends ViewerBase{
|
|
|
}
|
|
|
}else if(object.points.length == 2){ //线段
|
|
|
let lineDir = new THREE.Vector3().subVectors(object.points[0],object.points[1]).normalize()
|
|
|
- let angle = this.scene.view.direction.angleTo(lineDir)
|
|
|
+ let angle = this.mainViewport.view.direction.angleTo(lineDir)
|
|
|
let maxDiff = Math.PI*0.25// 45度
|
|
|
if(angle<maxDiff || angle>Math.PI-maxDiff){//当几乎正对时就不执行
|
|
|
if(angle>Math.PI/2){ //令dir和lineDir成钝角
|
|
@@ -4342,7 +4471,7 @@ export class Viewer extends ViewerBase{
|
|
|
}else if(Potree.settings.displayMode == 'showPanos'){
|
|
|
let pano = viewer.images360.fitPanoTowardPoint({
|
|
|
point : target,
|
|
|
- dir : this.scene.view.direction, //尽量不改相机方向,避免镜头晃动
|
|
|
+ dir : this.mainViewport.view.direction, //尽量不改相机方向,避免镜头晃动
|
|
|
checkIntersect: o.checkIntersect, sameFloor:o.sameFloor,
|
|
|
bestDistance, maxDis: o.maxDis //越近越好,但不要太近,bestDistance左右差不多
|
|
|
})
|
|
@@ -4391,7 +4520,7 @@ export class Viewer extends ViewerBase{
|
|
|
|
|
|
|
|
|
if(o.startCamera && o.endCamera){
|
|
|
- viewer.scene.view.tranCamera(this.mainViewport, { endPosition:position, target ,
|
|
|
+ viewer.mainViewport.view.tranCamera(this.mainViewport, { endPosition:position, target ,
|
|
|
boundSize,
|
|
|
callback:()=>{
|
|
|
//console.log('focusOnObjectSuccess: '+object.name, type)
|
|
@@ -4400,7 +4529,7 @@ export class Viewer extends ViewerBase{
|
|
|
endYaw:o.endYaw, endPitch:o.endPitch
|
|
|
}, duration)
|
|
|
}else if(camera.type == "OrthographicCamera"){
|
|
|
- viewer.scene.view.moveOrthoCamera(this.mainViewport, { endPosition:position, target ,
|
|
|
+ viewer.mainViewport.view.moveOrthoCamera(this.mainViewport, { endPosition:position, target ,
|
|
|
boundSize,
|
|
|
endYaw:o.endYaw, endPitch:o.endPitch,
|
|
|
callback:()=>{
|
|
@@ -4409,7 +4538,7 @@ export class Viewer extends ViewerBase{
|
|
|
},
|
|
|
}, duration)
|
|
|
}else{
|
|
|
- viewer.scene.view.setView({position, target, duration,
|
|
|
+ viewer.mainViewport.view.setView({position, target, duration,
|
|
|
endYaw:o.endYaw, endPitch:o.endPitch,
|
|
|
callback:()=>{
|
|
|
//console.log('focusOnObjectSuccess: '+object.name, type)
|
|
@@ -4500,7 +4629,7 @@ export class Viewer extends ViewerBase{
|
|
|
}else{
|
|
|
if(math.closeTo(position, this.images360.position)) return 'posNoChange'
|
|
|
|
|
|
- viewer.scene.view.setView({position, target, duration })
|
|
|
+ viewer.mainViewport.view.setView({position, target, duration })
|
|
|
}
|
|
|
o.dontMoveMap || viewer.mapViewer.fitToPointcloud(pointcloud, duration)
|
|
|
}
|
|
@@ -4878,7 +5007,7 @@ export class Viewer extends ViewerBase{
|
|
|
if(o.pano != void 0){//pano 权重高于 position
|
|
|
this.images360.flyToPano(o)
|
|
|
}else{
|
|
|
- this.scene.view.setView($.extend({},o, {callback}))
|
|
|
+ this.mainViewport.view.setView($.extend({},o, {callback}))
|
|
|
}
|
|
|
}
|
|
|
|