three.js全景漫遊實踐(待續...)

Hello 小夥伴們,若是以爲本文還不錯,記得給個 star , 小夥伴們的 star 是我持續更新的動力!GitHub 地址javascript

簡介

全景圖分兩種

  1. 由六張正方形圖片組成的SkyBox
  2. 一整張的寬高比爲2比1的全景圖片。

今天我就實現一整張全景圖的案例。css

思路

咱們超讚的設計師畫的中秋全景圖(利用透視網格輔助PS繪製)html

建立一個球體網格,對網格進行x軸反轉,使全部的麪點向內

let geometry = new THREE.SphereGeometry( 500, 60, 40 );
geometry.scale( -1, 1, 1 );
複製代碼

使用上面的全景貼圖建立基礎材質java

let material = new THREE.MeshBasicMaterial({
    map: new THREE.TextureLoader().load( 'panorama.jpg'),
    depthTest: false//此參數控制是否使用像素深度來計算新像素的值
});

let mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
複製代碼

把相機設置爲球的中心點git

let camera = new THREE.PerspectiveCamera( 100, window.innerWidth / window.innerHeight, 1, 1100 );
camera.target = new THREE.Vector3( 0, 0, 0 );
camera.position.set(0, 0, 0);
複製代碼

陀螺儀相機控制器,實現移動端陀螺儀控制相機github

let controls = new THREE.DeviceOrientationControls( camera );
複製代碼

此時尚未動畫效果,還須要增長一個實時更新渲染動畫bash

function animate() {
    render();
    requestAnimationFrame(animate);
}
function render() {
    //更新控制器
    controls.update();
    camera.lookAt( camera.target );
    renderer.render(scene, camera);
}
複製代碼

簡單案例代碼

DEMO: songdy.github.io/panorama/si…app

這就簡單實現了一個全景圖,貼出以上的所有代碼dom

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>簡單的全景圖</title>
    <link rel="stylesheet" type="text/css" href="./css/simple-index.css">
</head>
<body>
    <div id="container"></div>
    <script type="text/javascript" src="./js/three.min.js"></script>
    <script type="text/javascript" src="./js/DeviceOrientationControls.js"></script>
    <script type="text/javascript">
    class panorama{
        constructor () {
            this.scene = new THREE.Scene();
            this.initCamera();
            this.initMesh();
            this.initRenderer();
            this.animate();
        }

        initCamera () {
            let camera = this.camera = new THREE.PerspectiveCamera( 100, window.innerWidth / window.innerHeight, 1, 1100 );
            camera.position.set(0, 0, 0);

            this.controls = new THREE.DeviceOrientationControls( camera );
            this.controls.connect();
        }
        initMesh () {
            let geometry = new THREE.SphereGeometry( 500, 60, 40 );
            geometry.scale( -1, 1, 1 );
            geometry.rotateY(-Math.PI / 2)

            let material = new THREE.MeshBasicMaterial({
                map: new THREE.TextureLoader().load('./textures/SphericalMap.jpg')
            });

            let mesh = new THREE.Mesh( geometry, material );
            this.scene.add( mesh );
        }
        initRenderer () {
            let container = document.getElementById( 'container' );
            let renderer = this.renderer = new THREE.WebGLRenderer({ logarithmicDepthBuffer: true });
            renderer.setPixelRatio( window.devicePixelRatio );
            renderer.setSize( window.innerWidth, window.innerHeight );
            renderer.sortObjects = false;
            renderer.autoClear = false;
            container.appendChild( renderer.domElement );
        }
        animate() {
            this.render();
            requestAnimationFrame( ()=>{this.animate()});
        }
        render() {
            //更新控制器
            this.controls.update();
            this.renderer.render(this.scene, this.camera);
        }
    }
    new panorama();
    </script>
</body>
</html>
複製代碼

相機

直接上圖,常規的全景漫遊的進場效果:動畫

左邊是效果,右邊是相機輔助效果。

思路分析

相機起始在球體接近頂部位置,從上往下看

let camera = new THREE.PerspectiveCamera( 150, window.innerWidth / window.innerHeight, 1, 2000 );
camera.position.set(0, 450, 0);//相機定位在y軸450
camera.target = new THREE.Vector3( 0, -500, 0 );//設置目標點
camera.lookAt( camera.target );//看向y軸負方向
複製代碼

相機有上往下移動到求的中心點(0, 0, 0)。同時,相機目標點從底部(0, -500, 0)轉到背面(0, 0, -500)。把fov從150調整爲100,效果更讚了。

new TWEEN.Tween( { y : 450, lat : 0, fov : 150 } )
    .to( { y : 0, lat : 90, fov : 100 }, 2500 )
    .onUpdate(function() {
        camera.position.y = this.y;
        let phi = THREE.Math.degToRad( this.lat );
        camera.target.y = -500 * Math.cos( phi );
        camera.target.z = -500 * Math.sin( phi );
        camera.fov = this.fov;
        camera.updateProjectionMatrix();
    })
複製代碼

進場案例代碼

DEMO: songdy.github.io/panorama/ca…

輔助理解DEMO: songdy.github.io/panorama/ca…

把簡單版加入進場效果

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>玩轉相機</title>
    <link rel="stylesheet" type="text/css" href="./css/simple-index.css">
</head>
<body>
    <div id="container"></div>
    <script type="text/javascript" src="./js/three.min.js"></script>
    <script type="text/javascript" src="./js/DeviceOrientationControls.js"></script>
    <script type="text/javascript" src="./js/Tween.js"></script>
    <script type="text/javascript">
    class panorama{
        constructor () {
            this.SCREEN_WIDTH = window.innerWidth;
            this.SCREEN_HEIGHT = window.innerHeight;
            this.scene = new THREE.Scene();
            this.initCamera();
            this.initMesh();
            this.initRenderer();
            this.animate();
            this.start();
        }
        initCamera () {
            let aspect = this.SCREEN_WIDTH / this.SCREEN_HEIGHT;
            this.camera = new THREE.PerspectiveCamera( 150, 0.5 * aspect, 1, 2000 );
            this.camera.position.set(0, 450, 0);
            this.camera.target = new THREE.Vector3( 0, -1, 0 );

        }
        initMesh () {
            let geometry = new THREE.SphereGeometry( 500, 60, 40 );
            geometry.scale( -1, 1, 1 );
            geometry.rotateY(-Math.PI / 2)
            let material = new THREE.MeshBasicMaterial({
                map: new THREE.TextureLoader().load('./textures/SphericalMap.jpg')
            });
            this.mesh = new THREE.Mesh( geometry, material );
            this.scene.add( this.mesh );
        }
        initRenderer () {
            let container = document.getElementById( 'container' );
            let renderer = this.renderer = new THREE.WebGLRenderer({ logarithmicDepthBuffer: true });
            renderer.setPixelRatio( window.devicePixelRatio );
            renderer.setSize( window.innerWidth, window.innerHeight );
            renderer.sortObjects = false;
            renderer.autoClear = false;
            container.appendChild( renderer.domElement );
        }
        start () {
                let {camera} = this;
                new TWEEN.Tween( { lat : 0, y : camera.position.y, fov : camera.fov } )
                .to( { lat: 90, y : 0, fov : 100 }, 2500 )
                .delay(1000)
                .easing(TWEEN.Easing.Cubic.InOut)
                .repeat(Infinity)
                .onUpdate(function() {
                    let phi = THREE.Math.degToRad( this.lat );
                    camera.target.y = -500 * Math.cos( phi );
                    camera.target.z = -500 * Math.sin( phi );
                    camera.position.y = this.y;
                    camera.fov = this.fov;
                    camera.updateProjectionMatrix();
                })
                .start()        
        }
        animate() {
            this.render();
            requestAnimationFrame( ()=>{this.animate()});
        }
        render() {
            TWEEN.update();
            this.camera.lookAt( this.camera.target );
            this.renderer.clear();
            this.renderer.render( this.scene, this.camera );
        }
    }
    new panorama();
    </script>
</body>
</html>
複製代碼
相關文章
相關標籤/搜索