|
@@ -10,6 +10,7 @@ import {ClippingTool} from "../utils/ClippingTool.js";
|
|
|
import {TransformationTool} from "../utils/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 {Features} from "../Features.js";
|
|
@@ -29,35 +30,54 @@ import {FirstPersonControls} from "../navigation/FirstPersonControls.js";
|
|
|
import {EarthControls} from "../navigation/EarthControls.js";
|
|
|
import {DeviceOrientationControls} from "../navigation/DeviceOrientationControls.js";
|
|
|
import {VRControls} from "../navigation/VRControls.js";
|
|
|
-import { EventDispatcher } from "../EventDispatcher.js";
|
|
|
+
|
|
|
import { ClassificationScheme } from "../materials/ClassificationScheme.js";
|
|
|
import { VRButton } from '../../libs/three.js/extra/VRButton.js';
|
|
|
-import {transitions, esing, lerp} from '../utils/transitions.js'
|
|
|
+import {transitions, easing, lerp} from '../utils/transitions.js'
|
|
|
import JSON5 from "../../libs/json5-2.1.3/json5.mjs";
|
|
|
import CursorDeal from '../utils/CursorDeal'
|
|
|
+import Common from '../utils/Common'
|
|
|
|
|
|
+import {Clip} from '../modules/clipModel/Clip'
|
|
|
+import {Alignment} from "../modules/datasetAlignment/Alignment.js";
|
|
|
|
|
|
+import Magnifier from "../utils/Magnifier.js";
|
|
|
+import Reticule from "../navigation/Reticule.js";
|
|
|
+import Viewport from "./Viewport.js"
|
|
|
+import {ViewerBase} from "./viewerBase.js"
|
|
|
+
|
|
|
+import SplitScreen from '../utils/SplitScreen'
|
|
|
|
|
|
|
|
|
-var W, H, pixelRatio;
|
|
|
-
|
|
|
|
|
|
|
|
|
-export class Viewer extends EventDispatcher{
|
|
|
+export class Viewer extends ViewerBase{
|
|
|
|
|
|
constructor(domElement, args = {}){
|
|
|
- super();
|
|
|
+ super(domElement,args);
|
|
|
+ window.viewer = this
|
|
|
+ this.modules = { //add
|
|
|
+ Clip : Clip,
|
|
|
+ Alignment : Alignment
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ //add --------
|
|
|
this.navigateMode = 'free' // 'panorama'; 'free'自由模式是只显示点云或者未进入到漫游点,
|
|
|
this.isEdit = true
|
|
|
+ CursorDeal.attachToViewer(this)//ADD
|
|
|
+
|
|
|
+ //-------------
|
|
|
+
|
|
|
+
|
|
|
|
|
|
- this.renderArea = domElement;
|
|
|
this.guiLoaded = false;
|
|
|
this.guiLoadTasks = [];
|
|
|
|
|
|
this.onVrListeners = [];
|
|
|
|
|
|
- CursorDeal.attachToViewer(this)//ADD
|
|
|
-
|
|
|
this.messages = [];
|
|
|
this.elMessages = $(`
|
|
|
<div id="message_listing"
|
|
@@ -132,6 +152,12 @@ export class Viewer extends EventDispatcher{
|
|
|
//add
|
|
|
{
|
|
|
$(domElement).append($("<div id='potree_labels'></div>"))
|
|
|
+
|
|
|
+ let mapArea = $("<div id='mapGaode'></div>")
|
|
|
+ $(domElement).append(mapArea)
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
}
|
|
|
|
|
|
|
|
@@ -180,8 +206,7 @@ export class Viewer extends EventDispatcher{
|
|
|
this.filterPointSourceIDRange = [0, 65535];
|
|
|
|
|
|
this.potreeRenderer = null;
|
|
|
- this.edlRenderer = null;
|
|
|
- this.renderer = null;
|
|
|
+ this.edlRenderer = null;
|
|
|
this.pRenderer = null;
|
|
|
|
|
|
this.scene = null;
|
|
@@ -201,8 +226,9 @@ export class Viewer extends EventDispatcher{
|
|
|
this.clock = new THREE.Clock();
|
|
|
this.background = null;
|
|
|
|
|
|
- this.initThree();
|
|
|
+
|
|
|
|
|
|
+
|
|
|
|
|
|
if(args.noDragAndDrop){
|
|
|
|
|
@@ -271,16 +297,35 @@ export class Viewer extends EventDispatcher{
|
|
|
this.setScene(scene);
|
|
|
|
|
|
{
|
|
|
- this.inputHandler = new InputHandler(this);
|
|
|
- this.inputHandler.setScene(this.scene);
|
|
|
-
|
|
|
+ this.inputHandler = new InputHandler(this, this.scene.scene);
|
|
|
+ //this.inputHandler.setScene(this.scene);
|
|
|
+ //this.inputHandler.addInputListener(this);//add
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
this.clippingTool = new ClippingTool(this);
|
|
|
this.transformationTool = new TransformationTool(this);
|
|
|
this.navigationCube = new NavigationCube(this);
|
|
|
this.navigationCube.visible = false;
|
|
|
|
|
|
this.compass = new Compass(this);
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
+ //add----------
|
|
|
+ this.magnifier = new Magnifier(this);
|
|
|
+ this.reticule = new Reticule(this)
|
|
|
+ this.scene.scene.add(this.magnifier)
|
|
|
+ this.scene.scene.add(this.reticule)
|
|
|
+ this.mainViewport = new Viewport(this.renderer, this.scene.view, this.scene.cameraP, {
|
|
|
+ left:0, bottom:0, width:1, height: 1, name:'MainView'
|
|
|
+ })
|
|
|
+ this.viewports = [this.mainViewport]
|
|
|
+
|
|
|
+
|
|
|
+ this.mapViewer = new MapViewer($('#mapGaode')[0])
|
|
|
+ //-----------
|
|
|
+
|
|
|
+
|
|
|
this.createControls();
|
|
|
|
|
|
this.clippingTool.setScene(this.scene);
|
|
@@ -446,16 +491,19 @@ export class Viewer extends EventDispatcher{
|
|
|
}
|
|
|
};
|
|
|
|
|
|
- setControls(controls){
|
|
|
+ setControls(controls/* , setSpeed */){
|
|
|
if (controls !== this.controls) {
|
|
|
if (this.controls) {
|
|
|
- this.controls.enabled = false;
|
|
|
- this.inputHandler.removeInputListener(this.controls);
|
|
|
- }
|
|
|
-
|
|
|
+ this.controls.setEnable(false)
|
|
|
+ //this.inputHandler.removeInputListener(this.controls);
|
|
|
+ this.controls.moveSpeed = this.moveSpeed; //记录 (因为orbit的radius很大,转为firstPerson时要缩小)
|
|
|
+ }
|
|
|
this.controls = controls;
|
|
|
- this.controls.enabled = true;
|
|
|
- this.inputHandler.addInputListener(this.controls);
|
|
|
+ controls.moveSpeed && this.setMoveSpeed(controls.moveSpeed) //add
|
|
|
+
|
|
|
+ this.controls.setEnable(true)
|
|
|
+
|
|
|
+ //this.inputHandler.addInputListener(this.controls);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -672,6 +720,8 @@ export class Viewer extends EventDispatcher{
|
|
|
setFOV (value) {
|
|
|
if (this.fov !== value) {
|
|
|
this.fov = value;
|
|
|
+ this.scene.cameraP.fov = this.fov;
|
|
|
+ this.scene.cameraP.updateProjectionMatrix()
|
|
|
this.dispatchEvent({'type': 'fov_changed', 'viewer': this});
|
|
|
}
|
|
|
};
|
|
@@ -889,11 +939,7 @@ export class Viewer extends EventDispatcher{
|
|
|
});
|
|
|
};
|
|
|
|
|
|
- getBoundingBox (pointclouds) {
|
|
|
- //可以直接返回viewer.bound
|
|
|
- return this.scene.getBoundingBox(pointclouds);
|
|
|
- };
|
|
|
-
|
|
|
+
|
|
|
getGpsTimeExtent(){
|
|
|
const range = [Infinity, -Infinity];
|
|
|
|
|
@@ -1021,16 +1067,19 @@ export class Viewer extends EventDispatcher{
|
|
|
async loadProject(url){
|
|
|
|
|
|
const response = await fetch(url);
|
|
|
-
|
|
|
- const text = await response.text();
|
|
|
- const json = JSON5.parse(text);
|
|
|
- // const json = JSON.parse(text);
|
|
|
-
|
|
|
- if(json.type === "Potree"){
|
|
|
- Potree.loadProject(viewer, json);
|
|
|
- }
|
|
|
+ if(response.ok){
|
|
|
+ const text = await response.text();
|
|
|
+ const json = JSON5.parse(text);
|
|
|
+ // const json = JSON.parse(text);
|
|
|
|
|
|
- //Potree.loadProject(this, url);
|
|
|
+ if(json.type === "Potree"){
|
|
|
+ Potree.loadProject(viewer, json);
|
|
|
+ }
|
|
|
+
|
|
|
+ }else{
|
|
|
+ console.warn("未能加载:"+url )
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
|
|
|
saveProject(){
|
|
@@ -1136,10 +1185,18 @@ export class Viewer extends EventDispatcher{
|
|
|
|
|
|
createControls () {
|
|
|
{ // create FIRST PERSON CONTROLS
|
|
|
- this.fpControls = new FirstPersonControls(this);
|
|
|
+ this.fpControls = new FirstPersonControls(this, this.scene.view);
|
|
|
this.fpControls.enabled = false;
|
|
|
this.fpControls.addEventListener('start', this.disableAnnotations.bind(this));
|
|
|
this.fpControls.addEventListener('end', this.enableAnnotations.bind(this));
|
|
|
+ this.addEventListener("loadPointCloudDone", ()=>{
|
|
|
+ let boundPlane = new THREE.Box3()
|
|
|
+ boundPlane.expandByPoint(this.bound.boundingBox.min.clone())//最低高度为bound的最低
|
|
|
+ boundPlane.expandByPoint(this.bound.boundingBox.max.clone().setZ(this.bound.center.z))//最高高度为bound的中心高度
|
|
|
+ FirstPersonControls.boundPlane = boundPlane
|
|
|
+ FirstPersonControls.standardSpeed = THREE.Math.clamp( Math.sqrt(this.bound.boundSize.length() )/ 100 , 0.02,0.5); //在这个boundPlane中的速度
|
|
|
+ })
|
|
|
+
|
|
|
}
|
|
|
|
|
|
// { // create GEO CONTROLS
|
|
@@ -1424,74 +1481,9 @@ export class Viewer extends EventDispatcher{
|
|
|
$("body")[0].addEventListener("drop", dropHandler);
|
|
|
}
|
|
|
|
|
|
- initThree () {
|
|
|
-
|
|
|
- console.log(`initializing three.js ${THREE.REVISION}`);
|
|
|
-
|
|
|
- let width = this.renderArea.clientWidth;
|
|
|
- let height = this.renderArea.clientHeight;
|
|
|
-
|
|
|
- let contextAttributes = {
|
|
|
- alpha: true,
|
|
|
- depth: true,
|
|
|
- stencil: false,
|
|
|
- antialias: true,
|
|
|
- //premultipliedAlpha: _premultipliedAlpha,
|
|
|
- preserveDrawingBuffer: true,
|
|
|
- powerPreference: "high-performance",
|
|
|
- };
|
|
|
-
|
|
|
- // let contextAttributes = {
|
|
|
- // alpha: false,
|
|
|
- // preserveDrawingBuffer: true,
|
|
|
- // };
|
|
|
-
|
|
|
- // let contextAttributes = {
|
|
|
- // alpha: false,
|
|
|
- // preserveDrawingBuffer: true,
|
|
|
- // };
|
|
|
-
|
|
|
- let canvas = document.createElement("canvas");
|
|
|
-
|
|
|
- let context = canvas.getContext('webgl', contextAttributes );
|
|
|
-
|
|
|
- this.renderer = new THREE.WebGLRenderer({
|
|
|
- alpha: true,
|
|
|
- premultipliedAlpha: false,
|
|
|
- canvas: canvas,
|
|
|
- context: context,
|
|
|
-
|
|
|
- });
|
|
|
- this.renderer.sortObjects = true; //原先false 打开了renderOrder才奏效
|
|
|
- //this.renderer.setSize(width, height);
|
|
|
- this.renderer.autoClear = false;
|
|
|
- this.renderArea.appendChild(this.renderer.domElement);
|
|
|
- this.renderer.domElement.tabIndex = '2222';
|
|
|
- this.renderer.domElement.style.position = 'absolute';
|
|
|
- this.renderer.domElement.addEventListener('mousedown', () => {
|
|
|
- this.renderer.domElement.focus();
|
|
|
- });
|
|
|
- //this.renderer.domElement.focus();
|
|
|
-
|
|
|
- // NOTE: If extension errors occur, pass the string into this.renderer.extensions.get(x) before enabling
|
|
|
- // enable frag_depth extension for the interpolation shader, if available
|
|
|
- let gl = this.renderer.getContext();
|
|
|
- gl.getExtension('EXT_frag_depth');
|
|
|
- gl.getExtension('WEBGL_depth_texture');
|
|
|
- gl.getExtension('WEBGL_color_buffer_float'); // Enable explicitly for more portability, EXT_color_buffer_float is the proper name in WebGL 2
|
|
|
-
|
|
|
- if(gl.createVertexArray == null){
|
|
|
- let extVAO = gl.getExtension('OES_vertex_array_object');
|
|
|
-
|
|
|
- if(!extVAO){
|
|
|
- throw new Error("OES_vertex_array_object extension not supported");
|
|
|
- }
|
|
|
-
|
|
|
- gl.createVertexArray = extVAO.createVertexArrayOES.bind(extVAO);
|
|
|
- gl.bindVertexArray = extVAO.bindVertexArrayOES.bind(extVAO);
|
|
|
- }
|
|
|
+
|
|
|
|
|
|
- }
|
|
|
+
|
|
|
|
|
|
updateAnnotations () {
|
|
|
|
|
@@ -1646,7 +1638,10 @@ export class Viewer extends EventDispatcher{
|
|
|
type: 'update_start',
|
|
|
delta: delta,
|
|
|
timestamp: timestamp});
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
+ this.updateScreenSize() //判断是否改变canvas大小
|
|
|
+
|
|
|
|
|
|
const scene = this.scene;
|
|
|
const camera = scene.getActiveCamera();
|
|
@@ -1657,7 +1652,7 @@ export class Viewer extends EventDispatcher{
|
|
|
const lTarget = camera.position.clone().add(camera.getWorldDirection(new THREE.Vector3()).multiplyScalar(1000));
|
|
|
this.scene.directionalLight.position.copy(camera.position);
|
|
|
this.scene.directionalLight.lookAt(lTarget);
|
|
|
-
|
|
|
+
|
|
|
|
|
|
for (let pointcloud of visiblePointClouds) {
|
|
|
|
|
@@ -1700,8 +1695,27 @@ export class Viewer extends EventDispatcher{
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+
|
|
|
if (!this.freeze) {
|
|
|
- let result = Potree.updatePointClouds(scene.pointclouds, camera, this.renderer);
|
|
|
+
|
|
|
+ /*let cameraGroup = []
|
|
|
+ let size = this.renderer.getSize(new THREE.Vector2())
|
|
|
+ if(this.viewports){
|
|
|
+ this.viewports.forEach(viewport=>{
|
|
|
+ if(!viewport.active)return
|
|
|
+ cameraGroup.push({camera:viewport.camera, areaSize:new THREE.Vector2(Math.floor(size.x * viewport.width), Math.floor(size.y * viewport.height))})
|
|
|
+ })
|
|
|
+ }else{
|
|
|
+ cameraGroup.push({camera, areaSize:size})
|
|
|
+ }
|
|
|
+ let result = Potree.updatePointClouds(scene.pointclouds, cameraGroup );
|
|
|
+ */
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
|
|
|
|
|
|
// DEBUG - ONLY DISPLAY NODES THAT INTERSECT MOUSE
|
|
@@ -1760,8 +1774,8 @@ export class Viewer extends EventDispatcher{
|
|
|
// Potree.debug.numNodes = numNodes;
|
|
|
|
|
|
//console.log(lowestDistance.toString(2), duration);
|
|
|
-
|
|
|
- const tStart = performance.now();
|
|
|
+ //搬走
|
|
|
+ /* const tStart = performance.now();
|
|
|
const campos = camera.position;
|
|
|
let closestImage = Infinity;
|
|
|
for(const images of this.scene.orientedImages){
|
|
@@ -1794,8 +1808,17 @@ export class Viewer extends EventDispatcher{
|
|
|
|
|
|
if(this.scene.cameraMode == CameraMode.ORTHOGRAPHIC) {
|
|
|
camera.near = -camera.far;
|
|
|
- }
|
|
|
- }
|
|
|
+ }*/
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
|
|
|
this.scene.cameraP.fov = this.fov;
|
|
|
|
|
@@ -1809,31 +1832,30 @@ export class Viewer extends EventDispatcher{
|
|
|
} else if (controls !== null) {
|
|
|
controls.setScene(scene);
|
|
|
controls.update(delta);
|
|
|
-
|
|
|
+
|
|
|
//更新camera
|
|
|
-
|
|
|
- if(this.viewports){
|
|
|
- this.viewports.forEach(viewport=>{
|
|
|
- if(!viewport.active)return
|
|
|
- viewport.view.applyToCamera(viewport.camera)
|
|
|
+ this.viewports.forEach(viewport=>{
|
|
|
+ if(!viewport.active)return
|
|
|
+ viewport.view.applyToCamera(viewport.camera)
|
|
|
+ viewport.camera.updateMatrix();
|
|
|
+ viewport.camera.updateMatrixWorld();
|
|
|
+ viewport.camera.matrixWorldInverse.copy(viewport.camera.matrixWorld).invert();
|
|
|
+
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ this.viewports.forEach(e=>{//判断camera画面是否改变
|
|
|
+ if(e.hasChanged()){
|
|
|
+ this.dispatchEvent({
|
|
|
+ type: "camera_changed",
|
|
|
+ camera: e.camera,
|
|
|
+ viewport : e
|
|
|
})
|
|
|
-
|
|
|
- }else{
|
|
|
- if(typeof debugDisabled === "undefined" ){
|
|
|
- scene.view.applyToCamera(this.scene.cameraP)
|
|
|
|
|
|
- }
|
|
|
- scene.view.applyToCamera(this.scene.cameraO)
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- camera.updateMatrix();
|
|
|
- camera.updateMatrixWorld();
|
|
|
- camera.matrixWorldInverse.copy(camera.matrixWorld).invert();
|
|
|
+ }
|
|
|
+ })
|
|
|
|
|
|
- {//判断camera画面是否改变
|
|
|
+ /* {//判断camera画面是否改变
|
|
|
if(this._previousCamera === undefined){
|
|
|
this._previousCamera = this.scene.getActiveCamera().clone();
|
|
|
this._previousCamera.rotation.copy(this.scene.getActiveCamera().rotation);
|
|
@@ -1852,11 +1874,8 @@ export class Viewer extends EventDispatcher{
|
|
|
this._previousCamera = this.scene.getActiveCamera().clone();
|
|
|
this._previousCamera.rotation.copy(this.scene.getActiveCamera().rotation);
|
|
|
|
|
|
- }
|
|
|
+ } */
|
|
|
|
|
|
- {//判断是否改变canvas大小
|
|
|
- this.updateScreenSize()
|
|
|
- }
|
|
|
|
|
|
{ // update clip boxes
|
|
|
let boxes = [];
|
|
@@ -1927,59 +1946,67 @@ export class Viewer extends EventDispatcher{
|
|
|
performance.mark("update-end");
|
|
|
performance.measure("update", "update-start", "update-end");
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+ //add ------
|
|
|
+ this.reticule.updateVisible()
|
|
|
+ this.mapViewer.update(delta)
|
|
|
|
|
|
- this.inputHandler.reticule.updateVisible()//add
|
|
|
+ }
|
|
|
|
|
|
|
|
|
- }
|
|
|
|
|
|
+ updateViewPointcloud(camera, areaSize, isViewport){
|
|
|
+
|
|
|
+
|
|
|
+ let result = Potree.updatePointClouds(this.scene.pointclouds, camera, areaSize );
|
|
|
|
|
|
+
|
|
|
|
|
|
- updateScreenSize(o={}) { //add
|
|
|
-
|
|
|
- var render = false, ratio, w, h;
|
|
|
- //记录应当render的大小
|
|
|
- if (!o.resize && o.width != void 0 && o.height != void 0) {
|
|
|
- w = o.width
|
|
|
- h = o.height
|
|
|
- render = true
|
|
|
- ratio = 1
|
|
|
- }else {
|
|
|
- w = this.renderArea.clientWidth;
|
|
|
- h = this.renderArea.clientHeight
|
|
|
- if(o.resize){
|
|
|
- W = this.renderWidth, H = this.renderHeight
|
|
|
+ if(isViewport)return
|
|
|
+ const tStart = performance.now();
|
|
|
+ const campos = camera.position;
|
|
|
+ let closestImage = Infinity;
|
|
|
+ for(const images of this.scene.orientedImages){
|
|
|
+ for(const image of images.images){
|
|
|
+ const distance = image.mesh.position.distanceTo(campos);
|
|
|
+
|
|
|
+ closestImage = Math.min(closestImage, distance);
|
|
|
}
|
|
|
-
|
|
|
- if(w !== W || h !== H || this.forceUpdateSize || pixelRatio != window.devicePixelRatio){
|
|
|
- W = w
|
|
|
- H = h
|
|
|
- render = true
|
|
|
- pixelRatio = window.devicePixelRatio //如果player放在小窗口了,也要监测devicePixelRatio,因为缩放时client宽高不会改变
|
|
|
- //config.isMobile ? (ratio = Math.min(window.devicePixelRatio, 2)) : (ratio = window.devicePixelRatio)
|
|
|
- ratio = window.devicePixelRatio
|
|
|
- }
|
|
|
}
|
|
|
- if (render) {
|
|
|
- this.setSize(w, h, ratio);
|
|
|
- this.forceUpdateSize = !1
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- setSize(width, height, devicePixelRatio){//add
|
|
|
+ const tEnd = performance.now();
|
|
|
+
|
|
|
+ if(result.lowestSpacing !== Infinity){
|
|
|
+ let near = result.lowestSpacing * 10.0;
|
|
|
+ let far = -this.getBoundingBox().applyMatrix4(camera.matrixWorldInverse).min.z;
|
|
|
+
|
|
|
+ far = Math.max(far * 1.5, 10000);
|
|
|
+ near = Math.min(100.0, Math.max(0.01, near));
|
|
|
+ near = Math.min(near, closestImage);
|
|
|
+ far = Math.max(far, near + 10000);
|
|
|
+
|
|
|
+ if(near === Infinity){
|
|
|
+ near = 0.1;
|
|
|
+ }
|
|
|
+
|
|
|
+ camera.near = near;
|
|
|
+ camera.far = far;
|
|
|
+ }else{
|
|
|
+ // don't change near and far in this case
|
|
|
+ }
|
|
|
+
|
|
|
+ if(this.scene.cameraMode == CameraMode.ORTHOGRAPHIC) {
|
|
|
+ camera.near = -camera.far;
|
|
|
+ }
|
|
|
|
|
|
- this.renderer.setSize(width, height, null, devicePixelRatio); //改 为了防止给canvas设置宽高
|
|
|
- //this.composer.setSize(width, height);
|
|
|
-
|
|
|
- this.dispatchEvent({
|
|
|
- type: 'resize',
|
|
|
- clientWidth:width, clientHeight:height, devicePixelRatio,
|
|
|
- canvasWidth:this.renderer.domElement.width,
|
|
|
- canvasHeight:this.renderer.domElement.height,
|
|
|
- });
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
getPRenderer(){
|
|
|
if(this.useHQ){
|
|
|
if (!this.hqRenderer) {
|
|
@@ -2172,96 +2199,139 @@ export class Viewer extends EventDispatcher{
|
|
|
|
|
|
}
|
|
|
|
|
|
- renderDefault(params={}){
|
|
|
+ renderDefault(params_={}){
|
|
|
let pRenderer = this.getPRenderer();
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- if(!params.target){ // resize
|
|
|
- const width = params.width || this.scaleFactor * this.renderArea.clientWidth;
|
|
|
- const height = params.height || this.scaleFactor * this.renderArea.clientHeight;
|
|
|
|
|
|
-
|
|
|
- //this.renderer.setSize(width, height);
|
|
|
|
|
|
+ let renderSize = this.renderer.getSize(new THREE.Vector2());
|
|
|
+ let needSResize = this.viewports.length > 1 || params_.resize
|
|
|
|
|
|
- if(this.viewports){
|
|
|
- this.viewports.forEach(view=>{
|
|
|
- if(!view.active)return
|
|
|
- var aspect = (this.renderArea.clientWidth * view.width) / (this.renderArea.clientHeight * view.height)
|
|
|
- if(view.name == 'default'){
|
|
|
- view.camera.aspect = aspect;
|
|
|
- view.camera.updateProjectionMatrix();
|
|
|
- }else{
|
|
|
- view.camera.aspect = aspect;
|
|
|
- //不改宽度 同4dkk
|
|
|
- var heightHalf = view.camera.right / aspect
|
|
|
- view.camera.top = heightHalf
|
|
|
- view.camera.bottom = -heightHalf
|
|
|
- view.camera.updateProjectionMatrix()
|
|
|
- }
|
|
|
- })
|
|
|
- }else{
|
|
|
- const pixelRatio = this.renderer.getPixelRatio();
|
|
|
- const aspect = width / height;
|
|
|
-
|
|
|
- const scene = this.scene;
|
|
|
-
|
|
|
- scene.cameraP.aspect = aspect;
|
|
|
- scene.cameraP.updateProjectionMatrix();
|
|
|
-
|
|
|
- let frustumScale = this.scene.view.radius;
|
|
|
- scene.cameraO.left = -frustumScale;
|
|
|
- scene.cameraO.right = frustumScale;
|
|
|
- scene.cameraO.top = frustumScale * 1 / aspect;
|
|
|
- scene.cameraO.bottom = -frustumScale * 1 / aspect;
|
|
|
- scene.cameraO.updateProjectionMatrix();
|
|
|
-
|
|
|
- scene.cameraScreenSpace.top = 1/aspect;
|
|
|
- scene.cameraScreenSpace.bottom = -1/aspect;
|
|
|
- scene.cameraScreenSpace.updateProjectionMatrix();
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
|
|
|
- if(this.viewports && !params.target){
|
|
|
- this.viewports.forEach(view=>{
|
|
|
- if(!view.active)return
|
|
|
- var left = Math.floor(this.renderArea.clientWidth * view.left)
|
|
|
- , bottom = Math.floor(this.renderArea.clientHeight * view.bottom)
|
|
|
- , width = Math.floor(this.renderArea.clientWidth * view.width)
|
|
|
- , height = Math.floor(this.renderArea.clientHeight * view.height);
|
|
|
+ this.viewports.forEach(view=>{
|
|
|
+ let params = $.extend({},params_);
|
|
|
+ if(!params.target){
|
|
|
+ params.camera = params.camera || view.camera;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(!view.active || params.viewport && params.viewport != view)return
|
|
|
+ var left,bottom,width,height
|
|
|
+ if(!params_.target){
|
|
|
+ left = Math.floor(renderSize.x * view.left)
|
|
|
+ , bottom = Math.floor(renderSize.y * view.bottom)
|
|
|
+ , width = view.resolution.x
|
|
|
+ , height = view.resolution.y
|
|
|
this.renderer.setViewport(left, bottom, width, height) //规定视口,影响图形变换
|
|
|
- this.renderer.setScissor( left, bottom, width, height );//规定渲染范围
|
|
|
- this.renderer.setScissorTest( view.width<1 || view.height<1 );//开启WebGL剪裁测试功能,如果不开启,.setScissor方法设置的范围不起作用 | width==1且height==1时开启会只有鼠标的地方刷新,很奇怪
|
|
|
- params.camera = view.camera;
|
|
|
- params.width = width; params.height = height;
|
|
|
+
|
|
|
+ let scissorTest = view.width<1 || view.height<1
|
|
|
+ scissorTest && this.renderer.setScissor( left, bottom, width, height );//规定渲染范围
|
|
|
+ this.renderer.setScissorTest( scissorTest );//开启WebGL剪裁测试功能,如果不开启,.setScissor方法设置的范围不起作用 | width==1且height==1时开启会只有鼠标的地方刷新,很奇怪
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /* needSResize && this.emitResizeMsg({ //resize everything such as lines targets
|
|
|
+ resolution: new THREE.Vector2(width,height),
|
|
|
+ }); */
|
|
|
+ needSResize && this.emitResizeMsg(new THREE.Vector2(width,height), new THREE.Vector2(left, bottom/* renderSize.y-bottom-height */),view)
|
|
|
+
|
|
|
+ viewer.dispatchEvent({type: "render.begin", viewer: viewer, viewport:view, params });
|
|
|
+
|
|
|
+ if(view.render){
|
|
|
+ view.render({renderer:this.renderer, renderOverlay: this.renderOverlay.bind(this) })
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ if(!view.noPointcloud ){
|
|
|
+
|
|
|
+ if(!params.target){
|
|
|
+ params.width = width; params.height = height;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ this.scene.pointclouds.forEach(e=>{
|
|
|
+ if(view.differentPointMat){
|
|
|
+ if(view.name == "MainView"){
|
|
|
+ e.material.activeAttributeName = viewer.matBeforeSplitscreen.colorType
|
|
|
+ e.material.color.copy(viewer.matBeforeSplitscreen.color)
|
|
|
+ e.material.useFilterByNormal = false
|
|
|
+ e.material.opacity = viewer.matBeforeSplitscreen.opacity
|
|
|
+ }else{
|
|
|
+ e.material.activeAttributeName = "color"
|
|
|
+ e.material.color.set(e.color)
|
|
|
+ e.material.useFilterByNormal = true
|
|
|
+ e.material.opacity = 0.09
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+
|
|
|
+ this.updateViewPointcloud(params.camera, new THREE.Vector2(params.width,params.height), true)
|
|
|
pRenderer.clear(params);
|
|
|
pRenderer.render(params);
|
|
|
this.renderer.setRenderTarget(null)
|
|
|
- })
|
|
|
- }else{
|
|
|
- pRenderer.clear(params);
|
|
|
-
|
|
|
- pRenderer.render(params.target ? params : this.renderer);
|
|
|
-
|
|
|
- /* if(!params.target){
|
|
|
- this.renderer.render(this.overlay, this.scene.getActiveCamera() );
|
|
|
- } */
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
- this.renderer.setRenderTarget(null)//add
|
|
|
- }
|
|
|
-
|
|
|
+
|
|
|
+ if(!view.render){
|
|
|
+ this.renderOverlay(params)
|
|
|
+ }
|
|
|
+ this.dispatchEvent({type: "render.end", viewer: this, viewport:view });
|
|
|
+ })
|
|
|
+
|
|
|
+
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ renderOverlay(params){
|
|
|
+ let camera = params.camera ? params.camera : this.scene.getActiveCamera();
|
|
|
+
|
|
|
+ if(!params.magnifier){//为什么要在点云之后渲染,否则透明失效 、 会被点云覆盖
|
|
|
+ camera.layers.set(Potree.config.renderLayers.marker);//透明贴图层 skybox 、reticule marker 不能遮住测量线
|
|
|
+ this.renderer.render(this.scene.scene, camera);
|
|
|
+ }
|
|
|
+ this.dispatchEvent({type: "render.pass.scene", viewer: viewer});
|
|
|
+
|
|
|
+ //清除深度 !!!!
|
|
|
+ this.renderer.clearDepth();
|
|
|
+
|
|
|
+ this.transformationTool.update();
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ if(!params.magnifier){
|
|
|
+ //测量线
|
|
|
+ this.dispatchEvent({type: "render.pass.perspective_overlay", viewer:this, camera});
|
|
|
+
|
|
|
+ if(!params.screenshot){
|
|
|
+ camera.layers.set(Potree.config.renderLayers.magnifier);//magnifier 遮住测量线
|
|
|
+ this.renderer.render(this.scene.scene, camera);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ this.renderer.render(this.clippingTool.sceneVolume, camera);
|
|
|
+ this.renderer.render(this.transformationTool.scene, camera);
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
render(params){//add params
|
|
|
if(Potree.measureTimings) performance.mark("render-start");
|
|
|
|
|
|
- try{
|
|
|
+ //try{
|
|
|
|
|
|
const vrActive = this.renderer.xr.isPresenting;
|
|
|
|
|
@@ -2271,9 +2341,9 @@ export class Viewer extends EventDispatcher{
|
|
|
this.renderDefault(params);
|
|
|
}
|
|
|
|
|
|
- }catch(e){
|
|
|
+ /* }catch(e){
|
|
|
this.onCrash(e);
|
|
|
- }
|
|
|
+ } */
|
|
|
|
|
|
if(Potree.measureTimings){
|
|
|
performance.mark("render-end");
|
|
@@ -2392,7 +2462,7 @@ export class Viewer extends EventDispatcher{
|
|
|
}
|
|
|
|
|
|
this.update(this.clock.getDelta(), timestamp);
|
|
|
- this.inputHandler.magnifier.render();
|
|
|
+ this.magnifier.render();
|
|
|
this.render();
|
|
|
|
|
|
|
|
@@ -2466,16 +2536,114 @@ export class Viewer extends EventDispatcher{
|
|
|
}
|
|
|
|
|
|
|
|
|
+ /* makeScreenshot(camera, size, callback){
|
|
|
+
|
|
|
+ if(camera === undefined || camera === null){
|
|
|
+ camera = this.scene.getActiveCamera();
|
|
|
+ }
|
|
|
+
|
|
|
+ if(size === undefined || size === null){
|
|
|
+ size = this.renderer.getSize(new THREE.Vector2());
|
|
|
+ }
|
|
|
+ let {width, height} = size;
|
|
|
+ const aspect = width / height;
|
|
|
+ camera.aspect = aspect
|
|
|
+ camera.updateProjectionMatrix()
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ let oldBudget = Potree.pointBudget;
|
|
|
+ Potree.pointBudget = Math.max(10 * 1000 * 1000, 2 * oldBudget);
|
|
|
+ let result = Potree.updatePointClouds(this.scene.pointclouds, camera, size );
|
|
|
+ Potree.pointBudget = oldBudget;
|
|
|
+
|
|
|
+
|
|
|
+ this.dispatchEvent({ //resize everything such as lines targets
|
|
|
+ type: 'resize',
|
|
|
+ resolution: new THREE.Vector2(width,height),
|
|
|
+ });
|
|
|
+
|
|
|
+ let target = new THREE.WebGLRenderTarget(width, height, {
|
|
|
+ format: THREE.RGBAFormat,
|
|
|
+ });
|
|
|
+
|
|
|
+ // HACK? removed because of error, was this important?
|
|
|
+
|
|
|
+ this.renderDefault({
|
|
|
+ target ,
|
|
|
+ camera ,
|
|
|
+ screenshot : true,
|
|
|
+ width ,
|
|
|
+ height,
|
|
|
+ });
|
|
|
+
|
|
|
+ let pixelCount = width * height;
|
|
|
+ let buffer = new Uint8Array(4 * pixelCount);
|
|
|
+
|
|
|
+ this.renderer.readRenderTargetPixels(target, 0, 0, width, height, buffer);
|
|
|
+
|
|
|
+ callback && callback(buffer)
|
|
|
+ target.dispose();
|
|
|
+
|
|
|
+ //resize back
|
|
|
+ this.updateScreenSize({forceUpdateSize:true})
|
|
|
+
|
|
|
+ return {
|
|
|
+ width: width,
|
|
|
+ height: height,
|
|
|
+ buffer: buffer
|
|
|
+ };
|
|
|
+ } */
|
|
|
+
|
|
|
+ Screenshot(type, width=800, height=400, compressRatio){//add
|
|
|
+ let viewport,camera
|
|
|
+ if(type == 'mainView'){
|
|
|
+ viewport = this.mainViewport
|
|
|
+ }else if(type == 'map'){
|
|
|
+ viewport = this.mapViewer.viewports[0]
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ var { buffer } = this.makeScreenshot(camera, new THREE.Vector2(width,height), viewport);
|
|
|
+
|
|
|
+ var dataUrl = Potree.Utils.pixelsArrayToDataUrl(buffer, width, height, compressRatio)
|
|
|
+
|
|
|
+ Common.downloadFile(dataUrl, 'screenshot.jpg')
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
|
|
|
+ getBoundingBox (pointclouds) {
|
|
|
+ //可以直接返回viewer.bound
|
|
|
+ if(!this.bound){
|
|
|
+ this.updateModelBound()
|
|
|
+ }
|
|
|
+ return this.bound.boundingBox.clone()//this.scene.getBoundingBox(pointclouds);
|
|
|
+ };
|
|
|
+
|
|
|
+ updateModelBound(){
|
|
|
+ this.bound = Utils.computePointcloudsBound(this.scene.pointclouds)
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+ /* attachMapToViewer(state){
|
|
|
+ state ? viewer.mapViewer.attachToMainViewer(state);
|
|
|
+
|
|
|
+ } */
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
/* t.prototype.getTransformationMatrix = function(t) {//点云截取 所有点在乘上这个矩阵后, 还能落在 1 * 1 * 1的box内的点就是所裁剪的
|
|
|
var e = this.ViewService.mainView.getVolumeClippingLayer().getBoxFrame()
|
|
|
, n = (new o.Matrix4).getInverse(e.matrixWorld)
|