import * as THREE from "../../libs/three.js/build/three.module.js"; import {PointCloudSM} from "../utils/PointCloudSM.js"; import {EyeDomeLightingMaterial} from "../materials/EyeDomeLightingMaterial.js"; import {SphereVolume} from "../objects/tool/Volume.js"; import {Utils} from "../utils.js"; import {copyShader} from '../materials/shaders/otherShaders.js' import {Features} from "../Features.js"; export class EDLRenderer{//Eye-Dome Lighting 眼罩照明 constructor(viewer){ this.viewer = viewer; this.edlMaterial = null; //this.rtRegular; this.rtEDLs = new Map this.gl = viewer.renderer.getContext(); //反正也没用到,注释了: //this.shadowMap = new PointCloudSM(this.viewer.pRenderer); viewer.addEventListener('resize',this.resize.bind(this)) this.initEDL(viewer) } initEDL(viewer){ if (this.edlMaterial != null) { return; } this.edlMaterial = new EyeDomeLightingMaterial(); this.edlMaterial.depthTest = true; this.edlMaterial.depthWrite = true; this.edlMaterial.transparent = true; /* this.rtRegular = new THREE.WebGLRenderTarget(viewer.mainViewport.resolution2.x, viewer.mainViewport.resolution2.y, { minFilter: THREE.NearestFilter, magFilter: THREE.NearestFilter, format: THREE.RGBAFormat, depthTexture: new THREE.DepthTexture(undefined, undefined, THREE.UnsignedIntType) }); */ /* let copyUniforms = THREE.UniformsUtils.clone( copyShader.uniforms ); this.copyMaterial = new THREE.ShaderMaterial( { uniforms: copyUniforms, vertexShader: copyShader.vertexShader, fragmentShader: copyShader.fragmentShader, //premultipliedAlpha: true, transparent: true, //blending: THREE.AdditiveBlending, depthTest: false, depthWrite: false }); */ }; resize(e ){ if(Features.EXT_DEPTH.isSupported()){ let viewport = e.viewport this.getRtEDL(viewport).setSize(viewport.resolution2.x, viewport.resolution2.y); } } clearTargets(params={}){ const viewer = this.viewer; const {renderer} = viewer; const oldTarget = renderer.getRenderTarget(); if(params.target){//add renderer.setRenderTarget( params.target); renderer.clear() } if(Features.EXT_DEPTH.isSupported()){ if(params.rtEDL){ renderer.setRenderTarget( params.rtEDL); renderer.clear() }else{ var rtEDL = this.getRtEDL(params.viewport) if(rtEDL){ renderer.setRenderTarget( rtEDL ); renderer.clear( true, true, true ); } } } //renderer.setRenderTarget( this.rtRegular ); //renderer.clear( true, true, false ); renderer.setRenderTarget(oldTarget); } getRtEDL(viewport){//根据不同viewport返回rtEDL的texture if(!viewport){ console.warn('getRtEDL没传viewport!!!! !!!!!!!!!!') viewport = viewer.mainViewport } var rtEDL = this.rtEDLs.get(viewport) if(!rtEDL){ if(Features.EXT_DEPTH.isSupported()){ rtEDL = new THREE.WebGLRenderTarget(viewport.resolution2.x, viewport.resolution2.y, { minFilter: THREE.NearestFilter, magFilter: THREE.NearestFilter, format: THREE.RGBAFormat, type: THREE.FloatType, depthTexture: new THREE.DepthTexture(undefined, undefined, THREE.UnsignedIntType) }); //注: 部分手机在resize时会崩溃,经检验去掉rtEDL的resize可以解决,所以更应该注释掉这个 this.rtEDLs.set(viewport, rtEDL) } } return rtEDL } renderShadowMap(visiblePointClouds, camera, lights){ const {viewer} = this; const doShadows = lights.length > 0 && !(lights[0].disableShadowUpdates); if(doShadows){ let light = lights[0]; this.shadowMap.setLight(light); let originalAttributes = new Map(); for(let pointcloud of viewer.scene.pointclouds){ // TODO IMPORTANT !!! check originalAttributes.set(pointcloud, pointcloud.material.activeAttributeName); pointcloud.material.disableEvents(); pointcloud.material.activeAttributeName = "depth"; //pointcloud.material.pointColorType = PointColorType.DEPTH; } this.shadowMap.render(viewer.scene.scenePointCloud, camera); for(let pointcloud of visiblePointClouds){ let originalAttribute = originalAttributes.get(pointcloud); // TODO IMPORTANT !!! check pointcloud.material.activeAttributeName = originalAttribute; pointcloud.material.enableEvents(); } viewer.shadowTestCam.updateMatrixWorld(); viewer.shadowTestCam.matrixWorldInverse.copy(viewer.shadowTestCam.matrixWorld).invert(); viewer.shadowTestCam.updateProjectionMatrix(); } } render(params={}){ /* 渲染顺序: 底层:背景 -> skybox(也可中间) 中间层(含有深度信息):1 点云、marker等mesh, 2 测量线(现在被做成借用depthTex 顶层:maginifier magnifier的贴图渲染不需要顶层、中间层只需要点云。 */ const viewer = this.viewer; let camera = params.camera ? params.camera : viewer.scene.getActiveCamera(); const resolution = params.viewport ? params.viewport.resolution2 : this.viewer.renderer.getSize(new THREE.Vector2()); //viewer.dispatchEvent({type: "render.pass.begin",viewer: viewer}); let lights = []; /* viewer.scene.scene.traverse(node => { if(node.type === "SpotLight"){ lights.push(node); } }); */ viewer.renderer.setRenderTarget(params.target || null); let background = params.background || viewer.background; let backgroundOpacity = params.backgroundOpacity == void 0 ? viewer.backgroundOpacity : params.backgroundOpacity//如果想完全透明,只需要backgroundOpacity为0 if(backgroundOpacity != 0){//绘制背景 if(background === "skybox"){ viewer.skybox.camera.rotation.copy(viewer.scene.cameraP.rotation); viewer.skybox.camera.fov = viewer.scene.cameraP.fov; viewer.skybox.camera.aspect = viewer.scene.cameraP.aspect; viewer.skybox.parent.rotation.x = 0; viewer.skybox.parent.updateMatrixWorld(); viewer.skybox.camera.updateProjectionMatrix(); viewer.renderer.render(viewer.skybox.scene, viewer.skybox.camera); }else if(background === 'gradient'){ viewer.scene.cameraBG.layers.set(Potree.config.renderLayers.bg); viewer.renderer.render(viewer.scene.scene, viewer.scene.cameraBG); }else if(background === 'overlayColor'){//在不clear的前提下加一层背景色 viewer.scene.bg2.material.color.copy(params.backgroundColor) viewer.scene.bg2.material.opacity = params.backgroundOpacity viewer.scene.cameraBG.layers.set(Potree.config.renderLayers.bg2); viewer.renderer.render(viewer.scene.scene, viewer.scene.cameraBG); } } //skybox 全景图 if(!params.magnifier){ viewer.setCameraLayers(camera, ['skybox']) let useDepthTex if(Potree.settings.displayMode == 'showPanos' && viewer.images360.currentPano.pointcloud.hasDepthTex && Features.EXT_DEPTH.isSupported()){//渲染深度图 useDepthTex = true viewer.renderer.setRenderTarget(params.rtEDL || this.getRtEDL(params.viewport)) //将带有深度图的skybox画在rtEDL一下,这样就不需要绘制后边的点云了 viewer.renderer.render(viewer.scene.scene, camera); viewer.renderer.setRenderTarget(params.target || null); } viewer.renderer.render(viewer.scene.scene, camera); if(useDepthTex)return } const visiblePointClouds2 = viewer.scene.pointclouds.filter(pc => viewer.getObjVisiByReason(pc,'datasetSelection') ); //需要绘制到rtEDL的 const showPointClouds = params.magnifier ? visiblePointClouds2.length>0 : viewer.scene.pointclouds.some(e=>e.visible) //是否有需要绘制到屏幕的 visiblePointClouds2.forEach(e=>{//为了绘制到depthTexture,先显示(展示全景图时隐藏了点云,所以需要显示下。且放大镜需要绘制点云) e.oldVisi = e.visible e.visible = true; }) viewer.setCameraLayers(camera, ['pointcloud']) camera.layers.set(Potree.config.renderLayers.pointcloud); //TODO adapt to multiple lights //this.renderShadowMap(visiblePointClouds2, camera, lights); //??????? { for (let pointcloud of visiblePointClouds2) { let material = pointcloud.material; let octreeSize = pointcloud.pcoGeometry.boundingBox.getSize(new THREE.Vector3()).x; material.fov = THREE.Math.degToRad(camera.fov) /* material.screenWidth = width; material.screenHeight = height; */ material.resolution = resolution material.spacing = pointcloud.pcoGeometry.spacing; // * Math.max(this.scale.x, this.scale.y, this.scale.z); material.near = camera.near; material.far = camera.far; material.uniforms.octreeSize.value = octreeSize if(viewer.useEDL && Potree.settings.displayMode != 'showPanos'){ /* material.weighted = false; material.useLogarithmicDepthBuffer = false; */ material.useEDL = true; //material.fakeEDL = false; //add }else{ material.useEDL = false; //material.fakeEDL = true; //add 使也输出深度 } } if(Features.EXT_DEPTH.isSupported() && !params.dontRenderRtEDL){ //借用rtEDL存储深度信息 viewer.renderer.setRenderTarget(params.rtEDL || this.getRtEDL(params.viewport)/* this.rtEDL */); if(visiblePointClouds2.length>0){ //渲染scenePointCloud到rtEDL viewer.pRenderer.render(viewer.scene.scenePointCloud, camera, params.rtEDL || this.getRtEDL(params.viewport), { shadowMaps: lights.length > 0 ? [this.shadowMap] : null, clipSpheres: viewer.scene.volumes.filter(v => (v instanceof SphereVolume)), transparent: false, }); } if(Potree.settings.intersectOnObjs){// model也要渲染到rtEDL camera.layers.set(Potree.config.renderLayers.model); viewer.objs.traverse(e=>{if(e.material)e._OlddepthWrite = e.material.depthWrite, e.material.depthWrite = true}) //否则半透明的mesh无法遮住测量线 viewer.renderer.render(viewer.scene.scene, camera); viewer.objs.traverse(e=>{if(e.material)e.material.depthWrite = e._OlddepthWrite}) //缺点:半透明的model 就算完全透明, 也会遮住测量线 } //test /* { viewer.objs.traverse((obj)=>{ if(obj.material){ obj.material = obj.depthMat } }) viewer.setCameraLayers(camera, ['sceneObjects']) viewer.renderer.render(viewer.scene.scene, camera) viewer.objs.traverse((obj)=>{ if(obj.material){ obj.material = obj.standardMat } }) } */ } } //渲染到rtEDL完毕 viewer.dispatchEvent({type: "render.pass.scene", viewer: viewer/* , renderTarget: this.rtRegular */}); viewer.renderer.setRenderTarget(params.target || null); if(!params.magnifier)visiblePointClouds2.forEach(e=>{//放大镜显示点云 e.visible = e.oldVisi }) if(showPointClouds){ //绘制点云到画布 if(viewer.useEDL) { //设置edlMaterial //Features.EXT_DEPTH不支持的话不会到这一块 const uniforms = this.edlMaterial.uniforms; //if(viewer.useEDL){ /* uniforms.screenWidth.value = width; uniforms.screenHeight.value = height; */ uniforms.resolution.value.copy(resolution) uniforms.edlStrength.value = viewer.edlStrength; uniforms.radius.value = viewer.edlRadius; uniforms.useEDL.value = 1;//add /* }else{ uniforms.useEDL.value = 0;//add } */ let proj = camera.projectionMatrix; let projArray = new Float32Array(16); projArray.set(proj.elements); uniforms.uProj.value = projArray; uniforms.uEDLColor.value = (params.rtEDL || this.getRtEDL(params.viewport)).texture; //uniforms.uEDLDepth.value = (params.rtEDL || this.getRtEDL(params.viewport)).depthTexture; //其实没用到 uniforms.opacity.value = viewer.edlOpacity; // HACK Utils.screenPass.render(viewer.renderer, this.edlMaterial, params.target); }else{ //渲染点云 (直接用rtEDL上的会失去抗锯齿) let prop = { shadowMaps: lights.length > 0 ? [this.shadowMap] : null, clipSpheres: viewer.scene.volumes.filter(v => (v instanceof SphereVolume)) , notAdditiveBlending: Potree.settings.notAdditiveBlending//add 否则透明的点云会挡住后面的模型。 加上这句后竟然透明不会叠加了! } viewer.pRenderer.render(viewer.scene.scenePointCloud, camera, null , prop); } } //viewer.dispatchEvent({type: "render.pass.end",viewer: viewer}); visiblePointClouds2.forEach(e=>{ e.visible = e.oldVisi }) } }