EDLRendererNew.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. import * as THREE from "../../libs/three.js/build/three.module.js";
  2. import {PointCloudSM} from "../utils/PointCloudSM.js";
  3. import {ExtendEyeDomeLightingMaterial} from "../materials/ExtendEyeDomeLightingMaterial.js";
  4. import {SphereVolume} from "../utils/Volume.js";
  5. import {Utils} from "../utils.js";
  6. import {copyShader} from '../materials/shaders/otherShaders.js'
  7. import {Features} from "../Features.js";
  8. import {easing} from "../custom/utils/transitions.js";
  9. import Common from "../custom/utils/Common.js";
  10. //import DepthTexSampler from "../custom/utils/DepthTexSampler.js";
  11. export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
  12. constructor(viewer){
  13. this.viewer = viewer;
  14. this.edlMaterial = null;
  15. //this.rtRegular;
  16. this.rtEDLs = new Map
  17. this.gl = viewer.renderer.getContext();
  18. //反正也没用到,注释了:
  19. //this.shadowMap = new PointCloudSM(this.viewer.pRenderer);
  20. viewer.addEventListener('resize',this.resize.bind(this))
  21. this.initEDL(viewer)
  22. }
  23. initEDL(viewer){
  24. if (this.edlMaterial != null || !Features.EXT_DEPTH.isSupported()){
  25. return;
  26. }
  27. this.edlMaterial = new ExtendEyeDomeLightingMaterial();
  28. this.edlMaterial.depthTest = true;
  29. this.edlMaterial.depthWrite = true;
  30. this.edlMaterial.transparent = true;
  31. let copyUniforms = THREE.UniformsUtils.clone( copyShader.uniforms );
  32. let {vs,fs} = Common.changeShaderToWebgl2(copyShader.vertexShader, copyShader.fragmentShader, 'ShaderMaterial')
  33. this.recoverToScreenMat = new THREE.ShaderMaterial({
  34. uniforms: copyUniforms,
  35. vertexShader: vs,
  36. fragmentShader: fs,
  37. transparent: true,
  38. defines:{
  39. useDepth: true //开启后,其他物体才能被遮挡
  40. }
  41. })
  42. /* let copyUniforms = THREE.UniformsUtils.clone( copyShader.uniforms );
  43. this.copyMaterial = new THREE.ShaderMaterial( {
  44. uniforms: copyUniforms,
  45. vertexShader: copyShader.vertexShader,
  46. fragmentShader: copyShader.fragmentShader,
  47. //premultipliedAlpha: true,
  48. transparent: true,
  49. //blending: THREE.AdditiveBlending,
  50. depthTest: false,
  51. depthWrite: false
  52. }); */
  53. if(Potree.settings.useRTskybox != Potree.settings.useRTPoint){//如果两个只开了一个
  54. viewer.images360.addEventListener('endChangeMode',()=>{
  55. this.resize({viewport:viewer.mainViewport})
  56. })
  57. }
  58. //this.depthTexSampler = new DepthTexSampler(this);
  59. };
  60. resize(e){
  61. if(Features.EXT_DEPTH.isSupported()){
  62. let viewport = e.viewport
  63. let size = ( Potree.settings.displayMode == 'showPanos' ? Potree.settings.useRTskybox : Potree.settings.useRTPoint) ? viewport.resolution2 : viewport.resolution; //若要渲染skybox,需要和设备一样精度的rt
  64. this.getRtEDL(viewport).setSize( size.x, size.y ); //理论上可以是任意尺寸,但会影响精度,且aspect最好和渲染的一致
  65. }
  66. }
  67. clearTargets(params={}){
  68. const viewer = this.viewer;
  69. const {renderer} = viewer;
  70. const oldTarget = renderer.getRenderTarget();
  71. if(params.target){//add
  72. renderer.setRenderTarget( params.target);
  73. renderer.clear()
  74. }
  75. if(Features.EXT_DEPTH.isSupported()){
  76. let rtEDL = params.rtEDL || this.getRtEDL(params.viewport)
  77. if(rtEDL){
  78. renderer.setRenderTarget( rtEDL );
  79. let oldAlpha = renderer.getClearAlpha()
  80. renderer.setClearAlpha(0)
  81. renderer.clear( true, true, true );
  82. renderer.setClearAlpha(oldAlpha)
  83. }
  84. }
  85. //renderer.setRenderTarget( this.rtRegular );
  86. //renderer.clear( true, true, false );
  87. renderer.setRenderTarget(oldTarget);
  88. }
  89. getRtEDL(viewport){//根据不同viewport返回rtEDL的texture
  90. if(!viewport){
  91. console.warn('getRtEDL没传viewport!!!! !!!!!!!!!!')
  92. viewport = viewer.mainViewport
  93. }
  94. var rtEDL = this.rtEDLs.get(viewport)
  95. if(!rtEDL){
  96. if(Features.EXT_DEPTH.isSupported()){
  97. rtEDL = new THREE.WebGLRenderTarget(viewport.resolution.x, viewport.resolution.y, {
  98. minFilter: THREE.NearestFilter,
  99. magFilter: THREE.NearestFilter,
  100. format: THREE.RGBAFormat,
  101. type: THREE.FloatType,
  102. depthTexture: new THREE.DepthTexture(undefined, undefined, THREE.UnsignedIntType)
  103. });
  104. //注: 部分手机在resize时会崩溃,经检验去掉rtEDL的resize可以解决,所以更应该注释掉这个
  105. this.rtEDLs.set(viewport, rtEDL)
  106. }
  107. }
  108. //注:当pc窗口缩小,deviceRatio变小后,resolution2会小于resolution,然后遮挡会出现精度损失而有细微不准,是正常现象。
  109. return rtEDL
  110. }
  111. renderShadowMap(visiblePointClouds, camera, lights){
  112. const {viewer} = this;
  113. const doShadows = lights.length > 0 && !(lights[0].disableShadowUpdates);
  114. if(doShadows){
  115. let light = lights[0];
  116. this.shadowMap.setLight(light);
  117. let originalAttributes = new Map();
  118. for(let pointcloud of viewer.scene.pointclouds){
  119. // TODO IMPORTANT !!! check
  120. originalAttributes.set(pointcloud, pointcloud.material.activeAttributeName);
  121. pointcloud.material.disableEvents();
  122. pointcloud.material.activeAttributeName = "depth";
  123. //pointcloud.material.pointColorType = PointColorType.DEPTH;
  124. }
  125. this.shadowMap.render(viewer.scene.scenePointCloud, camera);
  126. for(let pointcloud of visiblePointClouds){
  127. let originalAttribute = originalAttributes.get(pointcloud);
  128. // TODO IMPORTANT !!! check
  129. pointcloud.material.activeAttributeName = originalAttribute;
  130. pointcloud.material.enableEvents();
  131. }
  132. viewer.shadowTestCam.updateMatrixWorld();
  133. viewer.shadowTestCam.matrixWorldInverse.copy(viewer.shadowTestCam.matrixWorld).invert();
  134. viewer.shadowTestCam.updateProjectionMatrix();
  135. }
  136. }
  137. getIfRtEDL_(params={}){
  138. return (Potree.settings.pointEnableRT && Potree.settings.displayMode == 'showPointCloud'
  139. || Potree.settings.displayMode == 'showPanos'/* && viewer.images360.currentPano.pointcloud.hasDepthTex */
  140. || viewer.useEDL) &&
  141. Features.EXT_DEPTH.isSupported() && params.camera.type != "OrthographicCamera" && !params.dontRenderRtEDL && (params.rtEDL || this.getRtEDL(params.viewport)) // 平面相机不用depthTex直接打开depthTest?且不使用edl
  142. }
  143. getIfuseEdl(params={} ){
  144. return viewer.useEDL && Potree.settings.displayMode != 'showPanos'
  145. }
  146. canUseRTPoint(){
  147. return Potree.settings.useRTPoint && !viewer.scene.pointclouds.some(e=>e.visible && e.material.opacity < 1) && !viewer.objs.children.some(e=>e.opacity < 1) //透明mesh发黑,透明无效
  148. }
  149. render(params={}){
  150. const viewer = this.viewer;
  151. let camera = params.camera ? params.camera : viewer.scene.getActiveCamera();
  152. let rtEDL = this.getIfRtEDL_(params)
  153. let useEDL = rtEDL && this.getIfuseEdl(params)
  154. let target = params.target || null
  155. const resolution = (rtEDL && Potree.settings.useRTPoint) ? new THREE.Vector2(rtEDL.width,rtEDL.height) : params.target ? new THREE.Vector2(params.target.width, params.target.height ) : params.viewport ? params.viewport.resolution2 : this.viewer.renderer.getSize(new THREE.Vector2());//截图时需要用target的大小
  156. let renderer = params.renderer || viewer.renderer
  157. let pRenderer = params.pRenderer || viewer.pRenderer
  158. renderer.setRenderTarget(target);
  159. //viewer.dispatchEvent({type: "render.pass.begin",viewer: viewer});
  160. let lights = [];
  161. /* viewer.scene.scene.traverse(node => {
  162. if(node.type === "SpotLight"){
  163. lights.push(node);
  164. }
  165. }); */
  166. //skybox 全景图
  167. if(!params.magnifier){
  168. if(Potree.settings.displayMode == 'showPanos' || Potree.settings.testCube ){
  169. Potree.Utils.setCameraLayers(camera, ['skybox']) //注:model等也可能是skybox
  170. if((Potree.settings.displayMode == 'showPanos' ) && (viewer.images360.currentPano.pointcloud.hasDepthTex || Potree.settings.modelSkybox && viewer.images360.currentPano.pointcloud.is4dkkModel) && rtEDL){//渲染深度图
  171. renderer.setRenderTarget(rtEDL) //将带有深度图的skybox画在rtEDL一下,这样就不需要绘制后边的点云了
  172. renderer.render(viewer.scene.scene, camera);
  173. renderer.setRenderTarget(target);
  174. if(Potree.settings.useRTskybox){//直接使用rtEDL,但是会失去抗锯齿,不知在skybox上需要抗锯齿吗
  175. this.recoverToScreenMat.uniforms.depthTex.value = rtEDL.depthTexture
  176. this.recoverToScreenMat.uniforms.tDiffuse.value = rtEDL.texture
  177. Utils.screenPass.render(renderer, this.recoverToScreenMat, target);
  178. }else{
  179. renderer.render(viewer.scene.scene, camera);
  180. }
  181. }else{
  182. renderer.render(viewer.scene.scene, camera);
  183. }
  184. if(Potree.settings.displayMode == 'showPanos' ){
  185. if(Potree.settings.fastTran && viewer.images360.fastTranMaskPass.enabled){
  186. viewer.images360.fastTranMaskPass.render()
  187. }
  188. if( viewer.objs.children.length == 0 || !params.useModelOnRT ) return //没有模型需要绘制遮挡
  189. }
  190. }
  191. }
  192. const pointclouds = viewer.scene.pointclouds.filter(pc => !pc.isSplat)
  193. const visiblePointClouds2 = pointclouds.filter(pc => pc.visible/* Potree.Utils.getObjVisiByReason(pc,'datasetSelection') */ ); //需要绘制到rtEDL的
  194. const showPointClouds = params.magnifier ? visiblePointClouds2.length>0 : pointclouds.some(e=>e.visible) //是否有需要绘制到屏幕的
  195. /* visiblePointClouds2.forEach(e=>{//为了绘制到depthTexture,先显示(展示全景图时隐藏了点云,所以需要显示下 )
  196. e.oldVisi = e.visible
  197. e.visible = true;
  198. }) */
  199. //好难写- -,太多东西了,无depTex时要把不显示的点云和模型绘制到rt上,但是rt又可能直接绘制到画面。有的模型是要在全景模式显示的
  200. //所以决定去掉不显示的点云,无深度图的话就无遮挡 http://192.168.0.21/index.php?m=bug&f=view&bugID=49575
  201. Potree.Utils.setCameraLayers(camera, ['pointcloud']) //设置多少都会渲染出来,因为渲染里没有sort
  202. //camera.layers.set(Potree.config.renderLayers.pointcloud);
  203. //TODO adapt to multiple lights
  204. //this.renderShadowMap(visiblePointClouds2, camera, lights); //???????
  205. {
  206. for (let pointcloud of visiblePointClouds2) {
  207. let material = pointcloud.material;
  208. let octreeSize = pointcloud.pcoGeometry.boundingBox.getSize(new THREE.Vector3()).x;
  209. material.fov = THREE.Math.degToRad(camera.fov)
  210. material.resolution = resolution
  211. material.spacing = pointcloud.pcoGeometry.spacing; // * Math.max(this.scale.x, this.scale.y, this.scale.z);
  212. material.near = camera.near;
  213. material.far = camera.far;
  214. material.uniforms.octreeSize.value = octreeSize
  215. if(useEDL ){
  216. material.useEDL = true;
  217. //material.fakeEDL = false; //add
  218. }else{
  219. material.useEDL = false;
  220. //material.fakeEDL = true; //add 使也输出深度
  221. }
  222. }
  223. if(rtEDL ){ //借用rtEDL存储深度信息
  224. renderer.setRenderTarget( rtEDL );
  225. if(visiblePointClouds2.length>0){ //渲染scenePointCloud到rtEDL
  226. pRenderer.render(viewer.scene.scenePointCloud, camera, rtEDL, {
  227. shadowMaps: lights.length > 0 ? [this.shadowMap] : null,
  228. clipSpheres: viewer.scene.volumes.filter(v => (v instanceof SphereVolume)),
  229. transparent: false, // 因透明时不写深度,所以不透明。 这也导致透明时不能直接使用rtEDL绘制到屏幕
  230. notAdditiveBlending: Potree.settings.notAdditiveBlending
  231. });
  232. }
  233. if(Potree.settings.intersectOnObjs){
  234. Potree.Utils.setCameraLayers(camera, ['model','light'])
  235. viewer.objs.traverse(e=>{if(e.material)e._OlddepthWrite = e.material.depthWrite, e.material.depthWrite = true}) //否则半透明的mesh无法遮住测量线
  236. renderer.render(viewer.scene.scene, camera);
  237. viewer.objs.traverse(e=>{if(e.material)e.material.depthWrite = e._OlddepthWrite})
  238. }
  239. }
  240. }
  241. //渲染到rtEDL完毕
  242. viewer.dispatchEvent({type: "render.pass.scene", viewer: viewer });
  243. renderer.setRenderTarget( target );
  244. /* if(!params.magnifier)visiblePointClouds2.forEach(e=>{//放大镜显示点云
  245. e.visible = e.oldVisi
  246. }) */
  247. {//绘制点云到画布
  248. if(useEDL){ //设置edlMaterial //Features.EXT_DEPTH不支持的话不会到这一块
  249. if(showPointClouds){
  250. const uniforms = this.edlMaterial.uniforms;
  251. uniforms.resolution.value.copy(resolution)
  252. uniforms.edlStrength.value = viewer.edlStrength;
  253. uniforms.radius.value = viewer.edlRadius;
  254. uniforms.useEDL.value = 1;//add
  255. let proj = camera.projectionMatrix;
  256. let projArray = new Float32Array(16);
  257. projArray.set(proj.elements);
  258. uniforms.uProj.value = projArray;
  259. uniforms.uEDLColor.value = rtEDL.texture;
  260. uniforms.opacity.value = viewer.edlOpacity; // HACK
  261. Utils.screenPass.render(renderer, this.edlMaterial, target); //相当于一个描边后期特效。 缺点: 因为target上的没有抗锯齿,所以点云在晃动镜头时会不稳定地闪烁1px位置。优点:比不打开edl少绘制一次点云,更流畅了?!
  262. }
  263. }else if(this.canUseRTPoint() && rtEDL ){
  264. //半透明点云在clearAlpha为非1的状态下截图 或 在useRTPoints时绘制到屏幕上透明度不对,亮度变低 。深度值遮挡也不对。 只能在半透明时关闭一下useRTPoint
  265. this.recoverToScreenMat.uniforms.tDiffuse.value = rtEDL.texture;
  266. if(this.recoverToScreenMat.defines.useDepth){
  267. this.recoverToScreenMat.uniforms.depthTex.value = rtEDL.depthTexture;
  268. }
  269. Utils.screenPass.render(renderer, this.recoverToScreenMat, target/* , Potree.settings.useFxaa && viewer.composer2 */);
  270. //这时候 params_.useModelOnRT 应该和 Potree.settings.intersectOnObjs 相等 否则出错
  271. }else{
  272. //渲染点云 (直接用rtEDL上的会失去抗锯齿, 导致频闪、密集时出现条纹, 自己写抗锯齿也要渲染好几次。另外透明度也要处理下)
  273. if(showPointClouds){
  274. let prop = {
  275. shadowMaps: lights.length > 0 ? [this.shadowMap] : null,
  276. clipSpheres: viewer.scene.volumes.filter(v => (v instanceof SphereVolume)) ,
  277. notAdditiveBlending: Potree.settings.notAdditiveBlending//add 否则透明的点云会挡住后面的模型。 加上这句后竟然透明不会叠加了!
  278. }
  279. pRenderer.render(viewer.scene.scenePointCloud, camera, null , prop);
  280. }
  281. }
  282. }
  283. /* visiblePointClouds2.forEach(e=>{
  284. e.visible = e.oldVisi
  285. }) */
  286. //viewer.dispatchEvent({type: "render.pass.end",viewer: viewer});
  287. }
  288. /*
  289. 渲染顺序:
  290. 底层:背景 -> skybox(也可中间)
  291. 中间层(含有深度信息):1 点云、marker等mesh,
  292. 2 测量线(现在被做成借用depthTex
  293. 顶层:maginifier
  294. magnifier的贴图渲染不需要顶层、中间层只需要点云。
  295. */
  296. }