微信小程序中用到了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)
}