美文网首页
球体全景图

球体全景图

作者: 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