| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650 |
- import * as THREE from "../../../libs/three.js/build/three.module.js";
- import Common from '../utils/Common.js'
- import math from '../utils/math.js'
- import {Features} from "../../Features.js";
- import {ExtendPointCloudMaterial} from "../../materials/ExtendPointCloudMaterial.js";
- import {Gradients} from "../../materials/Gradients.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 ="#extension GL_EXT_frag_depth : enable \n precision highp float;\nprecision highp int;\n\nuniform mat4 viewMatrix;\nuniform vec3 cameraPosition;\n"
- // otherwise error: 'GL_EXT_frag_depth' : extension is disabled
-
- let getClassificationLUT = ()=>{
- const [width, height] = [256, 1];
- let data = new Uint8Array(width * 4);
- let tex = new THREE.DataTexture(data, width, height, THREE.RGBAFormat);
- tex.magFilter = THREE.NearestFilter;
- tex.needsUpdate = true;
- return tex
- }
- 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
- },
- pano0ClassMap: {
- type: "t",
- value: null
- },
- pano1ClassMap: {
- type: "t",
- value: null
- },
- pano0TempMap: {
- type: "t",
- value: null
- },
- pano1TempMap: {
- type: "t",
- value: null
- },
- gradient: {
- type: "t",
- value: null
- },
- classificationLUT: {
- 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
- },
- temperRange:{//温度范围
- type:'vec2',
- value: new THREE.Vector2(math.getKelvinFromCelsius(15), math.getKelvinFromCelsius(60) )
- }
- },
-
- 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 + `
-
-
- #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;
- #if defined(useTempMap0) || defined(useTempMap1)
- uniform sampler2D gradient;
- uniform vec2 temperRange;
- #endif
- #if defined(useClassMap0) || defined(useClassMap1)
- uniform sampler2D classificationLUT;
- #endif
- #if defined(useTempMap0)
- uniform sampler2D pano0TempMap;
- #endif
- #if defined(useTempMap1)
- uniform sampler2D pano1TempMap;
- #endif
- #if defined(useClassMap0)
- uniform sampler2D pano0ClassMap;
- #endif
- #if defined(useClassMap1)
- uniform sampler2D pano1ClassMap;
- #endif
- 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);
-
- #if defined(depth_background)
- //后排的 skybox 不能挡住chunk
- depthValue.y += 0.3;
- #endif
-
-
-
- return depthValue;
- }
- //注:未加载好的话,depth为0,导致第一次漫游过去的时候许多mesh会立刻被遮挡,所以要确保加载完
- #endif
-
- int unpack16(vec2 channels){
- return int(round(channels.y * 255.0)) + (int(round(channels.x * 255.0)) << 8) ; //some phone needs round,such as vivo x30
- }
-
- int getIntFromColor(sampler2D map, vec3 dir){//uint16-> int 0-65536
- //float texWidth = 1024.;
- vec2 uv = getSamplerCoord2(dir.xyz);
- uv.x -= 0.25;
- vec4 color = texture2D(map, uv);
- return unpack16(color.rg);
- /* if( fract(uv.x * texWidth) > 0.5){
- return unpack16(color.rg);
- }else{
- return unpack16(color.ba);
- } */
-
- }
-
-
- /*vec4 getColorFromMap(sampler2D map, vec3 dir){
- vec2 uv = getSamplerCoord2(dir.xyz);
- uv.x -= 0.25;
- vec4 color = texture2D(map, uv);
- return color;
- }*/
-
-
- //ir热成像
- #if defined(useTempMap0) || defined(useTempMap1)
-
- vec4 getTemperature(sampler2D map, vec3 dir){
-
- float temperature = float(getIntFromColor(map, dir))/ 10.0 ;
-
- float w = (temperature - temperRange.x) / (temperRange.y - temperRange.x);
- w = clamp(w,0.0,1.0);
- vec4 color = vec4(texture2D(gradient, vec2(w,1.0-w)).rgb, 1.0);
- return color;
-
- }
- #endif
-
- #if defined(useClassMap0) || defined(useClassMap1)
-
- /*vec4 getClassification(sampler2D map, vec3 dir, vec4 originColor){
- vec4 color = getColorFromMap(map, dir);
- float v = color.r * 255.0;
- if(v<=2.01&&v>=1.99){
- color = vec4(1.0,0.0,0.0,1.0);
- } else{
- color = vec4(0.0,0.0,0.0,1.0);
- }
- return color;
- } */
-
-
-
- vec4 getClassification(sampler2D map, vec3 dir, vec4 originColor){
-
- int classIndex = getIntFromColor(map, dir);
-
- vec2 uv = vec2(float(classIndex) / 255.0, 0.5); //copy from pointcloud_new.vs
- vec4 classColor = texture2D(classificationLUT, uv);
-
- float blendRatio = 0.5;
- float classAlpha = classColor.a * blendRatio;
- vec4 color = vec4(classColor.rgb * classAlpha + originColor.rgb * (1.0-classAlpha), 1.0); //mix with old rgba
- return color;
- }
- #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
-
- #if defined(useTempMap0)
- colorFromPano0 = getTemperature(pano0TempMap,vWorldPosition0N.xyz);
- #else
- colorFromPano0 = textureCube(pano0Map,vWorldPosition0N.xyz);
- #if defined(useClassMap0)
- colorFromPano0 = getClassification(pano0ClassMap,vWorldPosition0N.xyz, colorFromPano0);
- #endif
- #endif
-
- #else
- progress_ = 1.0;
- #endif
-
-
- vec4 colorFromPano1 = vec4(0.0,0.0,0.0,0.0);
- #if defined(useTempMap1)
- colorFromPano1 = getTemperature(pano1TempMap,vWorldPosition1N.xyz);
- #else
- colorFromPano1 = textureCube(pano1Map,vWorldPosition1N.xyz);
- #if defined(useClassMap1)
- colorFromPano1 = getClassification(pano1ClassMap,vWorldPosition1N.xyz, colorFromPano1);
- #endif
- #endif
-
-
- 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);
- vec2 depth1 = vec2(0.0,0.0);
- float depth = 0.0;
-
- bool useDepth0 = false;
- bool useDepth1 = true;
-
-
- #if defined(usePanoMap0)
- useDepth0 = true;
- #if defined(UnableMixTwoDepth)
- if(progress_<0.5){
- useDepth1 = false;
- }else{
- useDepth0 = false;
- }
- #endif
- if(useDepth0) depth0 = getDepth(vWorldPosition0N, depthMap0, cameraHeight0, ceilHeight0, eyePos);
- #endif
-
- if(useDepth1) depth1 = getDepth(vWorldPosition1N, depthMap1, cameraHeight1, ceilHeight1, eyePos);
-
-
- #if defined(UnableMixTwoDepth)
- depth = useDepth0 ? depth0.y : depth1.y;//不支持叠加,只能用其中一个,过渡时无法渐变
- #else
- depth = mix(depth0.y,depth1.y,progress_);
- #endif
- gl_FragDepthEXT = clamp(depth, 0.0, 1.0); //防止部分手机出现黑块。ios 16 。 因为我给的超远值超出范围
-
- #endif
-
- }
- `
- }
-
- //注:gl_FragDepthEXT 修改了确实能像真实mesh那样遮挡住在后面的物体。但是为过渡时不能直接像有模型那样,和角度有关。
-
- export default class ModelTextureMaterial extends THREE.RawShaderMaterial {
- constructor( ){
-
- let defines = {depthTexUVyLimit: Potree.config.depthTexUVyLimit}
- if(Potree.browser.maybeQilin()){
- defines.UnableMixTwoDepth = 1 //该系统在开启硬件加速后,webgl容易出bug。如过渡时黑屏报错,因无法将两个depth叠加。见bug记录
- }
- let {vs,fs} = Common.changeShaderToWebgl2(shader.vertexShader, shader.fragmentShader, 'RawShaderMaterial')
- if(!Potree.settings.isWebgl2){
- defines['round(x)'] = 'floor(x + 0.5)' //webgl1 unsupport round
- fs = fs.replace('int(round(channels.x * 255.0)) << 8', 'int(round(channels.x * 255.0 * pow(2.0, 8.0)))') //unsupport <<
- }
- super({
- fragmentShader: fs,
- vertexShader: vs,
- uniforms: THREE.UniformsUtils.clone(shader.uniforms),
- side:THREE.DoubleSide,
- name: "ModelTextureMaterial",
- defines,
- })
-
- this.glslVersion = Potree.settings.isWebgl2 && '300 es'
- this.uniforms.classificationLUT.value = this.classificationTexture = getClassificationLUT()
-
- 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 setClass = ()=>{
- this.classification = viewer.classifications
- ExtendPointCloudMaterial.prototype.recomputeClassification.call(this)
- }
- viewer.addEventListener('classifications_changed',setClass)
- setClass()
-
-
-
- this._gradient = Gradients.ir //海拔贴图种类,火灾也是这个
- this.uniforms.gradient.value = ExtendPointCloudMaterial.generateGradientTexture(this._gradient);
- }
- 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
- },
- })
- //-------------------------------------
- }
-
-
-
-
- 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)
- this.updateTempEnable()
- this.updateClassEnable()
- //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
- }
-
-
- if(this.dontChangeDepth)return
- let hasDepthTex = this.pano0 && this.pano1 && this.pano0.pointcloud.hasDepthTex && this.pano1.pointcloud.hasDepthTex //暂时不知道一个有图一个没图怎么写所以
- Potree.Utils.addOrRemoveDefine(this, 'hasDepthTex', hasDepthTex?'add':'remove' )
-
-
- }
-
-
-
- updateTempEnable(){
- let tex0 = Potree.settings.showHotTemp && this.pano0.tempTex || Potree.settings.showHotIr && this.pano0.irTex
- let tex1 = Potree.settings.showHotTemp && this.pano1.tempTex || Potree.settings.showHotIr && this.pano1.irTex
- this.uniforms.pano0TempMap.value = tex0
- this.uniforms.pano1TempMap.value = tex1
-
- Potree.Utils.addOrRemoveDefine(this, 'useTempMap0', tex0?'add':'remove' )
- Potree.Utils.addOrRemoveDefine(this, 'useTempMap1', tex1?'add':'remove' )
- viewer.dispatchEvent('content_changed')
- }
- updateClassEnable(){
- let hasClassTex0 = Potree.settings.showClass && this.pano0.segTex
- let hasClassTex1 = Potree.settings.showClass && this.pano1.segTex
- this.uniforms.pano0ClassMap.value = this.pano0.segTex
- this.uniforms.pano1ClassMap.value = this.pano1.segTex
-
- Potree.Utils.addOrRemoveDefine(this, 'useClassMap0', hasClassTex0?'add':'remove' )
- Potree.Utils.addOrRemoveDefine(this, 'useClassMap1', hasClassTex1?'add':'remove' )
- viewer.dispatchEvent('content_changed')
- }
-
-
-
- }
- ModelTextureMaterial.prototype.setTempRange = ExtendPointCloudMaterial.prototype.setTempRange
-
|