DS-SDK封裝ThreeJS的三維場(chǎng)景核心庫(kù)Viewer
正文
viewer核心庫(kù)的封裝主要是針對(duì)threejs場(chǎng)景進(jìn)行初始封裝,以便多項(xiàng)目復(fù)用。具體細(xì)節(jié)我就不多寫了,網(wǎng)上一大堆,但是我發(fā)現(xiàn)網(wǎng)上的例子都比較雷同,所以我的這一篇文檔會(huì)著重從我做過(guò)的項(xiàng)目上遇到的一些問(wèn)題來(lái)具體描寫,詳細(xì)請(qǐng)看第七、第八小節(jié),主要是第一我們真實(shí)項(xiàng)目中,其實(shí)你的渲染頁(yè)面不是整個(gè)頁(yè)面,而且其中的一小塊div,所以你的寬高是div而不是windws的(如下圖);第二對(duì)于頁(yè)面大小變化的監(jiān)視,以我的知識(shí)結(jié)構(gòu)來(lái)說(shuō),還沒有很好的解決方案來(lái)監(jiān)視div的大小變化。

基礎(chǔ)封裝初始化包括以下:
一、ThreeJS-ES6庫(kù)引入
引入部分除了ThreeJS核心庫(kù)的東西外,還有標(biāo)簽渲染器,用于后期在場(chǎng)景中添加標(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,然后初始化場(chǎng)景渲染器,初始化二維標(biāo)簽渲染器,和三維標(biāo)簽渲染器。 這一部分代碼我們?cè)O(shè)置渲染器的大小,這個(gè)放到了后面會(huì)講。
_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è)置像素深度(用來(lái)度量圖像的分辨率)
preserveDrawingBuffer: true // true/false 表示是否保存繪圖緩沖
})
this.renderer.domElement.style.zIndex = 1
// 默認(rèn)情況下,js的光強(qiáng)數(shù)值不真實(shí)。為了使得光強(qiáng)更趨于真實(shí)值,應(yīng)該把渲染器的physicallyCorrectLights屬性設(shè)為true
this.renderer.physicallyCorrectLights = true
// 盡管我們的貼圖不是HDR,但使用tone mapping可以塑造更真實(shí)的效果。
this.renderer.toneMapping = ACESFilmicToneMapping
// 場(chǎng)景中的陰影自動(dòng)更新
this.renderer.shadowMap.enabled = true
// 設(shè)置渲染器開啟陰影貼圖,并將類型設(shè)為PCFSoftShadowMap
this.renderer.shadowMap.type = PCFSoftShadowMap
// 這下我們可以看到更亮的材質(zhì),同時(shí)這也影響到環(huán)境貼圖。
this.renderer.outputEncoding = sRGBEncoding
// 一個(gè)canvas,渲染器在其上繪制輸出。
this.viewerDom.appendChild(this.renderer.domElement)
// 網(wǎng)頁(yè)標(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)簽遮擋三維場(chǎng)景的鼠標(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)簽遮擋三維場(chǎng)景的鼠標(biāo)事件
this.css3DRenderer.domElement.style.pointerEvents = 'none'
this.viewerDom.appendChild(this.css3DRenderer.domElement)
}
三、初始化相機(jī)
相機(jī)參數(shù)里面的aspect(攝像機(jī)視錐體長(zhǎng)寬比),其實(shí)應(yīng)該是畫布dom的長(zhǎng)寬比,而不是我們?yōu)g覽器windows的長(zhǎng)寬比,請(qǐng)你仔細(xì)品品這句話。
參數(shù) 構(gòu)造器 PerspectiveCamera( fov : Number, aspect : Number, near : Number,> far : Number ) fov — 攝像機(jī)視錐體垂直視野角度 aspect — 攝像機(jī)視錐體長(zhǎng)寬比 near — 攝像機(jī)視錐體近端面 far — 攝像機(jī)視錐體遠(yuǎn)端面
_initCamera () {
// 渲染相機(jī)
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)
}
四、初始化場(chǎng)景
_initScene () {
// 渲染場(chǎng)景
this.scene = new Scene()
this.scene.background = new Color('rgb(5,24,38)')
}
五、初始化鼠標(biāo)控制器
控制器主要是用來(lái)控制通過(guò)鼠標(biāo)漫游場(chǎng)景的。
參數(shù) OrbitControls(object:Camera,domElement:HTMLDOMElement) object:(必需)要控制的攝像機(jī)。相機(jī)不得是其他對(duì)象的子對(duì)象,除非該對(duì)象是場(chǎng)景本身。 domElement:用于事件偵聽器的HTML元素。
_initControl (option) {
this.controls = new OrbitControls(this.camera, this.renderer.domElement)
this.controls.enableDamping = false
this.controls.maxPolarAngle = Math.PI * 0.46// 垂直軌道多遠(yuǎn) 上限
this.controls.minPolarAngle = Math.PI * 0.3// 你可以垂直軌道多遠(yuǎn),下限
this.controls.screenSpacePanning = false // 定義平移時(shí)如何平移相機(jī)的位置 控制不上下移動(dòng)
}
六、燈光初始化
沒有燈光的話,就會(huì)一片漆黑,所以需要添加燈光。
// 全局光不需要 const ambientLight = new DS.THREE.AmbientLight(0xffffff, 0.2) viewer.scene.add(ambientLight)
七、全局渲染的函數(shù)-逐幀獲取頁(yè)面大小
這里是全局渲染的函數(shù),通過(guò)requestAnimationFrame函數(shù),可以逐幀去渲染場(chǎng)景。 攝像機(jī)視錐體的長(zhǎng)寬比,設(shè)置渲染器的長(zhǎng)寬比,都是這里一直去獲取傳入的div,而不是window的大小,設(shè)置參數(shù)(雖然這樣寫會(huì)很耗費(fèi)性能,但是我也沒有找到更好的方法去監(jiān)聽頁(yè)面的大小變化)。
function animate () {
requestAnimationFrame(animate)
that._undateDom()
that._readerDom()
// 全局的公共動(dòng)畫函數(shù),添加函數(shù)可同步執(zhí)行
that.animateEventList.forEach(event => {
event.fun && event.content && event.fun(event.content)
})
}
animate()
// 更新dom大小
_undateDom () {
const that = this
that.controls.update()
// 攝像機(jī)視錐體的長(zhǎng)寬比,通常是使用畫布的寬/畫布的高,所以這里的畫布指的是dom,就是一個(gè)div,而不是window
that.camera.aspect = that.viewerDom.clientWidth / that.viewerDom.clientHeight
// 更新攝像機(jī)投影矩陣。在任何參數(shù)被改變以后必須被調(diào)用,來(lái)使得這些改變生效
that.camera.updateProjectionMatrix()
//設(shè)置渲染器的長(zhǎng)寬比,所以就不需要在代碼里面去寫window的頁(yè)面監(jiān)聽,來(lái)改變頁(yè)面大小【】
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)
}
八、全局動(dòng)畫函數(shù)
這里我做了一個(gè)全局所有動(dòng)畫的管理器,頁(yè)面上所有的需要?jiǎng)赢嫷暮瘮?shù)都可以傳入運(yùn)行,包括模型的動(dòng)畫、加載水面的運(yùn)動(dòng)、貼圖的UV動(dòng)畫。
動(dòng)畫函數(shù)數(shù)組用來(lái)存儲(chǔ)所有的動(dòng)畫函數(shù)
//動(dòng)畫函數(shù)數(shù)組 this.animateEventList = []
對(duì)動(dòng)畫函數(shù)的添加
/**
* 添加全局的動(dòng)畫事件
* @param animate 函數(shù)加參數(shù)對(duì)象
* 傳入對(duì)象 = {
fun: 函數(shù)名稱,
content: 函數(shù)參數(shù)
}
*/
addAnimate (animate) {
this.animateEventList.push(animate)
}
這里以狀態(tài)監(jiān)視器為例,創(chuàng)建函數(shù),并且添加到全局的動(dòng)畫函數(shù)數(shù)組里面去
/**
* 狀態(tài)更新
* @param statsControls
*/
_statsUpdate (statsControls) {
statsControls.update()
}
/**
* 添加狀態(tài)監(jiān)測(cè)
*/
addStats () {
if (!this.statsControls) this.statsControls = new Stats()
this.statsControls.dom.style.position = 'absolute'
this.viewerDom.appendChild(this.statsControls.dom)
// 添加到動(dòng)畫
this.statsUpdateObject = {
fun: this._statsUpdate, // 函數(shù)名稱,函數(shù)在上面
content: this.statsControls // 綁定傳入的參數(shù)
}
this.addAnimate(this.statsUpdateObject)
}
對(duì)于函數(shù)的移除
/**
* 移除全局的動(dòng)畫事件
* @param animate 函數(shù)加參數(shù)對(duì)象
* 傳入對(duì)象 = {
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)檢測(cè)
*/
removeStats () {
if (this.statsControls) this.viewerDom.removeChild(this.statsControls.dom)
// 添加到動(dòng)畫
this.statsUpdateObject = {
fun: this._statsUpdate,
content: this.statsControls
}
this.removeAnimate(this.statsUpdateObject)
}
九、銷毀頁(yè)面
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()
}
以上就是針對(duì)核心Viewer庫(kù)封裝的一些記錄,也不知道寫得行不行,但是里面寫得一些也是在工作應(yīng)用當(dāng)中遇到的一些真實(shí)問(wèn)題,更多關(guān)于ThreeJS核心庫(kù)Viewer封裝DS-SDK的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
微信小程序?qū)崿F(xiàn)圖片自適應(yīng)(支持多圖)
這篇文章主要介紹了微信小程序如何實(shí)現(xiàn)圖片自適應(yīng)的相關(guān)資料,文中介紹的方法同樣適應(yīng)于多圖,有需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-01-01
TypeScript?泛型接口具體使用實(shí)戰(zhàn)
這篇文章主要為大家介紹了TypeScript?泛型接口具體使用實(shí)戰(zhàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07
ThreeJS使用紋理貼圖創(chuàng)建一個(gè)我的世界草地方塊
這篇文章主要為大家介紹了ThreeJS使用紋理貼圖創(chuàng)建一個(gè)我的世界草地方塊的實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06
TypeScript十大排序算法之選擇排序?qū)崿F(xiàn)示例詳解
這篇文章主要為大家介紹了TypeScript十大排序算法之選擇排序?qū)崿F(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02
PureScript與JavaScript中equality設(shè)計(jì)的使用對(duì)比分析
這篇文章主要為大家介紹了PureScript中的equality與JavaScript中的equality設(shè)計(jì)對(duì)比分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11
Spartacus中navigation?item?reducer實(shí)現(xiàn)解析
這篇文章主要為大家介紹了Spartacus中navigation?item?reducer實(shí)現(xiàn)解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07

