viewerBase.js 8.7 KB

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