【问题标题】:Rotate camera in Three.js with mouse用鼠标在 Three.js 中旋转相机
【发布时间】:2012-01-15 15:26:40
【问题描述】:

我的场景中有很多对象,因此旋转所有对象可能会很痛苦。那么在鼠标点击和拖动时将相机围绕原点移动的最简单方法是什么?这样,场景中的所有灯光和对象都在同一个位置,所以唯一改变的是相机。 Three.js 没有提供围绕一个点旋转相机的方法,或者是这样吗?

谢谢

【问题讨论】:

    标签: javascript 3d three.js


    【解决方案1】:

    Here's a project with a rotating camera。通过源查看,它似乎只是将相机位置移动了一圈。

    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();
    
    }
    

    Here's another demo 在这个我认为它只是创建了一个新的THREE.TrackballControls 对象,以相机作为参数,这可能是更好的方法。

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

    【讨论】:

    • 确保添加事件监听器。在源代码中,它们看起来像这样: document.addEventListener( 'mousemove', onDocumentMouseMove, false );
    • 执行与正交轨迹球控件相同的操作时失败。请帮助我使用正交相机对正交轨迹球控件执行此操作。
    • 您提到了源代码,但我似乎找不到。当我查看您在 Chrome 开发工具中链接到的应用程序请求的 JS 文件时,我没有看到您在上面发布的代码。你能链接到源或解释你是如何找到它的吗?我主要是好奇你的代码 sn-p 引用的 isMouseDown 和投影仪变量在哪里/如何定义。谢谢!
    【解决方案2】:

    看看下面的例子

    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 );
    

    【讨论】:

    • 单行controls = new THREE.OrbitControls( camera, renderer.domElement );不能让它工作。你应该添加一个更改事件的处理程序并在处理程序中调用renderer.render(scene, camera),或者添加动画循环并调用controls.update()animate().
    • 我可以通过导入 OrbitControls 模块并实例化它来完成这项工作。不需要处理程序或更新调用。 (它需要对渲染器 DOM 元素的引用来附加处理程序本身,并引用渲染器来调用渲染本身。)
    【解决方案3】:

    看看 THREE.PointerLockControls

    【解决方案4】:

    这可以作为使用鼠标/触控板(在打字稿中)移动/旋转/缩放相机的良好起点:

    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,同时保持位置 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)
    

    【讨论】:

    • 看起来很有趣!你碰巧有一个现场演示要签出吗?
    • 我没有,但这是个好主意,希望这些天来更新答案
    【解决方案5】:

    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();
    

    【讨论】:

      【解决方案6】:

      【讨论】:

        猜你喜欢
        • 2020-10-21
        • 1970-01-01
        • 2021-08-23
        • 2019-04-12
        • 2013-07-15
        • 2016-01-20
        • 1970-01-01
        • 1970-01-01
        • 2017-01-19
        相关资源
        最近更新 更多