DS-SDK封裝ThreeJS的三維場景核心庫Viewer
正文
viewer核心庫的封裝主要是針對threejs場景進行初始封裝,以便多項目復(fù)用。具體細節(jié)我就不多寫了,網(wǎng)上一大堆,但是我發(fā)現(xiàn)網(wǎng)上的例子都比較雷同,所以我的這一篇文檔會著重從我做過的項目上遇到的一些問題來具體描寫,詳細請看第七、第八小節(jié),主要是第一我們真實項目中,其實你的渲染頁面不是整個頁面,而且其中的一小塊div,所以你的寬高是div而不是windws的(如下圖);第二對于頁面大小變化的監(jiān)視,以我的知識結(jié)構(gòu)來說,還沒有很好的解決方案來監(jiān)視div的大小變化。
基礎(chǔ)封裝初始化包括以下:
一、ThreeJS-ES6庫引入
引入部分除了ThreeJS核心庫的東西外,還有標(biāo)簽渲染器,用于后期在場景中添加標(biāo)簽,還有控制器何和幀率顯示器。
import { Cache, WebGLRenderer, ACESFilmicToneMapping, PCFSoftShadowMap, sRGBEncoding, PerspectiveCamera, Scene, Color } from 'three' // 二維標(biāo)簽渲染器 import { CSS2DRenderer } from 'three/examples/jsm/renderers/CSS2DRenderer' import { CSS3DRenderer } from 'three/examples/jsm/renderers/CSS3DRenderer' import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js' import Stats from 'three/examples/jsm/libs/stats.module.js'
二、初始化渲染器
初始化渲染器部分主要是獲取渲染畫布的dom,然后初始化場景渲染器,初始化二維標(biāo)簽渲染器,和三維標(biāo)簽渲染器。 這一部分代碼我們設(shè)置渲染器的大小,這個放到了后面會講。
_initRenderer () { // 獲取畫布dom this.viewerDom = document.getElementById(this.id) // 初始化渲染器 this.renderer = new WebGLRenderer({ logarithmicDepthBuffer: true, antialias: true, // true/false表示是否開啟反鋸齒 alpha: true, // true/false 表示是否可以設(shè)置背景色透明 precision: 'highp', // highp/mediump/lowp 表示著色精度選擇 premultipliedAlpha: true, // true/false 表示是否可以設(shè)置像素深度(用來度量圖像的分辨率) preserveDrawingBuffer: true // true/false 表示是否保存繪圖緩沖 }) this.renderer.domElement.style.zIndex = 1 // 默認(rèn)情況下,js的光強數(shù)值不真實。為了使得光強更趨于真實值,應(yīng)該把渲染器的physicallyCorrectLights屬性設(shè)為true this.renderer.physicallyCorrectLights = true // 盡管我們的貼圖不是HDR,但使用tone mapping可以塑造更真實的效果。 this.renderer.toneMapping = ACESFilmicToneMapping // 場景中的陰影自動更新 this.renderer.shadowMap.enabled = true // 設(shè)置渲染器開啟陰影貼圖,并將類型設(shè)為PCFSoftShadowMap this.renderer.shadowMap.type = PCFSoftShadowMap // 這下我們可以看到更亮的材質(zhì),同時這也影響到環(huán)境貼圖。 this.renderer.outputEncoding = sRGBEncoding // 一個canvas,渲染器在其上繪制輸出。 this.viewerDom.appendChild(this.renderer.domElement) // 網(wǎng)頁標(biāo)簽 this.labelRenderer = new CSS2DRenderer() this.labelRenderer.domElement.style.zIndex = 2 this.labelRenderer.domElement.style.position = 'absolute' this.labelRenderer.domElement.style.top = '0px' this.labelRenderer.domElement.style.left = '0px' // 避免HTML標(biāo)簽遮擋三維場景的鼠標(biāo)事件 this.labelRenderer.domElement.style.pointerEvents = 'none' this.viewerDom.appendChild(this.labelRenderer.domElement) // 三維標(biāo)簽 this.css3DRenderer = new CSS3DRenderer() this.css3DRenderer.domElement.style.zIndex = 0 this.css3DRenderer.domElement.style.position = 'absolute' this.css3DRenderer.domElement.style.top = '0px' this.css3DRenderer.domElement.style.left = '0px' // 避免HTML標(biāo)簽遮擋三維場景的鼠標(biāo)事件 this.css3DRenderer.domElement.style.pointerEvents = 'none' this.viewerDom.appendChild(this.css3DRenderer.domElement) }
三、初始化相機
相機參數(shù)里面的aspect(攝像機視錐體長寬比),其實應(yīng)該是畫布dom的長寬比,而不是我們?yōu)g覽器windows的長寬比,請你仔細品品這句話。
參數(shù) 構(gòu)造器 PerspectiveCamera( fov : Number, aspect : Number, near : Number,> far : Number ) fov — 攝像機視錐體垂直視野角度 aspect — 攝像機視錐體長寬比 near — 攝像機視錐體近端面 far — 攝像機視錐體遠端面
_initCamera () { // 渲染相機 this.camera = new PerspectiveCamera(55, window.innerWidth / window.innerHeight, 0.1, 5000) this.camera.position.set(50, 0, 50) this.camera.lookAt(0, 0, 0) }
四、初始化場景
_initScene () { // 渲染場景 this.scene = new Scene() this.scene.background = new Color('rgb(5,24,38)') }
五、初始化鼠標(biāo)控制器
控制器主要是用來控制通過鼠標(biāo)漫游場景的。
參數(shù) OrbitControls(object:Camera,domElement:HTMLDOMElement) object:(必需)要控制的攝像機。相機不得是其他對象的子對象,除非該對象是場景本身。 domElement:用于事件偵聽器的HTML元素。
_initControl (option) { this.controls = new OrbitControls(this.camera, this.renderer.domElement) this.controls.enableDamping = false this.controls.maxPolarAngle = Math.PI * 0.46// 垂直軌道多遠 上限 this.controls.minPolarAngle = Math.PI * 0.3// 你可以垂直軌道多遠,下限 this.controls.screenSpacePanning = false // 定義平移時如何平移相機的位置 控制不上下移動 }
六、燈光初始化
沒有燈光的話,就會一片漆黑,所以需要添加燈光。
// 全局光不需要 const ambientLight = new DS.THREE.AmbientLight(0xffffff, 0.2) viewer.scene.add(ambientLight)
七、全局渲染的函數(shù)-逐幀獲取頁面大小
這里是全局渲染的函數(shù),通過requestAnimationFrame函數(shù),可以逐幀去渲染場景。 攝像機視錐體的長寬比,設(shè)置渲染器的長寬比,都是這里一直去獲取傳入的div,而不是window的大小,設(shè)置參數(shù)(雖然這樣寫會很耗費性能,但是我也沒有找到更好的方法去監(jiān)聽頁面的大小變化)。
function animate () { requestAnimationFrame(animate) that._undateDom() that._readerDom() // 全局的公共動畫函數(shù),添加函數(shù)可同步執(zhí)行 that.animateEventList.forEach(event => { event.fun && event.content && event.fun(event.content) }) } animate() // 更新dom大小 _undateDom () { const that = this that.controls.update() // 攝像機視錐體的長寬比,通常是使用畫布的寬/畫布的高,所以這里的畫布指的是dom,就是一個div,而不是window that.camera.aspect = that.viewerDom.clientWidth / that.viewerDom.clientHeight // 更新攝像機投影矩陣。在任何參數(shù)被改變以后必須被調(diào)用,來使得這些改變生效 that.camera.updateProjectionMatrix() //設(shè)置渲染器的長寬比,所以就不需要在代碼里面去寫window的頁面監(jiān)聽,來改變頁面大小【】 that.renderer.setSize(that.viewerDom.clientWidth, that.viewerDom.clientHeight) //that.renderer.setPixelRatio(window.devicePixelRatio) // 設(shè)置設(shè)備像素比 that.labelRenderer.setSize(that.viewerDom.clientWidth, that.viewerDom.clientHeight) that.css3DRenderer.setSize(that.viewerDom.clientWidth, that.viewerDom.clientHeight) } // 渲染dom _readerDom () { this.renderer.render(this.scene, this.camera) this.labelRenderer.render(this.scene, this.camera) this.css3DRenderer.render(this.css3dScene, this.camera) }
八、全局動畫函數(shù)
這里我做了一個全局所有動畫的管理器,頁面上所有的需要動畫的函數(shù)都可以傳入運行,包括模型的動畫、加載水面的運動、貼圖的UV動畫。
動畫函數(shù)數(shù)組用來存儲所有的動畫函數(shù)
//動畫函數(shù)數(shù)組 this.animateEventList = []
對動畫函數(shù)的添加
/** * 添加全局的動畫事件 * @param animate 函數(shù)加參數(shù)對象 * 傳入對象 = { fun: 函數(shù)名稱, content: 函數(shù)參數(shù) } */ addAnimate (animate) { this.animateEventList.push(animate) }
這里以狀態(tài)監(jiān)視器為例,創(chuàng)建函數(shù),并且添加到全局的動畫函數(shù)數(shù)組里面去
/** * 狀態(tài)更新 * @param statsControls */ _statsUpdate (statsControls) { statsControls.update() }
/** * 添加狀態(tài)監(jiān)測 */ addStats () { if (!this.statsControls) this.statsControls = new Stats() this.statsControls.dom.style.position = 'absolute' this.viewerDom.appendChild(this.statsControls.dom) // 添加到動畫 this.statsUpdateObject = { fun: this._statsUpdate, // 函數(shù)名稱,函數(shù)在上面 content: this.statsControls // 綁定傳入的參數(shù) } this.addAnimate(this.statsUpdateObject) }
對于函數(shù)的移除
/** * 移除全局的動畫事件 * @param animate 函數(shù)加參數(shù)對象 * 傳入對象 = { fun: 函數(shù)名稱, content: 函數(shù)參數(shù) } */ removeAnimate (animate) { this.animateEventList.map((val, i) => { if (val === animate) this.animateEventList.splice(i, 1) }) }
以移除狀態(tài)監(jiān)視器為例
/** * 移除狀態(tài)檢測 */ removeStats () { if (this.statsControls) this.viewerDom.removeChild(this.statsControls.dom) // 添加到動畫 this.statsUpdateObject = { fun: this._statsUpdate, content: this.statsControls } this.removeAnimate(this.statsUpdateObject) }
九、銷毀頁面
beforeDestroy () { this.scene.traverse((child) => { if (child.material) { child.material.dispose() } if (child.geometry) { child.geometry.dispose() } child = null }) this.renderer.forceContextLoss() this.renderer.dispose() this.scene.clear() }
以上就是針對核心Viewer庫封裝的一些記錄,也不知道寫得行不行,但是里面寫得一些也是在工作應(yīng)用當(dāng)中遇到的一些真實問題,更多關(guān)于ThreeJS核心庫Viewer封裝DS-SDK的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
TypeScript十大排序算法插入排序?qū)崿F(xiàn)示例詳解
這篇文章主要為大家介紹了TypeScript十大排序算法插入排序?qū)崿F(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-02-02TypeScript快速學(xué)習(xí)入門基礎(chǔ)語法
TypeScript的基礎(chǔ)語法,包括變量聲明、復(fù)合類型(數(shù)組和對象)、條件控制(if-else和switch)、循環(huán)(for和while)、函數(shù)(基礎(chǔ)和箭頭函數(shù),以及可選參數(shù))、面向?qū)ο筇匦裕杜e、接口、繼承)以及模塊開發(fā)中的導(dǎo)出和導(dǎo)入2024-07-07TypeScript開發(fā)HapiJS應(yīng)用詳解
這篇文章主要為大家介紹了TypeScript開發(fā)HapiJS應(yīng)用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-08-08TypeScript實現(xiàn)十大排序算法之歸并排序示例詳解
這篇文章主要為大家介紹了TypeScript實現(xiàn)十大排序算法之歸并排序示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-02-02TypeScript實現(xiàn)類型安全的EventEmitter
這篇文章主要為大家介紹了TypeScript實現(xiàn)類型安全的EventEmitter示例詳解有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-03-03Typescript是必須要學(xué)習(xí)嗎?如何學(xué)習(xí)TS全棧開發(fā)
Typescript目前在前端,網(wǎng)站,小程序中的位置基本無可替代,同時也可以構(gòu)建完美的CLI應(yīng)用。在移動,桌面,后端方面,性能不是要求很高的情況下完全可以勝任,并且在區(qū)塊鏈,嵌入式,人工智能方面也開始茁壯成長。2022-12-12