xzw před 1 rokem
rodič
revize
9003d8b10f

+ 1 - 1
src/custom/modules/Particles/ParticleEditor.js

@@ -231,7 +231,7 @@ let ParticleEditor = {
         curve.addEventListener('dragCurvePoint',()=>{  
             Common.intervalTool.isWaiting('particlePointChange', ()=>{ //延时update,防止卡顿   
                 particles.forEach(e=>e.updateGeometry())  
-                geoNeedsUpdate = false 
+                //geoNeedsUpdate = false 
                 curve.dispatchEvent('sendUpdatePoints') 
             }, 400)  
         })

+ 2 - 2
src/custom/modules/panoEdit/panoEditor.js

@@ -1086,12 +1086,12 @@ class PanoEditor extends THREE.EventDispatcher{
             setPos(circle) 
             pano.addEventListener('rePos', setPos.bind(this,circle))
                
-            let drag = ()=>{
+            let drag = (e)=>{
                 /* if(this.activeViewName == 'mainView' && this.tranMode == 'translate'){//如果3d页不禁止xy的话,这段打开
                     this.transformControls.dispatchEvent('dragging')//触发拖拽
                     return
                 } */
-                if(this.tranMode != 'translate' || this.activeViewName == 'mainView')return
+                if(this.tranMode != 'translate' || this.activeViewName == 'mainView')return e.refuse()
                 this.selectPano(circle.pano)                    //为了方便拖拽点云,拖动circle就直接选中
               
                 viewer.inputHandler.drag.object = null  //取消拖拽状态,否则不触发点云拖动

+ 3 - 2
src/custom/modules/panos/DepthImageSampler.js

@@ -42,8 +42,9 @@ class DepthImageSampler extends THREE.EventDispatcher{
             //console.log('重复使用',item.pano.id)
             return
         }
+        Potree.timeCollect.depthSamChangeImg.start = true  //不过在刚启动时得到的用时较大
         try{
-            viewer.addTimeMark('depthSampler','start')
+            viewer.addTimeMark('depthSamChangeImg','start')
             this.canvas.width = img.width 
             this.canvas.height = img.height 
             this.context.drawImage(img, 0, 0) 
@@ -62,7 +63,7 @@ class DepthImageSampler extends THREE.EventDispatcher{
             
             
             this.dispatchEvent({type:'changeImg',pano})
-            viewer.addTimeMark('depthSampler','end') //耗时chrome 25ms,firefox: 38ms, iphoneX:33ms
+            viewer.addTimeMark('depthSamChangeImg','end') //耗时chrome 25ms,firefox: 38ms, iphoneX:33ms
             
         }catch(e){
             console.error(e ) //内存不足  Failed to execute 'getImageData' on 'CanvasRenderingContext2D': Out of memory at ImageData creation

+ 37 - 6
src/custom/modules/panos/Images360.js

@@ -238,6 +238,33 @@ export class Images360 extends THREE.EventDispatcher{
             });
  
             this.elDisplayModel = elDisplayModel
+            
+            
+             
+            
+            let mapStyleBtn = $("<input type='button' value='普通'></input>")
+                mapStyleBtn.css({
+                    position : "absolute",
+                    right : '50%',
+                    bottom: '20px',
+                    zIndex: "10000",
+                    fontSize:'1em'  ,color:"black",
+                    width : '100px',
+                    background:'rgba(255,255,255,0.8)',
+                }) 
+                this.domRoot.appendChild(mapStyleBtn[0]);
+                let map = viewer.mapViewer.mapLayer.maps.find(e=>e.name == 'map') 
+                mapStyleBtn.on("click", (e) => {  
+                    map.switchStyle(map.style == 'satellite' ? 'standard' : 'satellite') 
+                    mapStyleBtn.val(map.style == 'satellite' ? '卫星' : '普通')
+                });
+                
+             
+            
+            
+            
+            
+            
         }
          
         
@@ -1412,7 +1439,6 @@ export class Images360 extends THREE.EventDispatcher{
             Images360.filters.not(this.currentPano),
             Images360.filters.isEnabled(), 
             Images360.filters.inFloorDirection( this.position, direction, option1 ),  //原先用inPanoDirection,但容易穿楼层,当mouse较低或较高
-            Images360.filters.inPanoDirection( this.position, this.getDirection(), option1/* , true */),  //垂直方向上再稍微限制一下, 要接近视线方向,避免点击前方时因无路而到下一楼。但不能太高,否则楼梯上稍微朝下点击都到不了上方。之所以使用视线方向是因为镜头方向比鼠标方向目的性更强。
             (pano)=>{ 
                 /* let isNeighbour = this.isNeighbour(this.currentPano, pano, true, true); //不计算的
                 if(isNeighbour == void 0){
@@ -1441,6 +1467,11 @@ export class Images360 extends THREE.EventDispatcher{
                 } 
             }  */
         ] 
+        
+        if(!byKey){
+            Images360.filters.inPanoDirection( this.position, this.getDirection(), option1/* , true */)   //垂直方向上再稍微限制一下, 要接近视线方向,避免点击前方时因无路而到下一楼。但不能太高,否则楼梯上稍微朝下点击都到不了上方。之所以使用视线方向是因为镜头方向比鼠标方向目的性更强。
+        }
+
          
         var list = [//决胜项目
             (pano)=>{
@@ -1576,7 +1607,7 @@ export class Images360 extends THREE.EventDispatcher{
     
     
 	update(){ 
-        if(this.tileDownloader.started){
+        //if(this.tileDownloader.started){
             
             var vectorForwards = this.getTileDirection()
             
@@ -1584,7 +1615,7 @@ export class Images360 extends THREE.EventDispatcher{
             
             this.updateTileDownloader(tileArr, vectorForwards);
             this.updatePanoRenderer(vectorForwards) 
-        }
+        //}
         
         this.updateZoomPano();
         
@@ -1993,7 +2024,7 @@ export class Images360 extends THREE.EventDispatcher{
                             tile.material.color = (new THREE.Color()).setHSL(colorHue, 0.6, 0.7)  
                             
                             
-                            tile.scoreLabel = new TextSprite(  { 
+                            /* tile.scoreLabel = new TextSprite(  { 
                                 backgroundColor: { r: 0, g: 0, b: 0, a: 0 },
                                 textColor: { r: 0, g: 0, b: 0, a: 1 },
                                 borderRadius: 15,
@@ -2004,7 +2035,7 @@ export class Images360 extends THREE.EventDispatcher{
                             tile.scoreLabel.sprite.material.side = 2;
                             tile.scoreLabel.rotation.x = Math.PI
                             
-                            tile.add(tile.scoreLabel) 
+                            tile.add(tile.scoreLabel)  */
                             
                         }
                         
@@ -2415,7 +2446,7 @@ Images360.prototype.getNeighbours = function(){ //逐渐自动获取neighbours
         let changeTexCount = ()=>{
             changeCount ++;
         }
-        let median = Potree.timeCollect.depthSampler.median 
+        let median = Potree.timeCollect.depthSamChangeImg.median 
           
         
         let ifOverTime = ()=>{ 

+ 12 - 6
src/custom/modules/panos/Panorama.js

@@ -143,7 +143,7 @@ class Panorama extends THREE.EventDispatcher{
             
             
         }else{
-            this.originPosition = new THREE.Vector3().fromArray(o.dataset_location) 
+            this.originPosition = new THREE.Vector3().fromArray(o.dataset_location)   //完全对应vision.txt的translation
             this.originFloorPosition = new THREE.Vector3().fromArray(o.dataset_floor_location)
             
             this.originID = parseInt(o.file_id)//"file_id":"00022"对应是原本的4dkk的id --来自vision.txt
@@ -166,7 +166,7 @@ class Panorama extends THREE.EventDispatcher{
             }else{ */
             
                 
-                var qua = o.dataset_orientation 
+                var qua = o.dataset_orientation  //完全对应vision.txt的rotation
                 qua = [qua[1], qua[2], qua[3], qua[0]] 
                 this.quaternion = new THREE.Quaternion().fromArray(qua)
                 this.quaternion4dkk = math.convertVisionQuaternion(this.quaternion)//4dkk内使用的quaternion 
@@ -601,24 +601,30 @@ class Panorama extends THREE.EventDispatcher{
     getCeilHeight(){//天花板高度值   (假设不存在depth为0的点,所有为0的要么是在盲区,要么是无穷远。)
          
         if(this.ceilZ == void 0){
-            const depthTiming = Potree.timeCollect.depthSampler.median    //pc firefox达到4.  chrome为0.01
+            //const depthTiming = Potree.timeCollect.depthSampler.median    //pc firefox达到4.  chrome为0.01
                      
             
             //用三个间隔120度散开,和中心垂直线成一定夹角的三个向量去求 最高高度 (不求平均的原因:万一是0不好算)
             
             let rotMat = new THREE.Matrix4().makeRotationX((Potree.config.depthTexUVyLimit+0.01)*Math.PI)// 角度不能小于天花板中空的半径 
             
+            let dir0 = new THREE.Vector3(0,0,1).applyMatrix4(rotMat)
             
+            let dirs = [
+                dir0, 
+                dir0.clone().applyMatrix4(new THREE.Matrix4().makeRotationZ(Math.PI*2 / 3)),
+                dir0.clone().applyMatrix4(new THREE.Matrix4().makeRotationZ(-Math.PI*2 / 3))
+            ];
+             
             
-            let dirs = [new THREE.Vector3(0,0,1).applyMatrix4(rotMat)];
-            if(depthTiming < 1){
+            /* if(depthTiming < 1){
                 let rotMat1 = new THREE.Matrix4().makeRotationZ(Math.PI*2 / 3);
                 dirs.push(dirs[0].clone().applyMatrix4(rotMat1))
             }
             if(depthTiming < 0.3){
                 let rotMat2 = new THREE.Matrix4().makeRotationZ(-Math.PI*2 / 3);
                 dirs.push(dirs[0].clone().applyMatrix4(rotMat2)); 
-            }
+            } */
              
             let zs = dirs.map(dir_=>{ 
                 let dir = dir_.clone().applyMatrix4(this.panoMatrix2)  //pano不一定是垂直的, 需要把之前的dirInPano先转成真实的dir,防止超出角度限制

+ 8 - 8
src/custom/modules/panos/tile/TileDownloader.js

@@ -42,7 +42,7 @@ class TileDownloader extends THREE.EventDispatcher{
         
                                                                                   
          
-        viewer.addEventListener('pageVisible', (e)=>{//不可见时不refreshUpdateInterval 
+        /* viewer.addEventListener('pageVisible', (e)=>{//不可见时不refreshUpdateInterval 
             //console.log('visibilitychange:', state)
             Potree.Utils.updateVisible(this,  'pageVisible', e.v) 
             this.judgeStart() 
@@ -53,7 +53,7 @@ class TileDownloader extends THREE.EventDispatcher{
             this.judgeStart()  //开始下载depthTex
         }else{ 
             Potree.Utils.updateVisible(this,'showPanos', false ) //默认visible = false
-        }
+        } */
         
     }
 
@@ -65,23 +65,23 @@ class TileDownloader extends THREE.EventDispatcher{
   
     start() { 
         this.downloadCubeTex = true 
-        if(!Potree.settings.useDepthTex){
+        /* if(!Potree.settings.useDepthTex){
             Potree.Utils.updateVisible(this,'showPanos', true )
             this.judgeStart()            
         }else{
             //this.refreshInterval || this.judgeStart()
-        }
+        } */
     }
 
     stop() {
         this.downloadCubeTex = false
-        if(!Potree.settings.useDepthTex){
+        /* if(!Potree.settings.useDepthTex){
             Potree.Utils.updateVisible(this,'showPanos', false )
             this.judgeStart()
-        } 
+        }  */
     }
 
-    judgeStart(){//add
+    /* judgeStart(){//add
         if(this.visible){
             //console.log('judgeStart true')
             this.started = true 
@@ -92,7 +92,7 @@ class TileDownloader extends THREE.EventDispatcher{
             //window.clearTimeout(this.refreshInterval)
         }
         
-    }
+    } */
 
     /* refreshUpdateInterval(e) {
         e || (e = 0),

+ 1 - 1
src/custom/objects/fireParticle/explode/ExplodeParticle.js

@@ -442,7 +442,7 @@ class ExplodeParticle extends THREE.Points {
         if (this.age > this.deathAge && !this.loop) {
             this.alive = false
         }
-
+         
     }
 
     setSize(e) {

+ 2 - 0
src/custom/objects/fireParticle/explode/Particle.js

@@ -50,6 +50,8 @@ class Particle {
     if(this.opacityTween.times.length > 0) {
       this.opacity = this.opacityTween.lerp(this.age/this.deathAge)
     }
+     viewer.dispatchEvent('content_changed');   
+    
   }
 
 }

+ 1 - 0
src/custom/objects/fireParticle/fire/FireParticle.js

@@ -262,6 +262,7 @@ class FireParticle extends THREE.Points{
         delta *= 1//更改速度
         
         this.material.uniforms.time.value = (this.material.uniforms.time.value + delta) % 1; 
+        viewer.dispatchEvent('content_changed')
     }
     
     dispose(){

+ 2 - 1
src/custom/objects/fireParticle/smoke/Particle.js

@@ -51,7 +51,8 @@ export default class Particle{
         
         if ( this.opacityTween.times.length > 0 )
         {
-            this.opacity = this.opacityTween.lerp( this.age/this.deathAge);
+            this.opacity = this.opacityTween.lerp( this.age/this.deathAge); 
         }
+        viewer.dispatchEvent('content_changed')
     }
 }

+ 2 - 3
src/custom/objects/tool/TransformControls.js

@@ -416,7 +416,7 @@ var TransformControls = function ( camera, domElement, options ) {
 			space = 'world';
 
 		}
-		 
+		
 
 		if ( object === undefined || axis === null || this.dragging === false || ( pointer.button !== undefined && pointer.button !== 0 ) ) return;
 
@@ -439,8 +439,7 @@ var TransformControls = function ( camera, domElement, options ) {
 
 		if ( mode === 'translate' ) {
 
-			// Apply translate
-
+			// Apply translate 
 			offset.copy( pointEnd ).sub( pointStart );
 
 			if ( space === 'local' && axis !== 'XYZ' ) {

+ 4 - 1
src/custom/settings.js

@@ -175,7 +175,8 @@ const config = {//配置参数   不可修改
          
         lineWidth: 4,
        
-        textColor: "#FFFFFF"
+        textColor: "#FFFFFF",
+        
         
     },
     material:{//初始化
@@ -425,6 +426,8 @@ let settings = {//设置   可修改
 
     notAdditiveBlending:false, //点云是否使用普通的blend, 否则会曝光过渡
     precision:2,  // 两位小数 
+    unit: 'm',
+    
     useV4url:true, //v4的全景图等路径不一样 scene_view_data
     
     useRTskybox:true,  //直接使用rtEDL绘制到屏幕,当是全景模式时. 在降4倍时能给render节省1毫秒,gpu时间未测 

+ 11 - 9
src/custom/viewer/ViewerNew.js

@@ -135,14 +135,16 @@ export class Viewer extends ViewerBase{
         }
         {
             Potree.timeCollect = {
-                depthSampler : {minCount:400, median: 25}, //median预置一个中等值,以防止cpu过低的设备首次卡顿  
-                 
+                //median预置一个中等值,以防止cpu过低的设备首次卡顿  
+                //depthSampler : {minCount:400, median: 1}, //旧的 实时从图片中获取色值的用时,但是现在直接从data中取
+                 depthSamChangeImg:{minCount:200, median: 25} //换图的用时。 需要一开始就start
+            }
+            for(let i in Potree.timeCollect){
+                Potree.timeCollect[i].measures = [];
+                Potree.timeCollect[i].sum = 0; 
             }
-            
             setTimeout(()=>{
-                for(let i in Potree.timeCollect){
-                    Potree.timeCollect[i].measures = [];
-                    Potree.timeCollect[i].sum = 0;
+                for(let i in Potree.timeCollect){ 
                     Potree.timeCollect[i].start = true
                 }
                 /* setTimeout(()=>{
@@ -979,7 +981,7 @@ export class Viewer extends ViewerBase{
     computeShelter(){
         //先算用深度图的,然后再点云;
         
-        let depthTiming = Potree.timeCollect.depthSampler.median 
+        //let depthTiming = Potree.timeCollect.depthSampler.median 
         let byTex=0,  byCloud=0;
         let len = shelterHistory.length;
         let waitCloud = []
@@ -1348,7 +1350,7 @@ export class Viewer extends ViewerBase{
 
 
 	onCrash(error){
-
+        console.error(error)
 		$(this.renderArea).empty();
 
 		if ($(this.renderArea).find('#potree_failpage').length === 0) {
@@ -3823,7 +3825,7 @@ export class Viewer extends ViewerBase{
             
             if(this.mapViewer/* .attachedToViewer */){ 
                 //console.log('mapFocusOn: '+target.toArray())
-                const minBound = new THREE.Vector2(1,1)//针对垂直线,在地图上只有一个点
+                const minBound = new THREE.Vector2(2,2)//针对垂直线,在地图上只有一个点
                 //原始的bound
                 let boundOri = new THREE.Box3() 
                 object.points.forEach(e=>{ 

+ 28 - 11
src/custom/viewer/map/Map.js

@@ -307,11 +307,7 @@ export class TiledMapBase extends THREE.EventDispatcher{
             this.baseTile.remove()
         }else{
             this.mapLayer.needUpdate = true
-        }
-       
-       
-        
-               
+        }        
         
     }
     
@@ -724,9 +720,7 @@ export class TiledMapOpenStreetMap extends TiledMapBase{
     constructor(mapLayer, tileColor){
         
         let baseUrl, attribution, projection, maxDepth;
-        
-        
-        
+         
         
         
         if(Potree.settings.mapCompany == 'google'){
@@ -736,7 +730,10 @@ export class TiledMapOpenStreetMap extends TiledMapBase{
             maxDepth = 22           
         }else{
             projection = "EPSG:3857"
-            baseUrl = "https://wprd04.is.autonavi.com/appmaptile?lang=zh_cn&style=7&x=${x}&y=${y}&z=${z}"    // https://blog.csdn.net/fredricen/article/details/77189453
+            baseUrl = "https://wprd04.is.autonavi.com/appmaptile?lang=zh_cn&style=7&yrs=m&x=${x}&y=${y}&z=${z}"    // 
+            //baseUrl = "https://webst01.is.autonavi.com/appmaptile?lang=zh_cn&style=6&yrs=m&x=${x}&y=${y}&z=${z}"    //卫星 maxDepth = 18   
+            //搜索高德地图瓦片url 
+            
             attribution = "© PopSmart,  © 高德地图"
             maxDepth = 19   
         }
@@ -758,10 +755,30 @@ export class TiledMapOpenStreetMap extends TiledMapBase{
     
     getTileUrl(t, e, n){ 
         return this.baseUrl.replace(/\${z}/, t.toString(10)).replace(/\${x}/, e.toString(10)).replace(/\${y}/, n.toString(10))
-    }  
+    } 
+
+
+    switchStyle(style = 'standard'){
+        if(Potree.settings.mapCompany == 'google')return 
+        if(style == this.style)return
+        
+        if(style == 'satellite'){//卫星
+            this.maxDepth = 18
+            this.baseUrl = "https://webst01.is.autonavi.com/appmaptile?lang=zh_cn&style=6&yrs=m&x=${x}&y=${y}&z=${z}"
+        }else{
+            this.maxDepth = 19
+            this.baseUrl = "https://wprd04.is.autonavi.com/appmaptile?lang=zh_cn&style=7&yrs=m&x=${x}&y=${y}&z=${z}"    // 
+            
+        }
+        this.style = style
+        this.setEnable(false)
+        this.setEnable(true)
+        viewer.dispatchEvent('content_changed')
+    }
+    
 }
 
-//yrs=y为混合地图,s为卫星地图,m为普通地图。我们使用谷歌地图的瓦片图层的时候默认采用的是lyrs=s,也就是普通的卫星图层,现在我们希望包含路网信息,只需要设置lyrs=y就OK了。
+
 
 
 export class TiledMapFromEntity extends TiledMapBase{

+ 1 - 1
src/materials/shaders/pointcloud_new.vs

@@ -1019,7 +1019,7 @@ void main() {
         float v = -gl_Position.z-1.0 ;   // 范围从-2到0,   e的-2到0次方的范围是0.818到1 
         //vOpacity = uOpacity * exp(v/ (levelPercent * 20.0 )  );  
         //近处加深,远处变淡  gl_Position.z似乎朝向屏幕里为正
-        float r = clamp( pow(1.5, v/5.0    ),  0.1, 1.0  );  //除以的数字越大,近高远低的程度越小,范围越长。 程度太高远处单薄的区域看不见  pow的底数越大改变率越大
+        float r = clamp( pow(1.1, v/10.0    ),  0.1, 1.0  );  //除以的数字越大,近高远低的程度越小,范围越长。 程度太高远处单薄的区域看不见  pow的底数越大改变率越大
         vOpacity = uOpacity * r  ;
         
        // vOpacity = clamp(vOpacity, 0.001, 1.0);  

+ 9 - 7
src/navigation/InputHandlerNew.js

@@ -1020,29 +1020,31 @@ export class InputHandler extends THREE.EventDispatcher {
             //this.drag.hoverViewport = this.hoverViewport
             this.drag.pointerDelta.subVectors(this.pointer,  this.drag.end)
             this.drag.end.copy(this.pointer)
-            
+            let dragConsumed = false; 
             
             if (this.drag.object && (e.buttons == Buttons.NONE || !this.drag.notPressMouse )){//如果是本不需要按鼠标的拖拽,但按下了鼠标,就不执行这段(改为拖拽场景,如添加测量时突然拖拽画面)
                 if (this.logMessages) console.log(this.constructor.name + ': drag: ' + this.drag.object.name);
-                
+                let refused 
                 this.drag.object.dispatchEvent($.extend(  
                     this.getEventDesc(e,isTouch),
                     {
                         type: 'drag',  //拖拽物体
+                        refuse: () => {refused = true;}
                     }
                 ))
+                if(!refused)dragConsumed = true
                 viewer.dispatchEvent('content_changed') 
                 
-            } else {
-                 
+            }  
+             
+            if(!dragConsumed){        
                 if (this.logMessages) console.log(this.constructor.name + ': drag: ');
-
-                let dragConsumed = false; 
+ 
                 this.viewer.dispatchEvent($.extend(  
                     this.getEventDesc(e,isTouch),   
                     {
                         type: 'global_drag',        //拖拽画面
-                        consume: () => {dragConsumed = true;}
+                        //consume: () => {dragConsumed = true;}
                     }
                 ))
                  

+ 4 - 4
src/viewer/EDLRendererNew.js

@@ -191,7 +191,7 @@ export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
          
         const viewer = this.viewer; 
 		let camera = params.camera ? params.camera : viewer.scene.getActiveCamera();
-        let rtEDL = (Potree.settings.pointEnableRT || Potree.settings.displayMode == 'showPanos' || viewer.useEDL) && 
+        let rtEDL =/*  (Potree.settings.pointEnableRT || Potree.settings.displayMode == 'showPanos' || viewer.useEDL) && */ 
                     Features.EXT_DEPTH.isSupported() && camera.type != "OrthographicCamera" && !params.dontRenderRtEDL && (params.rtEDL || this.getRtEDL(params.viewport))  // 平面相机不用depthTex直接打开depthTest?且不使用edl
         let useEDL = viewer.useEDL && rtEDL && Potree.settings.displayMode != 'showPanos'
         
@@ -214,11 +214,11 @@ export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
     
         //skybox  全景图
         if(!params.magnifier){ 
-            if(Potree.settings.displayMode == 'showPanos' || Potree.settings.testCube){
+            if(Potree.settings.displayMode == 'showPanos' || Potree.settings.testCube ||   window.bothShow ){
                  
                 Potree.Utils.setCameraLayers(camera, ['skybox'])
             
-                if(Potree.settings.displayMode == 'showPanos' && viewer.images360.currentPano.pointcloud.hasDepthTex && rtEDL){//渲染深度图
+                if((Potree.settings.displayMode == 'showPanos' || window.bothShow  )&& viewer.images360.currentPano.pointcloud.hasDepthTex && rtEDL){//渲染深度图
                      
                     viewer.renderer.setRenderTarget(rtEDL) //将带有深度图的skybox画在rtEDL一下,这样就不需要绘制后边的点云了
                     viewer.renderer.render(viewer.scene.scene, camera);
@@ -231,7 +231,7 @@ export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
                     }else{
                         viewer.renderer.render(viewer.scene.scene, camera);
                     }
-                    return
+                    if(Potree.settings.displayMode == 'showPanos' )return
                 }else{
                     viewer.renderer.render(viewer.scene.scene, camera);
                 }