You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改Three.js PointerLockControls旋转轴适配自定义camera.up?

修复Three.js PointerLockControls自定义up轴后的旋转异常问题

我在使用Three.js的PointerLockControls时,将相机的up轴设置为z轴:

camera.up.set(0,0,1);

但左右移动鼠标时,画面依然沿y轴旋转,而非预期的z轴。我的控件初始化代码如下:

const controls = new PointerLockControls( camera, document.body );
controls.addEventListener('lock', () => (menuPanel.style.display = 'none'))
controls.addEventListener('unlock', () => (menuPanel.style.display = 'block'))
startButton.addEventListener('click', function () {
    controls.lock();
}, false);

问题原因

PointerLockControls默认硬编码使用世界空间的y轴作为水平旋转轴,不会自动跟随相机的up属性变化,因此即使修改了相机up轴,旋转逻辑仍按原轴执行。

修复方案

通过重写控件的鼠标移动处理逻辑,让水平旋转绕相机自身的up轴进行。以下是两种实现方式:

方式1:自定义继承控件(推荐)

创建一个继承自PointerLockControls的自定义控件,修改旋转轴逻辑:

class CustomPointerLockControls extends PointerLockControls {
    constructor(camera, domElement) {
        super(camera, domElement);
        this.customUp = camera.up.clone();
    }

    handleMouseMove(event) {
        if (!this.isLocked) return;

        const movementX = event.movementX || event.mozMovementX || event.webkitMovementX || 0;
        const movementY = event.movementY || event.mozMovementY || event.webkitMovementY || 0;

        // 水平旋转绕自定义up轴,垂直旋转绕相机right轴
        const yRotQuat = new THREE.Quaternion().setFromAxisAngle(this.customUp, -movementX * 0.002);
        const xRotQuat = new THREE.Quaternion().setFromAxisAngle(this.camera.right, movementY * 0.002);

        this.camera.quaternion.premultiply(yRotQuat);
        this.camera.quaternion.premultiply(xRotQuat);
    }
}

// 使用自定义控件替换原初始化代码
const controls = new CustomPointerLockControls(camera, document.body);
controls.addEventListener('lock', () => (menuPanel.style.display = 'none'))
controls.addEventListener('unlock', () => (menuPanel.style.display = 'block'))
startButton.addEventListener('click', () => controls.lock(), false);

方式2:直接修改现有控件的处理方法

如果不想创建新类,可以直接覆盖原控件的handleMouseMove方法:

const controls = new PointerLockControls(camera, document.body);

// 重写鼠标移动处理逻辑
controls.handleMouseMove = function(event) {
    if (!this.isLocked) return;

    const movementX = event.movementX || event.mozMovementX || event.webkitMovementX || 0;
    const movementY = event.movementY || event.mozMovementY || event.webkitMovementY || 0;

    // 水平旋转绕camera.up轴
    const yRotQuat = new THREE.Quaternion().setFromAxisAngle(this.camera.up, -movementX * 0.002);
    const xRotQuat = new THREE.Quaternion().setFromAxisAngle(this.camera.right, movementY * 0.002);

    this.camera.quaternion.premultiply(yRotQuat);
    this.camera.quaternion.premultiply(xRotQuat);
};

// 后续事件监听保持不变
controls.addEventListener('lock', () => (menuPanel.style.display = 'none'))
controls.addEventListener('unlock', () => (menuPanel.style.display = 'block'))
startButton.addEventListener('click', () => controls.lock(), false);

说明

修改后,水平鼠标移动会绕相机设置的z轴旋转,垂直移动绕相机的right轴旋转,完全匹配自定义up轴的需求。

内容的提问来源于stack exchange,提问作者omega

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 00:55:37