利用threejs实现3D全景图

kumfo

threejs下载位置:http://www.threejs.org
我在Facebook上看到Facebook实现了3D全景图,然后,一直很好奇,最后,我发现threejs里面有一个库竟然可以实现,一下我贴出代码:


<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
    <title>three.js css3d - panorama</title>
    <style>
        body {
            background-color: #000000;
            margin: 0;
            cursor: move;
            overflow: hidden;
        }

        a {
            color: #ffffff;
        }

        #info {
            position: absolute;
            width: 100%;
            color: #ffffff;
            padding: 5px;
            font-family: Monospace;
            font-size: 13px;
            font-weight: bold;
            text-align: center;
            z-index: 1;
        }
    </style>
</head>
<body>
<script src="../build/three.min.js"></script> <!-- 此处引入threejs基础类 -->
<script src="js/renderers/CSS3DRenderer.js"></script> <!-- 此处引入CSS3Drenderer.js类 -->
<!-- 以上两个文件,在下载threejs的时候就有的,引入就好 -->
<script>
    var camera, scene, renderer;
    var geometry, material, mesh;
    var target = new THREE.Vector3();

    var lon = 90, lat = 0;
    var phi = 0, theta = 0;

    var touchX, touchY;

    init();
    animate();

    function init() {

        camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 1000 );

        scene = new THREE.Scene();
/** 次数是重点说明的
 * 这个sides对应的是六张图位于立体坐标轴内的位置,里面的position又包含x,y,三个轴
 * 然后ratation是三个轴上的变换
 */ 
        var sides = [
            {
                position: [ 512, 0, 0 ], // 1
                rotation: [ 0, -Math.PI / 2, 0 ]
            },
            {
                position: [ -512, 0, 0 ], // 2
                rotation: [ 0, Math.PI / 2, 0 ]
            },
            {
                position: [ 0,  512, 0 ], // 3
                rotation: [ Math.PI / 2, 0, Math.PI ]
            },
            {
                position: [ 0, -512, 0 ], // 4
                rotation: [ - Math.PI / 2, 0, Math.PI ]
            },
            {
                position: [ 0, 0,  512 ], // 5
                rotation: [ 0, Math.PI, 0 ]
            },
            {
                position: [ 0, 0, -512 ], // 6
                rotation: [ 0, 0, 0 ]
            }
        ];

        var canvas = document.createElement('canvas');
        var image = document.createElement('img');
        image.src = 'picture/360photos.jpg'; // 画图,这里引入的这张图片,是一张图上集合了6张图片
        image.height = 6144;
        image.width = 1024;
        canvas.width = 1024;
        canvas.height = 1024;
        // 这里有判断image.onload,这里是判断创建的image节点是否把引入的图片加载进来
            image.onload = function() {
                for ( var i = 0; i < sides.length; i ++ ) { // 由于是六张图放在一张图片上,然后这里分割六张图片
                    var cxt = canvas.getContext("2d");
                    cxt.drawImage(image, 0, -1024*i);
                    var side = sides[ i ];

                    var element = document.createElement( 'img' );
                    element.width = 1026; // 2 pixels extra to close the gap.
                    document.getElementsByTagName('body')[0].appendChild(canvas);
                    var _img_url = canvas.toDataURL("image/png"); // 获取图片位置
                    element.src = _img_url;
                    var object = new THREE.CSS3DObject( element ); // 这里根据sides把图片放在坐标轴上进行渲染
                    object.position.fromArray( side.position );
                    object.rotation.fromArray( side.rotation );
                    scene.add( object );
                }
        }


        renderer = new THREE.CSS3DRenderer();
        renderer.setSize( window.innerWidth, window.innerHeight );
        document.body.appendChild( renderer.domElement );

        //

        document.addEventListener( 'mousedown', onDocumentMouseDown, false );
        document.addEventListener( 'mousewheel', onDocumentMouseWheel, false );

        document.addEventListener( 'touchstart', onDocumentTouchStart, false );
        document.addEventListener( 'touchmove', onDocumentTouchMove, false );

        window.addEventListener( 'resize', onWindowResize, false );

    }

    function onWindowResize() {

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

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

    }

    function onDocumentMouseDown( event ) {

        event.preventDefault();

        document.addEventListener( 'mousemove', onDocumentMouseMove, false );
        document.addEventListener( 'mouseup', onDocumentMouseUp, false );

    }

    function onDocumentMouseMove( event ) {

        var movementX = event.movementX || event.mozMovementX || event.webkitMovementX || 0;
        var movementY = event.movementY || event.mozMovementY || event.webkitMovementY || 0;

        lon -= movementX * 0.1;
        lat += movementY * 0.1;

    }

    function onDocumentMouseUp( event ) {

        document.removeEventListener( 'mousemove', onDocumentMouseMove );
        document.removeEventListener( 'mouseup', onDocumentMouseUp );

    }

    function onDocumentMouseWheel( event ) {

        camera.fov -= event.wheelDeltaY * 0.05;
        camera.updateProjectionMatrix();

    }

    function onDocumentTouchStart( event ) {

        event.preventDefault();

        var touch = event.touches[ 0 ];

        touchX = touch.screenX;
        touchY = touch.screenY;

    }

    function onDocumentTouchMove( event ) {

        event.preventDefault();

        var touch = event.touches[ 0 ];

        lon -= ( touch.screenX - touchX ) * 0.1;
        lat += ( touch.screenY - touchY ) * 0.1;

        touchX = touch.screenX;
        touchY = touch.screenY;

    }

    function animate() {

        requestAnimationFrame( animate );

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

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

        camera.lookAt( target );

        renderer.render( scene, camera );

    }

</script>
</body>
</html>

以上,我把重要的说明点都写上了注释,然后,注意,我这里的图片是去facebook上下载下来的,我把Facebook上的图片手动进行了左右翻转实现的程序,如果不需要手动翻转,如果是渲染Facebook上的图片的话,需要把Facebook的图片用程序进行翻转再分割才能渲染出正常的图片,否则渲染出来的全景是不正常的。
我下面附上的图很大,宽度是1024像素的,然后高度是1024像素*6;原图是这张图的左右翻转。
下面,我附上图,此图来自简书上传的,可能会有盗链导致加载不出来:

360photos.jpg

阅读 31.2k

Kumfo的杂货铺
做一些经验总结和一些学习心得分享,主要围绕PHP。 现在正在学习机器学习,会增加一些机器学习的思考分享。
avatar
kumfo
SegmentFault 后端工程师

程序生存法则:ฏ๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎...

6.4k 声望
4.1k 粉丝
0 条评论
avatar
kumfo
SegmentFault 后端工程师

程序生存法则:ฏ๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎...

6.4k 声望
4.1k 粉丝
文章目录
宣传栏