微信小程序中用到了three.js第三方库,需要实现一个模型缩放的限制功能。

网上冲浪了好久也没找到最终解决的方案。

现在把自己的思路先记录一下,

1.缩放用的是canvas的手指事件,bindtouchstart、bindtouchmove、bindtouchend

所以可以从监听的事件入手,打印了一下事件参数,发现可以获取到手指距离左上角的一些参数,但由于模型的位置没法获取到,因此不能去对比设置,先放弃。

2.研究three.js文档

轨道控制器OrbitControls,里面看到几个描述有点相近的参数就拿来用一下:

文档还是要仔细看,我用的是PerspectiveCamera相机,所以minZoom和maxZoom是用不了的,继续推翻。

试用了下maxDistance和minDistance: 可以看到设置的值对模型展示的初始位置是有影响的,但是当时没想到要具体怎么实现,也先搁置。

3.从相机下手

通过相机的fov找到模型渲染的最大值和最小值,然后通过bindtouchstart、bindtouchmove、bindtouchend里计算出缩放的倍数来进行对fov值的改变更新。这个方法小有成效,第一视角过去的效果都可以,但是当模型旋转到侧边的时候再进行缩放,就会出现崩掉的效果。所以这个方法也要丢弃,不过可以知道从相机下手是比较确定的一个方向了:

if(e.touches.length == 2){ //双指事件
      if(e.type=='touchstart'){
        let xMove = e.touches[1].clientX - e.touches[0].clientX;
        let yMove = e.touches[1].clientY - e.touches[0].clientY;
        this.setData({
          distance : Math.sqrt(xMove * xMove + yMove * yMove)
        })
        this.platform.dispatchTouchEvent(e)
      }
      if(e.type=='touchmove'){
        let xMove = e.touches[1].clientX - e.touches[0].clientX;
        let yMove = e.touches[1].clientY - e.touches[0].clientY;
        let newDistance = Math.sqrt(xMove * xMove + yMove * yMove);
        let distanceDiff = newDistance - distance;
        newScale = scale + 0.0001 * distanceDiff
        this.setData({
          newScale:scale + 0.0001 * distanceDiff
        })

        fovTmp = camera.fov + (1-newScale)*camera.fov;
        console.log("fovTmp:",fovTmp)
        console.log("newScale:",newScale)
        if(newScale > 1 && fovTmp < 60){ //放大 && 极限值为60 &&
          camera.fov = 60;
        }else if(newScale < 1 && fovTmp > 120){ 
          camera.fov = 120;
        }else{
          camera.fov = fovTmp;
          this.platform.dispatchTouchEvent(e)
        }
        camera.updateProjectionMatrix();
      }
    } else{
      this.platform.dispatchTouchEvent(e)
    }

4.获取相机和模型的距离,通过camera.position.distanceTo(this._model.position)获取到距离之后去判断对应操作

if(e.touches.length == 2){ //双指事件
      if(e.type=='touchstart'){
        let xMove = e.touches[1].clientX - e.touches[0].clientX;
        let yMove = e.touches[1].clientY - e.touches[0].clientY;
        this.distance =Math.sqrt(xMove * xMove + yMove * yMove)
        this.platform.dispatchTouchEvent(e)
      }
      if(e.type=='touchmove'){
        let xMove = e.touches[1].clientX - e.touches[0].clientX;
        let yMove = e.touches[1].clientY - e.touches[0].clientY;
        let newDistance = Math.sqrt(xMove * xMove + yMove * yMove);
        let distanceDiff = newDistance - this.distance;
        this.newScale = scale + 0.005 * distanceDiff

        if(newScale > 1){
          console.log('放大了')
          if(camera.position.x <3&&camera.position.x >-3&&camera.position.z <3&&camera.position.z >-3&&camera.position.y >5 && this._position>56){
              
          }else  if(this._position < 53){
            
          }else{
            this.platform.dispatchTouchEvent(e)
          }
        }else{
          console.log('缩小了')
          if(this._position > 60){

          }else{
            this.platform.dispatchTouchEvent(e)
          }
        }
      }
    } else{
      this.platform.dispatchTouchEvent(e)
    }

5.通过this._center.applyMatrix4(camera.matrixWorldInverse).applyProjection(camera.projectionMatrix);

判断模型在视野内还是视野外:

let tempV = this._center.applyMatrix4(camera.matrixWorldInverse).applyProjection(camera.projectionMatrix);
    if ( (Math.abs(tempV.x) > 1) || (Math.abs(tempV.y) > 1) || (Math.abs(tempV.z) > 1) ) {
        // 在视野外了
        console.log(" 在视野外了1 ")
        controls.enablePan = false;
        if(e.touches.length == 2){ //视野外不允许缩放

        }else{
          this.platform.dispatchTouchEvent(e)
        }
    } else {
        // 在视野内  
        console.log(" 在视野内 ")
        if(this._position>60 || this._position < 51){
          controls.enablePan = false;
        }else{
          controls.enablePan = true;
        }
        this.platform.dispatchTouchEvent(e)
    }
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐