import * as THREE from "../../../libs/three.js/build/three.module.js"; import Common from '../utils/Common.js' import {Features} from "../../Features.js"; const prefixVertex ="precision highp float;\nprecision highp int;\n\nuniform mat4 modelMatrix;\nuniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\nuniform mat4 viewMatrix;\nuniform mat3 normalMatrix;\nuniform vec3 cameraPosition;\n attribute vec3 position;\n attribute vec3 normal;\n attribute vec2 uv;\n" const prefixFragment ="precision highp float;\nprecision highp int;\n\nuniform mat4 viewMatrix;\nuniform vec3 cameraPosition;\n" let shader = { uniforms: { opacity: { type: "f", // value: 1 }, progress: { type: "f", value: 0 }, pano0Map: { type: "t", value: null }, pano1Map: { type: "t", value: null }, depthMap0: { type: "t", value: null }, depthMap1: { type: "t", value: null }, pano0Position: { type: "v3", value: new THREE.Vector3 }, pano0Matrix: { type: "m4", value: new THREE.Matrix4 }, pano1Position: { type: "v3", value: new THREE.Vector3 }, pano1Matrix: { type: "m4", value: new THREE.Matrix4 }, /* pano1Matrix2: { type: "m4", value: new THREE.Matrix4 }, */ inverseProjectionMatrix: { value: new THREE.Matrix4 }, /* projectionMatrix:{//需要再写一遍吗 value: new THREE.Matrix4 }, */ viewport: { value: new THREE.Vector4 }, //如 {x: 0, y: 0, z: 428, w: 969} xy应该是offset, zw是宽高 cameraHeight0: { type: "f", value: 1 }, cameraHeight1: { type: "f", value: 1 }, ceilHeight0:{ type: "f", value: 2 }, ceilHeight1:{ type: "f", value: 2 }, }, vertexShader: prefixVertex + ` uniform vec3 pano0Position; uniform mat4 pano0Matrix; uniform vec3 pano1Position; uniform mat4 pano1Matrix; varying vec2 vUv; varying vec3 vWorldPosition0; varying vec3 vWorldPosition1; varying vec3 vWorldPosition12; vec3 transformAxis( vec3 direction ) //navvis->4dkk { float y = direction.y; direction.y = direction.z; direction.z = -y; return direction; } void main() { vUv = uv; vec4 worldPosition = modelMatrix * vec4(position, 1.0); vec3 positionLocalToPanoCenter0 = worldPosition.xyz - pano0Position; vWorldPosition0 = (vec4(positionLocalToPanoCenter0, 1.0) * pano0Matrix).xyz; vWorldPosition0.x *= -1.0; vWorldPosition0 = transformAxis(vWorldPosition0); vec3 positionLocalToPanoCenter1 = worldPosition.xyz - pano1Position; vWorldPosition1 = (vec4(positionLocalToPanoCenter1, 1.0) * pano1Matrix).xyz; vWorldPosition1.x *= -1.0; vWorldPosition1 = transformAxis(vWorldPosition1); /* vec3 positionLocalToPanoCenter12 = worldPosition.xyz - pano1Position; vWorldPosition12 = (vec4(positionLocalToPanoCenter12, 1.0) * pano1Matrix2).xyz; vWorldPosition12.x *= -1.0; vWorldPosition12 = transformAxis(vWorldPosition12); */ gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); } `, fragmentShader: prefixFragment + ` #extension GL_EXT_frag_depth : enable // otherwise error: 'GL_EXT_frag_depth' : extension is disabled #define PI 3.141592653 uniform float modelAlpha; uniform float opacity; uniform float progress; uniform int tranType; uniform vec3 pano0Position; uniform vec3 pano1Position; uniform float maxDistance; uniform float minDistance; uniform float minOpa; uniform samplerCube pano0Map; uniform samplerCube pano1Map; varying vec2 vUv; varying vec3 vWorldPosition0; varying vec3 vWorldPosition1; /* vec2 getSamplerCoord( vec3 direction ) { direction = normalize(direction); float tx=atan(direction.x,-direction.y)/(PI*2.0)+0.5; float ty=acos(direction.z)/PI; return vec2(tx,ty); } */ vec2 getSamplerCoord2( vec3 direction ) { direction = normalize(direction); float tx=atan(direction.x,direction.z)/(PI*2.0)+0.5; float ty=acos(direction.y)/PI; return vec2(tx,ty); } #if defined(GL_EXT_frag_depth) && defined(hasDepthTex) uniform sampler2D depthMap0; uniform sampler2D depthMap1; uniform mat4 inverseProjectionMatrix; uniform mat4 projectionMatrix; uniform vec4 viewport; uniform float cameraHeight0; uniform float cameraHeight1; uniform float ceilHeight0; uniform float ceilHeight1; vec2 getDepth(vec3 dir, sampler2D depthMap, float heightDown, float heightUp, vec4 eyePos){ vec2 depthValue = vec2(0.0, 0.0); vec2 uv2 = getSamplerCoord2( dir.xyz); //暂时只用基于目标漫游点的方向 uv2.x -= 0.25; //全景图和Cube的水平采样起始坐标相差90度,这里矫正 0.25 个采样偏移 vec4 depth = texture2D(depthMap, uv2); //float distance = depth.r + 256. * (depth.g + 256. * depth.b); //distance *= 255. * .001; // distance is now in meters //更改 float distance = (depth.g + depth.r / 256.) * 255.; if(distance == 0.0){//漫游点底部识别不到的区域,给一个地板高度 if(uv2.y < depthTexUVyLimit) distance = heightUp / dir.y; else if(uv2.y > 1.0 - depthTexUVyLimit) distance = heightDown / -dir.y; else distance = 100000.0;//给个超级远的值 } if(distance == 0.0)distance = 100000.0;//给个超级远的值 depthValue.x = distance; distance += .1; // add a safety margin vec4 eyePos2 = vec4(normalize(eyePos.xyz) * distance, 1.); vec4 clipPos2 = projectionMatrix * eyePos2; vec4 ndcPos2 = clipPos2 * 1. / clipPos2.w; depthValue.y = 0.5 * ((gl_DepthRange.far - gl_DepthRange.near) * ndcPos2.z + gl_DepthRange.near + gl_DepthRange.far); return depthValue; } //注:未加载好的话,depth为0,导致第一次漫游过去的时候许多mesh会立刻被遮挡,所以要确保加载完 #endif void main() { vec3 vWorldPosition0N = normalize(vWorldPosition0); vec3 vWorldPosition1N = normalize(vWorldPosition1); float progress_ = progress; vec4 colorFromPano0 = vec4(0.0,0.0,0.0,0.0); #if defined(usePanoMap0) //即progress < 1.0 通常是1 colorFromPano0=textureCube(pano0Map,vWorldPosition0N.xyz); #else progress_ = 1.0; #endif vec4 colorFromPano1=textureCube(pano1Map,vWorldPosition1N.xyz); gl_FragColor = mix(colorFromPano0,colorFromPano1,progress_); //深度图修改深度 #if defined(GL_EXT_frag_depth) && defined(hasDepthTex) vec4 ndcPos; ndcPos.xy = ((2.0 * gl_FragCoord.xy) - (2.0 * viewport.xy)) / (viewport.zw) - 1.; ndcPos.z = (2.0 * gl_FragCoord.z - gl_DepthRange.near - gl_DepthRange.far) / (gl_DepthRange.far - gl_DepthRange.near); ndcPos.w = 1.0; vec4 clipPos = ndcPos / gl_FragCoord.w; vec4 eyePos = inverseProjectionMatrix * clipPos; vec2 depth0 = vec2(0.0,0.0); #if defined(usePanoMap0) depth0 = getDepth(vWorldPosition0N, depthMap0, cameraHeight0, ceilHeight0, eyePos); #endif vec2 depth1 = getDepth(vWorldPosition1N, depthMap1, cameraHeight1, ceilHeight1, eyePos); gl_FragDepthEXT = mix(depth0.y,depth1.y,progress_); gl_FragDepthEXT = clamp(gl_FragDepthEXT, 0.0, 1.0); //防止部分手机出现黑块。ios 16 。 因为我给的超远值超出范围 #endif } ` } //注:gl_FragDepthEXT 修改了确实能像真实mesh那样遮挡住在后面的物体。但是为过渡时不能直接像有模型那样,和角度有关。 export default class ModelTextureMaterial extends THREE.RawShaderMaterial { constructor( ){ let defines = {depthTexUVyLimit: Potree.config.depthTexUVyLimit} let {vs,fs} = Common.changeShaderToWebgl2(shader.vertexShader, shader.fragmentShader, 'RawShaderMaterial') super({ fragmentShader: fs, vertexShader: vs, uniforms: THREE.UniformsUtils.clone(shader.uniforms), side:THREE.DoubleSide, name: "ModelTextureMaterial", defines, }) this.glslVersion = Potree.settings.isWebgl2 && '300 es' let setSize = (e)=>{ let viewport = e.viewport //let viewportOffset = viewport.offset || new Vector2() let resolution = viewport.resolution2 //this.uniforms.viewport.value.set(viewportOffset.x, viewportOffset.y, resolution.x, resolution.y) this.uniforms.viewport.value.set(0,0, resolution.x, resolution.y);// xy是在viewport中的left和bottom,和整个窗口没有关系,所以不是viewportOffset。几乎都是0,0 } let viewport = viewer.mainViewport; setSize({viewport}) viewer.addEventListener('resize',(e)=>{ if(e.viewport.name != "MainView")return setSize(e) }) //var supportExtDepth = !!Features.EXT_DEPTH.isSupported() { //add viewer.addEventListener('camera_changed', (e)=>{ if(e.viewport.name != "MainView")return //this.uniforms.projectionMatrix.value.copy(e.camera.projectionMatrix) e.camera && this.uniforms.inverseProjectionMatrix.value.copy(e.camera.projectionMatrixInverse) }) } let progress = 0 Object.defineProperty(this.uniforms.progress, 'value', { get: function () { return progress }, set: e => { if (e < 1 && !Potree.settings.fastTran ) { if (!('usePanoMap0' in this.defines)) { this.defines.usePanoMap0 = '' this.needsUpdate = true } } else { if ('usePanoMap0' in this.defines) { delete this.defines.usePanoMap0 this.needsUpdate = true } } progress = e }, }) //------------------------------------- } /** * * @param {Panorama} pano0 * @param {Panorama} pano1 * @param {boolean} flag 更新全景图的材质uniforms */ setProjectedPanos(pano0, pano1, progressValue ){ progressValue!=void 0 && (this.uniforms.progress.value = progressValue); //pano0.ensureSkyboxReadyForRender(); if(pano0){ this.uniforms.pano0Map.value = pano0.getSkyboxTexture();//pano0.texture this.uniforms.pano0Position.value.copy(pano0.position) this.uniforms.pano0Matrix.value.copy(pano0.panoMatrix/* pano0.mesh.matrixWorld */ ); //pano1.ensureSkyboxReadyForRender(); } this.uniforms.pano1Map.value = pano1.getSkyboxTexture()//pano1.texture; this.uniforms.pano1Position.value.copy(pano1.position) this.uniforms.pano1Matrix.value.copy(pano1.panoMatrix /* pano1.mesh.matrixWorld */ ); this.pano0 = pano0 this.pano1 = pano1 this.updateDepthTex(pano0) this.updateDepthTex(pano1) //console.log('setProjectedPanos', pano0&&pano0.id, pano1&&pano1.id) this.needsUpdate = true; } updateDepthTex(pano, extra){ if( !Potree.settings.useDepthTex || !pano || !pano.depthTex || pano!=this.pano0 && pano!=this.pano1)return //console.log('updateDepthTex', pano.id, this.pano0 && this.pano0.id, this.pano1 && this.pano1.id) if(this.pano0){ this.uniforms.depthMap0.value = this.pano0.entered ? this.pano0.depthTex : null; //dispose了就不要赋值否则dispose会失败 this.uniforms.cameraHeight0.value = this.pano0.floorPosition.distanceTo(this.pano0.position) this.uniforms.ceilHeight0.value = this.pano0.getCeilHeight() - this.pano0.position.z } if(this.pano1){ this.uniforms.depthMap1.value = this.pano1.depthTex //pano1还没entered时也需要,可能在飞入 this.uniforms.cameraHeight1.value = this.pano1.floorPosition.distanceTo(this.pano1.position) this.uniforms.ceilHeight1.value = this.pano1.getCeilHeight() - this.pano1.position.z } this.updateDepthTexEnable() } updateDepthTexEnable(){ let hasDepthTex = this.pano0 && this.pano1 && this.pano0.pointcloud.hasDepthTex && this.pano1.pointcloud.hasDepthTex //暂时不知道一个有图一个没图怎么写所以 Potree.Utils.addOrRemoveDefine(this, 'hasDepthTex', hasDepthTex?'add':'remove' ) } /* EnableDepthTex(){//开启DepthTex if(this.defines['hasDepthTex']){ return } this.defines['hasDepthTex'] = '' this.needsUpdate = true; } */ }