将相机旋转到面对物体而不会弄乱拉特龙的值

时间:2014-11-14 17:08:38

标签: javascript 3d three.js

用于控制相机的代码通过移动矢量(camera.target)然后将相机设置为查看该矢量来工作。在这种情况下camera.lookAt(camera.target);. onDocumentMouseMove函数计算经度和纬度,这有助于设置camera.target x,y和z值。下面是一个如何运作的例子。按任意键将使摄像机旋转到某个对象,但如果您这样做,下次通过拖动鼠标移动摄像机时,摄像机将自动跳到击键前的最后位置。这是因为为了让鼠标移动相机,它必须跟踪lat和lon。所以我遇到的问题是在击键后计算新的lat lon位置。我在想是否可以从lon和lat计算目标x,y,z值,而不是因为可以从x,y,z值反向计算lat和lon。不幸的是,数学是我无法实现的。我已经为这个问题增加了一笔赏金。任何帮助将非常感谢。 http://codepen.io/anon/pen/GgRXJz

        var spriteImg, material, geometry;
        var camera, scene, renderer;
        var keyboard = new THREEx.KeyboardState();
        var fov = 70,
        texture_placeholder,
        isUserInteracting = false,
        onMouseDownMouseX = 0, onMouseDownMouseY = 0,
        lon = 0, onMouseDownLon = 0,
        lat = 0, onMouseDownLat = 0,
        phi = 0, theta = 0;

        init();
        animate();

        function init() {

            var container;

            container = document.getElementById( 'container' );

            camera = new THREE.PerspectiveCamera( fov, window.innerWidth / window.innerHeight, 1, 1100 );
            camera.target = new THREE.Vector3( 0, 0, 0 );

            scene = new THREE.Scene();

            renderer = new THREE.WebGLRenderer();
            renderer.setClearColor(0xffffff, 1);
            renderer.setSize( window.innerWidth, window.innerHeight );
            container.appendChild( renderer.domElement );

            document.addEventListener( 'mousedown', onDocumentMouseDown, false );
            document.addEventListener( 'mousemove', onDocumentMouseMove, false );
            document.addEventListener( 'mouseup', onDocumentMouseUp, false );
            window.addEventListener( 'resize', onWindowResize, false );
            stats = new Stats();
            stats.domElement.style.position = 'absolute';
            stats.domElement.style.bottom = '0px';
            stats.domElement.style.left = '0px';
            stats.domElement.style.zIndex = 100;
            container.appendChild( stats.domElement );

            material = new THREE.MeshBasicMaterial( { color: 0x0125fd} );
            geometry = new THREE.PlaneGeometry(50, 50, 3, 3);
            blue1 = new THREE.Mesh(geometry, material);
            blue1.position.set(200,100,200);
            scene.add(blue1);
            blue1.lookAt( camera.position );

            blue2 = new THREE.Mesh(geometry, material);
            blue2.position.set(-200,-100,-200);
            blue2.lookAt( camera.position );
            scene.add(blue2);

        }

        function onWindowResize() {

            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();

            renderer.setSize( window.innerWidth, window.innerHeight );

        }

        function onDocumentMouseDown( event ) {

            isUserInteracting = true;

            onPointerDownPointerX = event.clientX;
            onPointerDownPointerY = event.clientY;

            onPointerDownLon = lon;
            onPointerDownLat = lat;

        }

        function onDocumentMouseMove( event ) {
            if ( isUserInteracting ) {
                lon = ( event.clientX - onPointerDownPointerX ) * 0.3 + onPointerDownLon;
                lat = ( onPointerDownPointerY - event.clientY ) * 0.3 + onPointerDownLat;
            }
        }

        function onDocumentMouseUp( event ) {
            isUserInteracting = false;
        }

        function animate() {
            requestAnimationFrame( animate );
            render();
            update();
        }   

        function update()
        {           
            stats.update();
        }

        function render() {

            lat = Math.max( - 85, Math.min( 85, lat ) );
            phi = THREE.Math.degToRad( 90 - lat );
            theta = THREE.Math.degToRad( lon );

            camera.target.x = 500 * Math.sin( phi ) * Math.cos( theta );
            camera.target.y = 500 * Math.cos( phi );
            camera.target.z = 500 * Math.sin( phi ) * Math.sin( theta );

            camera.lookAt( camera.target );

            renderer.render( scene, camera );
        }

2 个答案:

答案 0 :(得分:2)

要从x,y,z坐标计算纬度和经度,请反转方法。有关演示,请参阅updated code-pen

原始

lat = Math.max( - 85, Math.min( 85, lat ) );
phi = THREE.Math.degToRad( 90 - lat );
theta = THREE.Math.degToRad( lon );

camera.target.x = 500 * Math.sin( phi ) * Math.cos( theta );
camera.target.y = 500 * Math.cos( phi );
camera.target.z = 500 * Math.sin( phi ) * Math.sin( theta );

取自document.body.onkeydown的代码段,位于update()方法中的//Since you are looking at a given shape on keypress, decided to inverse from that //shape's position. camera.lookAt( blue1.position ); //Added the following four lines of code phi = Math.acos((blue1.position.y)/500); theta = Math.acos((blue1.position.x)/(500 * Math.sin(phi))) lon = THREE.Math.radToDeg(theta); lat = 90-THREE.Math.radToDeg(phi); 操作事件侦听器中 - 使用以下代码在演示中修改此方法

camera.target.x

代数中更精细的细节

看到我如何总是在学校停靠点只显示解决方案,这里是我如何从x,y和z得到逆/解经度和经度

x y z 代表您的给定观点(<object>.position.xphi等)

theta =Φ,lon

求解Θ

  1. x = 500 * sin(Φ)* cos(Θ)
  2. x /(500 * sin(Φ))= 500 * sin(Φ)* cos(Θ)/(500 * sin(Φ))
  3. x /(500 * sin(Φ))= cos(Θ)
  4. arccos(x /(500 * sin(Φ)))= arccos(cos(Θ))
  5. arccos(x /(500 * sin(Φ)))=Θ
  6. 解决Φ

    1. y = 500 * cos(Φ)
    2. y / 500 = 500 * cos(Φ)/ 500
    3. y / 500 = cos(Φ)
    4. arccos(y / 500)= arccos(cos(Φ))
    5. arccos(y / 500)=Φ
    6. 解决lat

      1. Θ= degToRad(lon)
      2. radToDeg(Θ)= degToRad(degToRad(lon))
      3. radToDeg(Θ)= lon
      4. 解决{{1}}

        1. Φ= degToRad(90 - lat);
        2. radToDeg(Φ)= radToDeg(degToRad(90 - lat))
        3. radToDeg(Φ)= 90 - lat
        4. radToDeg(Φ) - 90 = 90 - lat - 90
        5. radToDeg(Φ) - 90 = -lat
        6. -1 *(radToDeg(Φ) - 90)= -1 *( - lat)
        7. -radToDeg(Φ+ 90 = lat
        8. 90 - radToDeg(Φ)= lat
        9. 90 - radToDeg(Φ)= lat

答案 1 :(得分:0)

camera.lookAt(yourObject.position); //?

假设我把你弄好了,问题就在于这个部分:&#34;一种旋转相机以观察物体的方法&#34;

BTW我认为你的代码如何混淆camera.target,然后调用camera.lookAt会让你感到困惑。我想当你打电话给你时,你不需要修改目标,反之亦然。