123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343 |
- import * as THREE from "../../libs/three.js/build/three.module.js";
- import Common from '../utils/Common'
-
- export class ViewerBase extends THREE.EventDispatcher{
- constructor(domElement, args = {}){
- super()
- this.name = args.name
- this.renderArea = domElement
- this.oldResolution = new THREE.Vector2()
-
- this.screenSizeInfo = {
- W:0, H:0, pixelRatio:1 , windowWidth:0, windowHeight:0
- }
-
- this.initContext(args);
-
-
- this.addEventListener('content_changed', ()=>{//画面改变,需要渲染
- this.needRender = true
- })
-
-
- }
-
-
-
-
-
- initContext(args){
- //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,
- preserveDrawingBuffer: true,
- powerPreference: "high-performance",
- };
- 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 = args.autoClear || false;
- //args.clearColor = args.clearColor || '#aa0033'
- args.clearColor && this.renderer.setClearColor(args.clearColor)
- 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);
- }
-
- /* let oldClear = gl.clear;
- gl.clear = (bits)=>{
- console.error('clear')
- }
- */
-
- }
-
-
-
-
- updateScreenSize(o={}) { //有可能需要让viewport来判断,当窗口大小不变但viewport大小变时
-
- var render = false, ratio, w, h;
- //记录应当render的大小
- if (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(w !== this.screenSizeInfo.W || h !== this.screenSizeInfo.H || o.forceUpdateSize || this.screenSizeInfo.pixelRatio != window.devicePixelRatio){
- this.screenSizeInfo.W = w
- this.screenSizeInfo.H = h
- render = true
- this.screenSizeInfo.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);
- }
- }
- /* updateScreenSize(o={}) { //容易出错。。
-
- var render = false, ratio, w, h;
- //记录应当render的大小
- if (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
- let refreshWin = ()=>{
- this.screenSizeInfo.windowWidth = window.innerWidth
- this.screenSizeInfo.windowHeight = window.innerHeight
- }
-
- let prepareToRender = ()=>{
- w = this.renderArea.clientWidth;
- h = this.renderArea.clientHeight
- this.screenSizeInfo.W = w
- this.screenSizeInfo.H = h
- refreshWin() //render后才refreshWin
- render = true
- this.screenSizeInfo.pixelRatio = window.devicePixelRatio //如果player放在小窗口了,也要监测devicePixelRatio,因为缩放时client宽高不会改变
- //config.isMobile ? (ratio = Math.min(window.devicePixelRatio, 2)) : (ratio = window.devicePixelRatio)
- ratio = window.devicePixelRatio
- //console.log('setSize11', w)
- o.forceUpdateSize = false ;//防止再次render
- }
- let ifNeedUpdate = ()=>{
- w = this.renderArea.clientWidth;
- h = this.renderArea.clientHeight
- return o.forceUpdateSize || w !== this.screenSizeInfo.W || h !== this.screenSizeInfo.H || this.screenSizeInfo.pixelRatio != window.devicePixelRatio
- }
-
- if(ifNeedUpdate()){
- //当只有一个有效viewport时,且因为改变整个窗口大小而触发的话,延时
- let canInterval = !o.forceUpdateSize && this.viewports.filter(e=>e.active).length==1 && (this.screenSizeInfo.windowWidth != window.innerWidth || this.screenSizeInfo.windowHeight != window.innerHeight )
-
- if(canInterval){
- Common.intervalTool.isWaiting('updateScreenSize', ()=>{ //延时update,防止崩溃 , 未到时间就拦截(第一次直接执行)
- if(ifNeedUpdate()){
- prepareToRender()
- return true
- }
- }, 500)
- }else{
- //console.log('soon', window.innerWidth, this.screenSizeInfo.windowWidth)
- prepareToRender()
- }
-
- }
-
- }
- if (render) {
- this.setSize(w, h, ratio);
- }
- } */
-
- setSize(width, height, devicePixelRatio, onlyForTarget){
- //console.log('setSize', width)
- if(!onlyForTarget){//onlyForTarget表示不更改当前renderer,只是为了rendertarget才要改变viewport
- this.renderer.setSize(width, height, null, devicePixelRatio); // resize之后会自动clear(似乎因为setScissor ),所以一定要立刻绘制,所以setSize要在cameraChanged、update之前
- }
-
- this.composer && this.composer.setSize(width, height);
-
- if(this.viewports){
- this.viewports.forEach((view,i)=>{
- if(!view.active)return
-
- var width_ = width * view.width
- var height_ = height * view.height
-
- if(height_ == 0)return //avoid NAN
-
- view.setResolution(Math.ceil(width_), Math.ceil(height_), width, height ) //本来应该是floor,但是这样奇数时会少一个像素,导致向左移一个像素且宽度少1。现在则多绘制1个像素,超出的1个像素应该不会绘制出来(但不知道其他地方是否有偏差,比如pick时)
- let aspect = width_ / height_; //camera的参数精确些,不用视口的归整的resolution像素值,否则hasChange无法为true, 导致canvasResize了但map没update从而闪烁
- view.camera.aspect = aspect;
-
- if(view.camera.type == "OrthographicCamera"){
-
- /* //不改宽度 同4dkk
- var heightHalf = view.camera.right / aspect
- view.camera.top = heightHalf
- view.camera.bottom = -heightHalf */
- //高宽都改 使大小不随视口大小改变 navvis (直接和视口大小一致即可,通过zoom来定大小)
-
- view.camera.left = -width_/2
- view.camera.right = width_/2
- view.camera.bottom = -height_/2;
- view.camera.top = height_/2
-
-
- }else{
-
-
- }
-
- view.camera.updateProjectionMatrix();
- })
- }
-
-
- if(!onlyForTarget){//因为onlyForTarget不传递devicePixelRatio所以不发送了
- this.emitResizeMsg({viewport:this.viewports[0], deviceRatio:devicePixelRatio})
- }
-
- }
-
- emitResizeMsg(e){//切换viewport渲染时就发送一次, 通知一些材质更新resolution。
- if(!e.viewport.resolution.equals(this.oldResolution)){
- this.dispatchEvent($.extend(e, {type:'resize'}))
- this.oldResolution.copy(e.viewport.resolution)
- }
-
-
- }
-
-
-
- cameraChanged() {//判断相机是否改变
- var changed = false;
- /* if(this.needRender){
- this.needRender = false
- return true
- } */
- for(let i=0,j=this.viewports.length;i<j;i++){
- let changed_ = this.viewports[i].cameraChanged()
- if(changed_){
- changed = true
- this.dispatchEvent({
- type: "camera_changed",
- camera: this.viewports[i].camera,
- viewport : this.viewports[i]
- })
- }
- }
- return changed
- }
-
-
-
-
-
- makeScreenshot( size, viewports, compressRatio){//暂时不要指定viewports渲染,但也可以
-
-
- let {width, height} = size;
-
-
-
-
- /* 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,
- });
-
-
- this.setSize(width, height,1,true)
-
- this.render({
- target ,
- //camera ,
- viewports: viewports || this.viewports,
- screenshot : true,
- width ,
- height,
- resize :true //需要resize
- });
- let dataUrl = Potree.Utils.renderTargetToDataUrl(target, width, height, this.renderer, compressRatio)
-
-
- /* let pixelCount = width * height;
- let buffer = new Uint8Array(4 * pixelCount);
- this.renderer.readRenderTargetPixels(target, 0, 0, width, height, buffer);
- let dataUrl = Potree.Utils.pixelsArrayToDataUrl(buffer, width, height, compressRatio) */
-
- target.dispose();
-
- //resize back
- //this.updateScreenSize({forceUpdateSize:true})
-
- return {
- width,
- height,
- dataUrl
- };
- }
-
- }
|