three-orbit-controls 在微信小游戏环境的问题

目录

three-orbit-controls 这个是 ThreeJS 的扩展库,用于控制摄影机轨道,类似现实中摄影师坐在轨道车那样,可以自由控制摄影的朝向。想看效果直接观看 ThreeJS 的官方例子:https://threejs.org/examples/misc_controls_orbit.html

兼容微信小游戏环境

最近在用 ThreeJS 写一个 3D 的微信小游戏时,由于为了控制最佳的摄影机角度,我用到了这个扩展库去调整摄影机的角度。

在旋转摄影机镜头时,画面直接被清空了,然后 google 了一下资料,发现这个扩展库只处理浏览器的环境,查看源码可以发现里面用了element.clientWidthelement.clientWidth,这些都是微信小游戏环境不支持的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function handleTouchMoveRotate(event) {
//console.log( 'handleTouchMoveRotate' );
rotateEnd.set(event.touches[0].pageX, event.touches[0].pageY);
rotateDelta.subVectors(rotateEnd, rotateStart);

var element = scope.domElement === document ? scope.domElement.body : scope.domElement;

// rotating across whole screen goes 360 degrees around
rotateLeft(((2 * Math.PI * rotateDelta.x) / element.clientWidth) * scope.rotateSpeed);

// rotating up and down along whole screen attempts to go 360, but limited to 180
rotateUp(((2 * Math.PI * rotateDelta.y) / element.clientHeight) * scope.rotateSpeed);

rotateStart.copy(rotateEnd);

scope.update();
}

在处理镜头旋转时,首先会判断element这个对象如果是document对象的话,则使用document.body去计算旋转值,否则用OrbitControls的第二参数target(第一个参数是 camera)。所以,在不考虑修改第三方类库的情况下,我们可以传入微信小游戏的window对象。这时候又会抛出另外一个问题:

微信小游戏环境下,window 只有 nnerWidth/innerHeight 属性,不具备 clientWidth/clientHeight

weapp-adapter模拟 BOM 对象,但只考虑 innerWidth/innerHeight,这时候我们需要自己去扩展 weapp-adapter 库。我们取名为weapp-adapter-extend。weapp-adapter 模拟 BOM 的原理其实是新建一个_window对象,再该对象挂载到GameGlobal.global下(开发者工具无法重定义 window,需要另外处理):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// weapp-adapter-extend/window.js

import _window from './window';

function inject() {
const { platform } = wx.getSystemInfoSync();
// 开发者工具无法重定义 window
if (typeof __devtoolssubcontext === 'undefined' && platform === 'devtools') {
for (const key in _window) {
const descriptor = Object.getOwnPropertyDescriptor(global, key);

if (!descriptor || descriptor.configurable === true) {
Object.defineProperty(window, key, {
value: _window[key],
});
}
}
window.parent = window;
} else {
for (const key in _window) {
global[key] = _window[key];
}
global.window = global;
global.top = global.parent = global;
}
}

inject();
1
2
3
4
5
6
// weapp-adapter-extend/window.js

export default {
clientWidth: window.innerWidth,
clientHeight: window.innerHeight,
};

最后,实例化OrbitControls时,我们就可以传入window对象了:

1
const orbitControls = new OrbitControls(camera, window);

关于MouseEventWheelEvent

该扩展库用到了这两个事件去处理镜头放大缩小的交互行为,但微信小游戏环境并没有实现这两个事件,不过社区上有人已经模拟了MouseEvent,感兴趣可以去查看:https://github.com/finscn/weapp-adapter

[本文谢绝转载,谢谢]

粤ICP备2022084378号