(第三節)全景漫遊

1、實驗內容

經過上次實驗,瞭解了Three.js建立場景的基本步驟。這一節,咱們將經過Three.js實現全景漫遊功能。以下圖:
這裏寫圖片描述html

全景圖是獲取一個3D場景中的不一樣角度的圖片,而後經過拼接、融合實現3D的虛擬場景。例如百度地圖上全景漫遊。html5

2、探討

方法1:使用軟件(例如:Pano2vr )
前提準備:下載Pano2vr軟件;全景圖。
全景圖:對於現實世界,能夠經過魚眼攝像頭拍攝獲得全景圖;對於虛擬世界,使用3D模型軟件,例如3dMaxs,導入場景模型,生成全景圖。
有點:能夠導出flash、html5等格式的全景漫遊。你只須要準備一張全景圖就能夠。java

這裏咱們使用的是另一種方法,使用Three.js實現全景漫遊的功能,這樣有利於咱們之後的功能擴展。web

3、全景漫遊基本知識

全景圖經過廣角的表現手段以及繪畫、相片、視頻、三維模型等形式,儘量多表現出周圍的環境。360全景,即經過對專業相機捕捉整個場景的圖像信息或者使用建模軟件渲染事後的圖片,使用軟件進行圖片拼合,並用專門的播放器進行播放,即將平面照片或者計算機建模圖片變爲360 度全觀,用於虛擬現實瀏覽,把二維的平面圖模擬成真實的三維空間,呈現給觀賞者。[1]markdown

實現360度全景漫遊的有3種方法,1)球形圖、2)圓柱圖、3)正方體。
對基本原理比較感興趣的朋友能夠去看看這篇博客,寫的很詳細。
https://aotu.io/notes/2016/01/02/3D-panorama/?utm_source=tuicool&utm_medium=referralapp

注:圓柱圖實現方法的肯定比較明顯,因此使用的比較少。上面提到的軟件實現全景漫遊,使用的是球形的方法。這裏咱們實現的方法是正方體。dom

4、實驗步驟

一、建立場景:ide

/** * 建立場景 * @type {THREE.Scene} */
scene = new THREE.Scene();

二、添加相機
這裏咱們使用的是透視相機。函數

/** * 添加相機 * @type {THREE.PerspectiveCamera} */
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

三、添加渲染器
這裏使用的是CSS3DRenderer渲染器,要在html文件中添加:
這裏寫圖片描述ui

/** * 添加一個渲染器 * @type {THREE.CSS3DRenderer} */
renderer = new THREE.CSS3DRenderer();
renderer.setClearColor(0x000000, 1.0);
renderer.setSize(window.innerWidth, window.innerHeight);

四、建立正方體
建立正方體,分別對正方體的六個面進行貼圖

/** *正方體的6個面的資源及相關(座標、旋轉等)設置 */
var sides = [{url: './images/posx.jpg', position: [-512, 0, 0], rotation: [0, Math.PI / 2, 0]},
            {url: './images/negx.jpg', position: [512, 0, 0], rotation: [0, -Math.PI / 2, 0]},
            {url: './images/posy.jpg', position: [0, 512, 0], rotation: [Math.PI / 2, 0, Math.PI]},
            {url: './images/negy.jpg', position: [0, -512, 0], rotation: [-Math.PI / 2, 0, Math.PI]},
            {url: './images/posz.jpg', position: [0, 0, 512], rotation: [0, Math.PI, 0]},
            {url: './images/negz.jpg',position: [0, 0, -512], rotation: [0, 0, 0]}];

for (var i = 0; i < sides.length; i++) {
    var side = sides[i];
    var element = document.createElement('section');
    document.body.appendChild(element);
    element.id = 'section_'+ i;
    var imgElement = document.createElement('img');
    imgElement.width = 1028; // 2 pixels extra to close the gap.
    imgElement.height = 1028;
    imgElement.src = side.url;
    element.appendChild(imgElement);
    var object = new THREE.CSS3DObject(element);
    object.position.set(side.position[0], side.position[1], side.position[2]);
    object.rotation.set(side.rotation[0], side.rotation[1], side.rotation[2]);
    scene.add(object);
}

五、實時渲染函數

/** * 實時渲染函數 */
function render() {
    requestAnimationFrame(render);
    lon = Math.max(-180, Math.min(180, lon));//限制固定角度內旋轉
    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);
}

六、窗口改變時對camera焦點的處理

/** * 窗體大小改變 */
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;
}

5、總結

開始導師要實現全景圖的功能,開始對這方面的知識不瞭解,無從下手。後來經過查找資料,看論文等掌握了全景漫遊的基本知識點。經過此次式樣,掌握了全景漫遊功能的基本原理已經實現方法。

6、完整代碼

main.js

var scene, renderer, camera;
var target = new THREE.Vector3();   //相機焦點
var lon = 90, lat = 0;
var phi = 0, theta = 0;
var touchX, touchY;

function init() {
    /** * 建立場景 * @type {THREE.Scene} */
    scene = new THREE.Scene();

    /** * 添加相機 * @type {THREE.PerspectiveCamera} */
    camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

    /** * 添加一個渲染器 * @type {THREE.CSS3DRenderer} */
    renderer = new THREE.CSS3DRenderer();
    renderer.setClearColor(0x000000, 1.0);
    renderer.setSize(window.innerWidth, window.innerHeight);

    /** *正方體的6個面的資源及相關(座標、旋轉等)設置 */
    var sides = [{url: './images/posx.jpg', position: [-512, 0, 0], rotation: [0, Math.PI / 2, 0]},
                {url: './images/negx.jpg', position: [512, 0, 0], rotation: [0, -Math.PI / 2, 0]},
                {url: './images/posy.jpg', position: [0, 512, 0], rotation: [Math.PI / 2, 0, Math.PI]},
                {url: './images/negy.jpg', position: [0, -512, 0], rotation: [-Math.PI / 2, 0, Math.PI]},
                {url: './images/posz.jpg', position: [0, 0, 512], rotation: [0, Math.PI, 0]},
                {url: './images/negz.jpg',position: [0, 0, -512], rotation: [0, 0, 0]}];

    for (var i = 0; i < sides.length; i++) {
        var side = sides[i];
        var element = document.createElement('section');
        document.body.appendChild(element);
        element.id = 'section_'+ i;
        var imgElement = document.createElement('img');
        imgElement.width = 1028; // 2 pixels extra to close the gap.
        imgElement.height = 1028;
        imgElement.src = side.url;
        element.appendChild(imgElement);
        var object = new THREE.CSS3DObject(element);
        object.position.set(side.position[0], side.position[1], side.position[2]);
        object.rotation.set(side.rotation[0], side.rotation[1], side.rotation[2]);
        scene.add(object);
    }
    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);

    render();
}


/** * 實時渲染函數 */
function render() {
    requestAnimationFrame(render);
    lon = Math.max(-180, Math.min(180, lon));//限制固定角度內旋轉
    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);
}

/** * 窗體大小改變 */
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;
}

/** * 腳本入口 * @type {init} */
window.onload = init;

引用
1:百度百科 http://baike.baidu.com/view/2424250.htm

相關文章
相關標籤/搜索