viewerBase.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. import * as THREE from "../../../libs/three.js/build/three.module.js";
  2. import Common from '../utils/Common.js'
  3. export class ViewerBase extends THREE.EventDispatcher{
  4. constructor(domElement, args = {}){
  5. super()
  6. this.name = args.name
  7. this.renderArea = domElement
  8. this.oldResolution = new THREE.Vector2()
  9. this.oldResolution2 = new THREE.Vector2()
  10. this.screenSizeInfo = {
  11. W:0, H:0, pixelRatio:1 , windowWidth:0, windowHeight:0
  12. }
  13. this.initContext(args);
  14. this.addEventListener('content_changed', ()=>{//画面改变,需要渲染
  15. this.needRender = true
  16. //console.log('needRender')
  17. })
  18. }
  19. initContext(args){
  20. //console.log(`initializing three.js ${THREE.REVISION}`);
  21. let width = this.renderArea.clientWidth;
  22. let height = this.renderArea.clientHeight;
  23. let contextAttributes = {
  24. alpha: true,//支持透明
  25. depth: true,
  26. stencil: false,
  27. antialias: !!args.antialias,
  28. preserveDrawingBuffer: args.preserveDrawingBuffer || false ,
  29. powerPreference: "high-performance",
  30. };
  31. let canvas = document.createElement("canvas");
  32. let context = canvas.getContext('webgl2', contextAttributes ); //不用webgl2是因为有的写法在webgl2不支持 如gl_FragDepthEXT
  33. if(context){
  34. Potree.settings.isWebgl2 = true
  35. }
  36. this.renderer = new THREE.WebGLRenderer({
  37. premultipliedAlpha: false,
  38. canvas: canvas,
  39. context: context,
  40. });
  41. this.renderer.sortObjects = true; //原先false 打开了renderOrder才奏效
  42. //this.renderer.setSize(width, height);
  43. this.renderer.autoClear = args.autoClear || false;
  44. //args.clearColor = args.clearColor || '#aa0033'
  45. args.clearColor && this.renderer.setClearColor(args.clearColor)
  46. this.renderArea.appendChild(this.renderer.domElement);
  47. this.renderer.domElement.tabIndex = '2222';
  48. this.renderer.domElement.style.position = 'absolute';
  49. this.renderer.domElement.addEventListener('mousedown', () => {
  50. this.renderer.domElement.focus();
  51. });
  52. //this.renderer.domElement.focus();
  53. // NOTE: If extension errors occur, pass the string into this.renderer.extensions.get(x) before enabling
  54. // enable frag_depth extension for the interpolation shader, if available
  55. let gl = this.renderer.getContext();
  56. gl.getExtension('EXT_frag_depth');
  57. gl.getExtension('WEBGL_depth_texture');
  58. gl.getExtension('WEBGL_color_buffer_float'); // Enable explicitly for more portability, EXT_color_buffer_float is the proper name in WebGL 2
  59. if(gl.createVertexArray == null){
  60. let extVAO = gl.getExtension('OES_vertex_array_object');
  61. if(!extVAO){
  62. throw new Error("OES_vertex_array_object extension not supported");
  63. }
  64. gl.createVertexArray = extVAO.createVertexArrayOES.bind(extVAO);
  65. gl.bindVertexArray = extVAO.bindVertexArrayOES.bind(extVAO);
  66. }
  67. /* let oldClear = gl.clear;
  68. gl.clear = (bits)=>{
  69. console.error('clear')
  70. }
  71. */
  72. }
  73. updateScreenSize(o={}) { //有可能需要让viewport来判断,当窗口大小不变但viewport大小变时
  74. if(this.screenshoting && !o.forceUpdateSize) return //截图时不允许因窗口改变大小而updateScreenSize
  75. var render = false, ratio, w, h;
  76. //记录应当render的大小
  77. if (o.width != void 0 && o.height != void 0) {
  78. w = o.width
  79. h = o.height
  80. render = true
  81. ratio = 1
  82. }else {
  83. w = this.renderArea.clientWidth;
  84. h = this.renderArea.clientHeight
  85. if(w !== this.screenSizeInfo.W || h !== this.screenSizeInfo.H || o.forceUpdateSize || this.screenSizeInfo.pixelRatio != window.devicePixelRatio){
  86. this.screenSizeInfo.W = w
  87. this.screenSizeInfo.H = h
  88. render = true
  89. this.screenSizeInfo.pixelRatio = window.devicePixelRatio //如果player放在小窗口了,也要监测devicePixelRatio,因为缩放时client宽高不会改变
  90. //config.isMobile ? (ratio = Math.min(window.devicePixelRatio, 2)) : (ratio = window.devicePixelRatio)
  91. ratio = window.devicePixelRatio
  92. }
  93. }
  94. if (render) {
  95. this.setSize(w, h, ratio, o.forTarget );
  96. }
  97. }
  98. setSize(width, height, devicePixelRatio, onlyForTarget){
  99. //console.log('setSize', width)
  100. if(!onlyForTarget){//onlyForTarget表示不更改当前renderer,只是为了rendertarget才要改变viewport
  101. this.renderer.setPixelRatio(devicePixelRatio)
  102. this.renderer.setSize(width, height ); // resize之后会自动clear(似乎因为setScissor ),所以一定要立刻绘制,所以setSize要在cameraChanged、update之前
  103. }
  104. //this.composer && this.composer.setSize(width, height);
  105. if(this.viewports){
  106. this.viewports.forEach((view,i)=>{
  107. //if(!view.active)return
  108. var width_ = width * view.width
  109. var height_ = height * view.height
  110. view.setResolution(Math.ceil(width_), Math.ceil(height_), width, height )
  111. if(height_ == 0)return //avoid NAN
  112. let aspect = width_ / height_; //camera的参数精确些,不用视口的归整的resolution像素值,否则hasChange无法为true, 导致canvasResize了但map没update从而闪烁
  113. view.camera.aspect = aspect;
  114. if(view.camera.type == "OrthographicCamera"){
  115. /* //不改宽度 同4dkk
  116. var heightHalf = view.camera.right / aspect
  117. view.camera.top = heightHalf
  118. view.camera.bottom = -heightHalf */
  119. //高宽都改 使大小不随视口大小改变 navvis (直接和视口大小一致即可,通过zoom来定大小)
  120. view.camera.left = -width_/2
  121. view.camera.right = width_/2
  122. view.camera.bottom = -height_/2;
  123. view.camera.top = height_/2
  124. }else{
  125. }
  126. view.camera.updateProjectionMatrix();
  127. })
  128. }
  129. if(!onlyForTarget){//因为onlyForTarget不传递devicePixelRatio所以不发送了
  130. this.dispatchEvent('viewerResize')
  131. this.viewports.forEach(e=>{
  132. this.ifEmitResize({viewport:e, deviceRatio:devicePixelRatio})
  133. })
  134. }
  135. }
  136. ifEmitResize(e){//切换viewport渲染时, 若这些viewport大小不同就发送一次, 通知一些材质更新resolution。
  137. //console.log('ifEmitResize',e.viewport.name,e.viewport.resolution2 )
  138. if(!e.viewport.resolution.equals(this.oldResolution)||!e.viewport.resolution2.equals(this.oldResolution2)){
  139. this.dispatchEvent($.extend(e, {type:'resize'}))
  140. this.oldResolution.copy(e.viewport.resolution)
  141. this.oldResolution2.copy(e.viewport.resolution2)
  142. }
  143. }
  144. cameraChanged() {//判断相机是否改变
  145. var changed = false;
  146. /* if(this.needRender){
  147. this.needRender = false
  148. return true
  149. } */
  150. for(let i=0,j=this.viewports.length;i<j;i++){
  151. let viewport = this.viewports[i]
  152. let changeInfo = viewport.cameraChanged()
  153. if(changeInfo.changed){
  154. changed = true
  155. //if(!this.changeTime ||this.changeTime<100){
  156. this.dispatchEvent({
  157. type: "camera_changed",
  158. camera: viewport.camera,
  159. viewport ,
  160. changeInfo
  161. })
  162. //this.changeTime = (this.changeTime || 0) +1
  163. //}
  164. viewport.needRender = true //直接写这咯
  165. if(changeInfo.resolutionChanged){
  166. this.ifEmitResize({viewport}) //for map
  167. }
  168. }
  169. }
  170. return changed
  171. }
  172. makeScreenshot( size, viewports, compressRatio){//暂时不要指定viewports渲染,但也可以
  173. let {width, height} = size;
  174. /* let oldBudget = Potree.pointBudget;
  175. Potree.pointBudget = Math.max(10 * 1000 * 1000, 2 * oldBudget);
  176. let result = Potree.updatePointClouds(this.scene.pointclouds, camera, size );
  177. Potree.pointBudget = oldBudget;
  178. this.dispatchEvent({ //resize everything such as lines targets
  179. type: 'resize',
  180. resolution: new THREE.Vector2(width,height),
  181. });*/
  182. let target = new THREE.WebGLRenderTarget(width, height, {
  183. format: THREE.RGBAFormat,
  184. });
  185. this.setSize(width, height,1,true)
  186. this.render({
  187. target ,
  188. //camera ,
  189. viewports: viewports || this.viewports,
  190. screenshot : true,
  191. width ,
  192. height,
  193. resize :true //需要resize
  194. });
  195. let dataUrl = Potree.Utils.renderTargetToDataUrl(target, width, height, this.renderer, compressRatio)
  196. /* let pixelCount = width * height;
  197. let buffer = new Uint8Array(4 * pixelCount);
  198. this.renderer.readRenderTargetPixels(target, 0, 0, width, height, buffer);
  199. let dataUrl = Potree.Utils.pixelsArrayToDataUrl(buffer, width, height, compressRatio) */
  200. target.dispose();
  201. //resize back
  202. //this.updateScreenSize({forceUpdateSize:true})
  203. return {
  204. width,
  205. height,
  206. dataUrl
  207. };
  208. }
  209. dispose(scene=this.scene){
  210. scene.clear();
  211. this.renderer.dispose()
  212. this.renderer.forceContextLoss()
  213. let gl = this.renderer.getContext();
  214. gl.getExtension("WEBGL_lose_context") && gl.getExtension("WEBGL_lose_context").loseContext()
  215. this.renderArea.removeChild(this.renderer.domElement)
  216. this.dispatchEvent('dispose')
  217. }
  218. }