使用鼠标在Three.js中旋转相机

74

我的场景中有很多物体,如果要旋转它们所有的话可能会很麻烦。那么在鼠标点击和拖拽时移动摄像机围绕原点旋转的最简单方法是什么呢?这样场景中的所有灯光和物体都在同一个位置,唯一变化的是摄像机。Three.js没有提供一种围绕某一点旋转摄像机的方法,或者说它有吗?

谢谢

7个回答

68

这是一个带旋转相机的项目。查看源代码,似乎只是将相机位置在圆圈中移动。

function onDocumentMouseMove( event ) {

    event.preventDefault();

    if ( isMouseDown ) {

        theta = - ( ( event.clientX - onMouseDownPosition.x ) * 0.5 )
                + onMouseDownTheta;
        phi = ( ( event.clientY - onMouseDownPosition.y ) * 0.5 )
              + onMouseDownPhi;

        phi = Math.min( 180, Math.max( 0, phi ) );

        camera.position.x = radious * Math.sin( theta * Math.PI / 360 )
                            * Math.cos( phi * Math.PI / 360 );
        camera.position.y = radious * Math.sin( phi * Math.PI / 360 );
        camera.position.z = radious * Math.cos( theta * Math.PI / 360 )
                            * Math.cos( phi * Math.PI / 360 );
        camera.updateMatrix();

    }

    mouse3D = projector.unprojectVector(
        new THREE.Vector3(
            ( event.clientX / renderer.domElement.width ) * 2 - 1,
            - ( event.clientY / renderer.domElement.height ) * 2 + 1,
            0.5
        ),
        camera
    );
    ray.direction = mouse3D.subSelf( camera.position ).normalize();

    interact();
    render();

}

这里有另一个演示,在这个演示中,我认为它只是创建了一个新的THREE.TrackballControls对象,并将相机作为参数传递进去,这可能是更好的方法。

controls = new THREE.TrackballControls( camera );
controls.target.set( 0, 0, 0 )

9
请添加事件监听器。在源代码中,它们看起来像这样:document.addEventListener('mousemove', onDocumentMouseMove, false); - meetar
它在使用正交轨迹球控件时失败了。请帮我使用正交相机的正交轨迹球控件来完成这个任务。 - Aasha joney
1
你提到了源代码,但我似乎找不到它。当我在Chrome Dev Tools中查看应用程序请求的JS文件时,我没有看到你上面发布的代码。请问你能否提供源代码链接或解释一下如何找到它?我主要想知道你的代码片段引用的isMouseDown和projector变量是如何定义的。 谢谢! - currenthandle

56

请查看以下示例:

http://threejs.org/examples/#misc_controls_orbit

http://threejs.org/examples/#misc_controls_trackball

还有其他不同的鼠标控制示例,但这两个示例都允许相机围绕一个点旋转,并使用鼠标滚轮进行缩放,主要区别是OrbitControls强制执行相机的正上方方向,而TrackballControls允许相机翻转到头。

您只需在html文档中包含这些控件即可。

<script src="js/OrbitControls.js"></script>

并且在您的源代码中包含这一行

controls = new THREE.OrbitControls( camera, renderer.domElement );

4
仅一行代码 controls = new THREE.OrbitControls( camera, renderer.domElement ); 无法使其工作。您应该添加一个变更事件处理程序,在处理程序中调用 renderer.render(scene, camera),或添加动画循环并在 animate() 中调用 controls.update() - Halt
2
我只需导入OrbitControls模块并实例化它,就能使其工作。不需要处理程序或更新调用。(它需要一个对渲染器DOM元素的引用来附加处理程序本身,并且需要对渲染器进行呈现。) - Tomáš Hübelbauer

6
这可能是使用鼠标/触摸板移动/旋转/缩放相机的良好起点(使用typescript):
class CameraControl {
    zoomMode: boolean = false
    press: boolean = false
    sensitivity: number = 0.02

    constructor(renderer: Three.Renderer, public camera: Three.PerspectiveCamera, updateCallback:() => void){
        renderer.domElement.addEventListener('mousemove', event => {
            if(!this.press){ return }

            if(event.button == 0){
                camera.position.y -= event.movementY * this.sensitivity
                camera.position.x -= event.movementX * this.sensitivity        
            } else if(event.button == 2){
                camera.quaternion.y -= event.movementX * this.sensitivity/10
                camera.quaternion.x -= event.movementY * this.sensitivity/10
            }

            updateCallback()
        })    

        renderer.domElement.addEventListener('mousedown', () => { this.press = true })
        renderer.domElement.addEventListener('mouseup', () => { this.press = false })
        renderer.domElement.addEventListener('mouseleave', () => { this.press = false })

        document.addEventListener('keydown', event => {
            if(event.key == 'Shift'){
                this.zoomMode = true
            }
        })

        document.addEventListener('keyup', event => {
            if(event.key == 'Shift'){
                this.zoomMode = false
            }
        })

        renderer.domElement.addEventListener('mousewheel', event => {
            if(this.zoomMode){ 
                camera.fov += event.wheelDelta * this.sensitivity
                camera.updateProjectionMatrix()
            } else {
                camera.position.z += event.wheelDelta * this.sensitivity
            }

            updateCallback()
        })
    }
}

将其放入,如下所示:

this.cameraControl = new CameraControl(renderer, camera, () => {
    // you might want to rerender on camera update if you are not rerendering all the time
    window.requestAnimationFrame(() => renderer.render(scene, camera))
})

控制:

  • 按住鼠标左键/触摸板单指移动,可在x/y平面上移动相机。
  • 滚动鼠标滚轮/触摸板双指移动,可在z方向上移动相机。
  • 同时按住Shift键并滚动鼠标滚轮/触摸板双指移动,可通过增加/减少视野来放大/缩小。
  • 同时按住鼠标右键/触摸板双指移动,可旋转相机(四元数)。

另外:

如果您想通过更改“距离”(沿yz方向)来进行缩放,而不是更改视野,请保持相机位置的y和z比例不变,将其向上/向下调整,如下所示:

// in mousewheel event listener in zoom mode
const ratio = camera.position.y / camera.position.z
camera.position.y += (event.wheelDelta * this.sensitivity * ratio)
camera.position.z += (event.wheelDelta * this.sensitivity)

1
听起来很有趣!你有没有一个在线演示可以看一下吗? - davidchappy
我不知道,但这是一个好主意,希望近日内能更新答案。 - ambientlight

4

看一下THREE.PointerLockControls


1
参考链接:https://github.com/mrdoob/three.js/blob/master/examples/js/controls/PointerLockControls.js - defrex

3

3

OrbitControls和TrackballControls似乎适用于这个目的。

controls = new THREE.TrackballControls( camera );
controls.rotateSpeed = 1.0;
controls.zoomSpeed = 1.2;
controls.panSpeed = 0.8;
controls.noZoom = false;
controls.noPan = false;
controls.staticMoving = true;
controls.dynamicDampingFactor = 0.3;

在渲染中更新

controls.update();

2

请看文档中最简单的示例。这里是该示例的源代码。 需要使用THREE.OrbitControls


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接