美文网首页
球体全景图

球体全景图

作者: lesliefang | 来源:发表于2017-09-12 19:07 被阅读138次

    演示 http://csworld.cc:3005/Panorama_Sphere.html

    全景图片一般有两种实现方式,一是把图片贴到一个球体的表面,二是把全景图分成 6 张图片分别贴到一个正方体的 6 个面上。

    在 Three.js 中把全景图片贴到球体的表面非常简单

    var textureLoader = new THREE.TextureLoader();
    textureLoader.load('powu.jpg', function (texture) {
        var material = new THREE.MeshBasicMaterial({map: texture});
        var sphere = new THREE.SphereGeometry(500, 60, 40);
        // 翻转 X 轴使所有的面都朝里(改变了法向量的方向)
        sphere.scale(-1, 1, 1);
        var mesh = new THREE.Mesh(sphere, material);
        scene.add(mesh);
    });
    

    相机在球体的中心默认指向 Z 轴负方向。下面的关键是通过移动鼠标来改变相机的朝向,可通过计算经纬度来计算相机的朝向。

    coords.png

    如图球面上任意一个点 A 在赤道面上的投影 为 B, OAB 与赤道平面的夹角是纬度(lat), OB 与水平轴的夹角是经度(lon)。 默认的经纬度为零 (lon=0, lat=0), 当我们移动鼠标时根据鼠标移动的距离改变 lat, lon 的值,然后再根据 lat, lon 计算出 A 点的坐标,让相机指向 A 就行了。

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset=utf-8>
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>球体全景图</title>
        <style>
            body {
                margin: 0;
            }
    
            canvas {
                width: 100%;
                height: 100%
            }
        </style>
    </head>
    <body>
    <script src="three.js"></script>
    
    <script>
        var scene, camera, renderer;
        var isUserInteracting = false,
            onMouseDownX = 0, onMouseDownY = 0,
            lon = 0, lat = 0,
            phi = 0, theta = 0;
    
        var touchX = 0, touchY = 0;
    
        init();
        animate();
    
        function init() {
            scene = new THREE.Scene();
            camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 1000);
            // 自定义属性  target ,相机默认指向 (0,0,0)
            camera.target = new THREE.Vector3(0, 0, 0);
    
            var textureLoader = new THREE.TextureLoader();
            textureLoader.load('powu.jpg', function (texture) {
                var material = new THREE.MeshBasicMaterial({map: texture});
                var sphere = new THREE.SphereGeometry(500, 60, 40);
                // 翻转 X 轴使所有的面都朝里(改变了法向量的方向)
                sphere.scale(-1, 1, 1);
                var mesh = new THREE.Mesh(sphere, material);
                scene.add(mesh);
            });
    
            renderer = new THREE.WebGLRenderer();
            renderer.setSize(window.innerWidth, window.innerHeight);
            document.body.appendChild(renderer.domElement);
    
            document.addEventListener('mousedown', onMouseDown, false);
            document.addEventListener('mousemove', onMouseMove, false);
            document.addEventListener('mouseup', onMouseUp, false);
            document.addEventListener('wheel', onMouseWheel, false);
    
            document.addEventListener('touchstart', onTouchStart, false);
            document.addEventListener('touchmove', onTouchMove, false);
            document.addEventListener('touchend', onTouchEnd, false);
    
            window.addEventListener('resize', onWindowResize, false);
        }
    
        function animate() {
            requestAnimationFrame(animate);
            updateCamera();
            renderer.render(scene, camera);
        }
    
        function onMouseDown(event) {
            event.preventDefault();
            isUserInteracting = true;
            onMouseDownX = event.clientX;
            onMouseDownY = event.clientY;
        }
    
        function onMouseMove(event) {
            if (isUserInteracting === true) {
                lon -= (event.clientX - onMouseDownX ) * 0.1;  // 经度
                lat += (event.clientY - onMouseDownY) * 0.1; // 纬度
    
                onMouseDownX = event.clientX;
                onMouseDownY = event.clientY;
            }
        }
    
        function onMouseUp(event) {
            isUserInteracting = false;
        }
    
        function onMouseWheel(event) {
            camera.fov += event.deltaY * 0.05;
            camera.updateProjectionMatrix();
        }
    
        function onTouchStart(event) {
            event.preventDefault();
            isUserInteracting = true;
    
            var touch = event.touches[0];
            touchX = touch.screenX;
            touchY = touch.screenY;
        }
    
        function onTouchMove(event) {
            if (isUserInteracting === true) {
                var touch = event.touches[0];
                lon -= (touch.screenX - touchX) * 0.1;
                lat += (touch.screenY - touchY) * 0.1;
    
                touchX = touch.screenX;
                touchY = touch.screenY;
            }
        }
    
        function onTouchEnd(event) {
            isUserInteracting = false;
        }
    
        function onWindowResize() {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        }
    
        function updateCamera() {
            if (isUserInteracting === false) {
                lon += 0.1;
            }
    
            lat = Math.max(-85, Math.min(85, lat)); // 纬度限定在 [-85,85]
            phi = THREE.Math.degToRad(90 - lat); // 90 - 纬度
            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);
        }
    </script>
    </body>
    </html>
    

    相关文章

      网友评论

          本文标题:球体全景图

          本文链接:https://www.haomeiwen.com/subject/gaacsxtx.html