javascript - 旋转相机面对物体,而不会弄乱经纬度值

标签 javascript 3d three.js

我用来控制相机的代码通过移动矢量(camera.target)然后设置相机来查看该矢量来工作。在本例中,camera.lookAt(camera.target);。 onDocumentMouseMove 函数计算经度和纬度,这有助于设置camera.target x、y 和z 值。以下是事情如何运作的示例。按任意键都会导致相机旋转到某个对象,但如果您下次通过拖动鼠标移动相机时这样做,相机将自动跳转到按键之前的最后一个位置。这是因为为了让鼠标移动相机,它必须跟踪纬度和经度。所以我遇到的问题是在击键后计算新的经纬度位置。我在想如果目标 x,y,z 值可以根据 lon 和 lat 计算出来,那么按理说 lat 和 lon 可以根据 x,y,z 值反向计算。不幸的是,数学超出了我的能力范围。我已经为此问题添加了赏金。任何帮助将非常感激。 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 );
        }

最佳答案

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

逆:

摘自original code-pen的片段,发现于 document.body.onkeydown update() 内的操作事件监听器method -- 在demo中修改了这个方法,代码如下

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

代数的更多细节

鉴于我在学校总是为了仅显示解决方案而获得停靠点,以下是我如何从 x、y 和 z 逆/求解纬度和经度

xyz 代表您给定的观点( camera.target.x<object>.position.x 等)。

phi = Φ, theta = θ

求解 θ

  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(Φ))) = θ

求解 Φ

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

求解 lon

  1. θ = degToRad(lon)
  2. radToDeg(θ) = degToRad(degToRad(lon))
  3. radToDeg(θ) = lon

求解 lat

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

关于javascript - 旋转相机面对物体,而不会弄乱经纬度值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26935288/

相关文章:

javascript - 通过javascript更新html表单中文本输入的背景颜色

javascript - 根据先前选择的下拉列表删除选择下拉选项

javascript - ng-bind-html 和 ng-bind-html-unsafe 不起作用?

math - 世界空间到相机空间

javascript - 如何使用一些 Js 库在 html 页面中播放或查看 .FBX 文件

javascript - 三.js : Creating a right triangular prism

javascript - 如何使用 Cypress 和 Vue 中的组件进行组件测试?

c++ - 在 OpenGL (C++) 中绘制条纹

webgl - Threejs/WebGL : Most performant way for just cubes?

c# - 以 3D 形式渲染点或平面