实战避雷记录 | 关于小程序three.js模型缩放大小限制

微信小程序中用到了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)
    }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在Vue项目中使用Three.js获取模型的大小并自动计算放比例的方法如下: 1. 导入Three.js库和模型文件。在Vue项目中,可以通过npm安装Three.js,并在需要使用的组件中引入。 ```javascript import * as THREE from 'three'; import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; ``` 2. 创建场景、相机和渲染器。 ```javascript let scene, camera, renderer; function init() { scene = new THREE.Scene(); camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); } ``` 3. 加载模型文件并添加到场景中。 ```javascript function loadModel() { const loader = new GLTFLoader(); loader.load('path/to/model.gltf', function(gltf) { const model = gltf.scene; scene.add(model); }); } ``` 4. 自动计算模型的大小和放比例。 ```javascript function calculateScale() { const box = new THREE.Box3().setFromObject(model); const size = box.getSize(new THREE.Vector3()).length(); const targetSize = 10; // 设置目标大小 const scale = targetSize / size; model.scale.set(scale, scale, scale); } ``` 5. 渲染场景。 ```javascript function animate() { requestAnimationFrame(animate); renderer.render(scene, camera); } ``` 完整的Vue组件示例: ```vue <template> <div ref="container"></div> </template> <script> import * as THREE from 'three'; import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; export default { mounted() { let scene, camera, renderer, model; function init() { scene = new THREE.Scene(); camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); this.$refs.container.appendChild(renderer.domElement); } function loadModel() { const loader = new GLTFLoader(); loader.load('path/to/model.gltf', function(gltf) { model = gltf.scene; calculateScale(); scene.add(model); }); } function calculateScale() { const box = new THREE.Box3().setFromObject(model); const size = box.getSize(new THREE.Vector3()).length(); const targetSize = 10; // 设置目标大小 const scale = targetSize / size; model.scale.set(scale, scale, scale); } function animate() { requestAnimationFrame(animate); renderer.render(scene, camera); } init(); loadModel(); animate(); } } </script> ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值