three.js全景漫游實踐

来源:https://www.cnblogs.com/songdy/archive/2019/03/19/panorama1.html
-Advertisement-
Play Games

Hello 小伙伴們,如果覺得本文還不錯,記得給個 star , 小伙伴們的 star 是我持續更新的動力!GitHub 地址 簡介 全景圖分兩種 由六張正方形圖片組成的SkyBox 一整張的寬高比為2比1的全景圖片。 今天我就實現一整張全景圖的案例。 思路 我們超贊的設計師畫的中秋全景圖(利用透視 ...


Hello 小伙伴們,如果覺得本文還不錯,記得給個 star , 小伙伴們的 star 是我持續更新的動力!GitHub 地址

簡介

全景圖分兩種

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

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

思路

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

 

  創建一個球體網格,對網格進行x軸反轉,使所有的面點向內
let geometry = new THREE.SphereGeometry( 500, 60, 40 );
geometry.scale( -1, 1, 1 );

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

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

let mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );

把相機設置為球的中心點

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);

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

let controls = new THREE.DeviceOrientationControls( camera );

此時還沒有動畫效果,還需要增加一個實時更新渲染動畫

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

簡單案例代碼

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

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

<!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>

  

 

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • RadioButton為單選按鈕,他需要與RadioGroup配合使用 對應的佈局代碼: Java代碼: 在上述代碼中,利用setCheckedChangeListener()監聽RadioGroup控制項狀態,獲取監聽結果輸出到TextView控制項里顯示 ...
  • 學CSS很好的一個方法大概是先用純CSS來實現一個自己的框架,然後便可以在之後的使用中對一開始可能很粗糙的框架做細緻的優化與改進,刪除些冗餘,添加些功能之類的。 當然,為了避免一開始寫框架時候的時候手足無措,對一個css框架應該實現些什麼功能不大清楚,便可以參考已有的框架自己重寫一遍,寫的過程中這些 ...
  • 01-jquery簡介1)功能: ·html元素選取 ·Html元素操作 ·Css操作 ·Html事件函數 ·JavaScript特效和動畫 ·DOM的遍歷及修改 ·AJAX ·Utilities ·插件2)版本支持 ·jquery2 及以上不支持IE6,7,8 ·使用註釋: · · ·... ...
  • 解構賦值 Destructuring Assignment ES6中可以通過一定的模式將數組或對象中的值直接賦值給外部變數,稱為解構 對象的解構賦值 對象解構過程中,外部變數名也可以與對象內部變數名不同,但此時不可以使用對象的縮寫形式 對象解構過程中,外部變數名也可以與對象內部變數名不同,但此時不可 ...
  • 什麼是Vue? Vue (讀音 /vjuː/,類似於view) 是一套用於構建用戶界面的漸進式框架。與其它大型框架不同的是,Vue 被設計為可以自底向上逐層應用。Vue 的核心庫只關註視圖層,不僅易於上手,還便於與第三方庫或既有項目整合。另一方面,當與現代化的工具鏈以及各種支持類庫結合使用時,Vue ...
  • 寫在前面得話: 這篇文章主要記錄了我是怎麼一步一步寫出俄羅斯方塊,整個代碼用的函數編程,主要是為了讓一些不熟悉es6, 面向對象寫法得 新手能更容易看明白,全部得代碼中都是一些js的基礎知識,很容易理解。要說有點麻煩的,那就是游戲過程中的各種檢測。但是只要你多思考,你就能理解代碼為什麼要那樣寫,你也 ...
  • 一、語法結構 編程語言的語法結構是一套基礎性規則,用來描述如何使用這門語言來編寫程式。作為語法的基礎,它規定了諸如變數名的命名規範,註釋的規範,以及程式語句之間如何分隔等規則。下麵是介紹JavaScript的基本語法結構。 1、字元集JavaScript程式是用Unicode字元集編寫的,所以它幾乎 ...
  • 堆棧溢出的產生是由於過多的函數調用,導致調用堆棧無法容納這些調用的返回地址,一般容易在遞歸中產生。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...