123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 |
- import * as THREE from "../../../../libs/three.js/build/three.module.js";
- import math from "../../utils/math.js";
- import browser from "../../utils/browser.js";
- class DepthImageSampler extends THREE.EventDispatcher{
-
- constructor(){
- super()
- var canvas = document.createElement("canvas");
- this.canvas = canvas
- this.context = canvas.getContext("2d")
- this.imgDatas = []
-
- /* document.getElementsByTagName('body')[0].appendChild(canvas);
- canvas.style.position = 'fixed';
- canvas.style.width = '1024px';
- canvas.style.top = canvas.style.left = 0
- canvas.style['z-index'] = 100
- */
- this.maxDataCount = browser.isMobile() ? 6 : 20; //手机会崩溃. 平均每张图为8M数据量(以200个点的园区为例,加载时间久一些后,总内存=700 + 每张图的8M * maxDataCount)
- this.maxNeighCount = browser.isMobile() ? 3 : 14; //包含在maxDataCount内的nearPanos最大个数.至少比maxDataCount少3个,留出空位给最近更新的pano
- this.nearPanos = []
- }
-
- updateNearPanos(panos){
- this.nearPanos = panos.slice(0,this.maxNeighCount)
- }
-
- changeImg(img, pano){
-
- this.pano = pano
- let item = this.imgDatas.find(p=>p.pano == pano)
- if(/* this.img == img || */item){
- //最新的在末尾,所以换到末尾
-
- let index = this.imgDatas.indexOf(item)
- this.imgDatas.splice(index,1)
- this.imgDatas.push(item)
- //console.log('重复使用',item.pano.id)
- return
- }
-
- viewer.addTimeMark('depthSampler','start')
- this.canvas.width = img.width
- this.canvas.height = img.height
- this.context.drawImage(img, 0, 0)
- let data = this.context.getImageData(0, 0, img.width , img.height ).data; //getImageData 1px时 : pc chrome 耗时0.01毫秒左右(排除第一次的50) , 但firefox: 4。但换贴图之后就多达5甚至几十
- //console.log('changeImg',pano.id )
- //this.img = img
-
-
- if(this.imgDatas.length >= this.maxDataCount){
- let old = this.imgDatas.find(e=>!this.nearPanos.includes(e.pano))
- //console.log('推出',old.pano.id)
- this.imgDatas.splice(this.imgDatas.indexOf(old), 1)//推出使用时间最早的一个非nearPano
- }
- this.imgDatas.push({pano, data})
-
-
-
- this.dispatchEvent({type:'changeImg',pano})
- viewer.addTimeMark('depthSampler','end') //耗时chrome 25ms,firefox: 38ms, iphoneX:33ms
-
-
-
- /* pano.depthData = {}
- for(let h=0; h<img.height; h++){
- for(let w=0; w<img.width; w++){
- let blockIndex = img.width * h + w
- let r = data.slice(blockIndex*4, (blockIndex+1)*4)
- let depth = r[1] + r[0] / 256
- if(depth>0) pano.depthData[h+'|'+w] = depth
- }
- } */
-
- }
-
-
- getDepth( UVx, UVy) {//根据图片像素获取深度值
- var x = Math.round(UVx * (this.canvas.width - 1))
- , y = Math.round(UVy * (this.canvas.height - 1));
-
-
- if (!(x < 0 || y < 0 || x >= this.canvas.width || y >= this.canvas.height)) {
-
- /* viewer.addTimeMark('depthSampler','start')
-
- var r = this.context.getImageData(x, y, 1, 1).data; //pc chrome 耗时0.01毫秒左右(排除第一次的50) , 但firefox: 4。但换贴图之后就多达5甚至几十
-
- viewer.addTimeMark('depthSampler','end')
-
-
- //console.log('color', r, x,y)
- return r[1] + r[0] / 256 */
- let imgData = this.imgDatas.find(p=>p.pano == this.pano)
- let blockIndex = this.canvas.width * y + x
- let color = imgData.data.slice(blockIndex*4, (blockIndex+1)*4)
- return color[1] + color[0] / 256
-
- }
- }
-
-
-
- sample( intersect, currentPano, onlyPos ) {//通过和skybox的intersect得到真实的intersect的位置
- if(!intersect)return
-
-
-
- let location = new THREE.Vector3
- let normal
- currentPano = currentPano || viewer.images360.currentPano
-
- //let markName
-
-
- if(currentPano != this.currentPano){
- if(!currentPano.depthTex/* || !currentPano.depthTex.image */) return //未加载
-
- /* markName = 'depthSampleChangeTex'
- viewer.addTimeMark(markName,'start') */
- this.changeImg(currentPano.depthTex.image, currentPano)
- this.currentPano = currentPano
- }/* else{
- markName = 'depthSampleSame'
- viewer.addTimeMark(markName,'start')
- } */
-
- let origin = currentPano.position
- let dir = intersect.dir || new THREE.Vector3().subVectors(intersect.point, origin).normalize()
- //var uv = intersect.uv
- //let dirInPano = math.getNormalDir(dir, currentPano)//转化为考虑漫游点旋转的方向
-
- let dirInPano = dir.clone().applyMatrix4(currentPano.panoMatrix2Inverse).normalize(); //转化为考虑漫游点旋转的方向
- let uv = math.getUVfromDir(dirInPano)//转化为uv
-
- let distance = this.getDepth( uv.x, uv.y);
- //viewer.addTimeMark(markName,'end')
-
-
-
- if (!distance){
- const margin = 0.1
- if(uv.y > 1-Potree.config.depthTexUVyLimit){//漫游点底部识别不到的区域,给一个地板高度
-
- distance = (currentPano.floorPosition.z - origin.z - margin) / dir.z
- location.copy(dir).multiplyScalar(distance).add(origin);
- let normal = new THREE.Vector3(0,0,1)
-
- return {location, normal, distance}
- }else if(uv.y < Potree.config.depthTexUVyLimit){
- let ceilZ = currentPano.getCeilHeight()
- if(ceilZ == Infinity)return !1
- else{
- distance = (ceilZ - origin.z - margin) / dir.z
- location.copy(dir).multiplyScalar(distance).add(origin);
- let normal = new THREE.Vector3(0,0,-1)
- return {location, normal, distance}
- }
- }
- //console.log('无穷远')
- return !1; //应该是天空或模型外 , 因为很少有漫游点的地方还拍不到地板
- }
-
-
-
- //console.log('distance', distance, dirInPano.clone().multiplyScalar(distance))
-
-
-
- location.copy(dir).multiplyScalar(distance).add(origin);
-
- if(!onlyPos){
-
- var pL = this.getNearbyPoint(origin, uv, -1, 0)
- , pR = this.getNearbyPoint(origin, uv, 1, 0)
- , pB = this.getNearbyPoint(origin, uv, 0, -1)
- , pT = this.getNearbyPoint(origin, uv, 0, 1);
-
- normal = this.planeFit(dir,location, pL,pR,pB,pT )
- }
-
-
- /* if(normal.x != normal.x ){
- console.log('NAN', normal)
- var pL = this.getNearbyPoint(origin, uv, -1, 0)
- , pR = this.getNearbyPoint(origin, uv, 1, 0)
- , pB = this.getNearbyPoint(origin, uv, 0, -1)
- , pT = this.getNearbyPoint(origin, uv, 0, 1);
-
- } */
- //console.log(location, normal, distance)
-
- return {location, normal, distance}
- }
-
-
- getNearbyPoint( origin, uv, x, y) { //获取附近的若干像素距离的点
- let uv2 = uv.clone()
- uv2.x += x/(this.canvas.width-1);
- uv2.x = this.clampUV(uv2.x)
-
- uv2.y += y/(this.canvas.height-1);
- uv2.y = this.clampUV(uv2.y)
-
- /* if(uv2.x < 0 || uv2.y < 0 || uv2.x > 1 || uv2.y > 1){
- console.log('will nan')
- } */
-
- let dir = math.getDirFromUV(uv2)//从uv获取到方向
- dir.applyMatrix4(viewer.images360.currentPano.panoMatrix2)
- let depth = this.getDepth(uv2.x, uv2.y);
- /* if(Math.abs(depth - this.mainDepth) > 0.3){
- console.log('Math.abs(depth - this.mainDepth) > 0.3')
- } */
-
- //let dir = new THREE.Vector3().subVectors(intersect.point, origin).normalize()
- let position = new THREE.Vector3().copy(dir).multiplyScalar(depth).add(origin);
-
- //console.log('getNearbyPoint', uv2, depth, dir, position )
-
- return position
- }
- clampUV(v){
- return (v + 1) % 1; // 使输出在 0-1
- }
-
- planeFit(dir, position, pL,pR,pB,pT ) {//求平均法线
- let normal = new THREE.Vector3
-
-
- let plane = new THREE.Plane;
- function addNormal(p1, p2) {//根据临接的四个点,分别求法线,然后法线相加能得到平均法线
- if(!p1 || !p2)return
- plane.setFromCoplanarPoints(position, p1, p2)
-
- //console.log('normalSub', plane.normal)
-
- normal.addScaledVector(plane.normal, dir.dot(plane.normal) < 0 ? 1 : -1)//根据面的朝向判断加还是减
- }
- addNormal(pL, pB)
- addNormal(pL, pT)
- addNormal(pR, pB)
- addNormal(pR, pT)
-
- if(0 !== normal.x || 0 !== normal.y || 0 !== normal.z){
- normal.normalize()
- //console.log(normal)
- return normal
- }
-
-
- /* 四个面拼成一个菱形 */
- }
-
-
-
- }
- /*
- 注:
-
- 由于有时候获取intersect需要知道是哪个点云,所以还是不能用这个。如加测量线。
- */
- export default DepthImageSampler
-
|