如何在鼠标移动时重新创建Three.js OrbitControl运动?

3
我想重新创建Three.js OrbitControl的运动方式,但不需要点击和拖动,即仅通过鼠标移动使摄像机跟随。我尝试了从头开始重新创建它,但这需要太多的工作量,因为该问题是摄像机在三个轴上移动而不仅仅是两个。我相信有人以前已经做过这个。具体来说,我希望摄像机在场景原点周围移动,并保持与其相同的距离。

为了解决问题,您必须了解OrbitControls的工作原理:它使用目标和相机,本质上是一个向量。输入到OrbitControls会对这个向量“相机->目标”进行计算。例如,旋转将获取该向量的当前角度(相对于某个轴),将该角度修改为所需数量,然后将相机移动到向量的新端点并朝向目标旋转。向量的长度保持不变,您与目标的距离也保持不变。 - Leeft
我明白你的意思,但是我该如何告诉OrbitControls新位置呢?我一直在脚本中寻找,但是我没有看到输入新向量的方法。不过我看到它确实在这里删除了mousemove事件这里。我应该修改/分叉这个脚本以创建一个新版本吗? - a.barbieri
你需要进行多个更改才能实现你想要的功能,例如移除点击检测、使鼠标移动和触摸移动事件一直处于活动状态。同时查看 rotateLeftrotateUp 方法(它们也处理右和下),这些方法已经被用来改变 handleMouseMoveRotate 中向量的角度。 - Leeft
1个回答

6

我有和楼主相同的需求。以下是我解决问题的方法,其中得到了Leeft的帮助:

  1. Update OrbitControls.js to change scope of function handleMouseMoveRotate from

    function handleMouseMoveRotate( event )
    

    to

    this.handleMouseMoveRotate = function ( event )
    

    This is required for you to manually use this method from within your own code.

  2. In the JS code which loads the model, use the dispose method to remove the default mouse controls and add your own event handler for mousemove which manually calls handleMouseMoveRotate:

    init();
    animate();
    
    function init() {
        // Set up Camera, Scene and OrbitControls
        camera = new THREE.PerspectiveCamera( 45, containerWidth / containerHeight );
        scene = new THREE.Scene();
        controls = new THREE.OrbitControls(camera);
    
        // Remove default OrbitControls event listeners
        controls.dispose();
        controls.update();
    
        ... // omitted for brevity: Load model and Renderer
    
        document.addEventListener('mousemove', onDocumentMouseMove, false);
    }
    
    function onDocumentMouseMove( event ) {
        // Manually fire the event in OrbitControls
        controls.handleMouseMoveRotate(event);
    }
    
    function animate() {
        requestAnimationFrame( animate );
        render();
    }
    
    function render() {
        controls.update();
        camera.lookAt( scene.position );
        renderer.render( scene, camera );
    }
    

注意: 此解决方案将删除所有库的监听器。如果您有兴趣,可以从这里复制它们,并将它们粘贴到更新方法的末尾可重新启用。


感谢您付出努力寻找解决方案。我还没有测试过,但我已经看到dispose()将删除库设置的每个事件侦听器,而update()方法不会将它们设置回来,因为它们在该方法之外被调用。这个猴子补丁是否会删除OrbitControl功能(例如滚动缩放)? - a.barbieri
dispose()方法确实会移除原生的OrbitControl功能(例如缩放和滚动)。当update()方法运行时,它们不会被重新添加,这意味着您可以创建自己的事件处理程序方法 - 在这种情况下是调用我们感兴趣的唯一鼠标控制 - handleMouseMoveRotate - timray
1
意识到这一点非常重要。如果你同意的话,我会更新答案。 - a.barbieri
这似乎会抛出“超过最大调用栈大小”的错误。 - user3112634

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