threejs全景圖和錨點編輯的實現(xiàn)方案
全景圖和錨點編輯
今天來簡單聊聊threejs全景圖和錨點編輯的方案。 全景圖也就是所謂的天空盒子,所應(yīng)用到的場景例如:場景模型的天空背景、夜晚的星空背景、VR看房等~
錨點編輯這篇重點講一講錨點編輯,也就是所謂場景編輯的方案。其中思想無限接近于Low Code,說到Low Code!我拖更了四篇文章,由于過年那段時間太忙了,實在是沒時間更新!看到許多人都在等我完事,感到十分抱歉,后續(xù)一定會整理好更新!
全景圖
其實全景圖沒什么內(nèi)容??梢韵胂蟪梢粋€非常大正方體的盒子,通過六個面的圖片銜接而成。而我們相機則是存在于正方體內(nèi)部,這樣就能形成一個視覺誤差,認為我們處于場景中。
全景圖拆解
以下就是全景圖正方體拆解圖,六個面互相銜接,可以腦補下當將這個正方體組裝后,我們所看到就是一個無縫銜接的一個場景,當然認真看還是可以看出正方體的邊界處。

可以把骰子腦補成相機所在的位置,這樣就很容易理解

既然有天空盒子,那多個場景的天空盒子肯定存在不同之處。在我們切換場景如何切換對應(yīng)的天空盒子呢?很簡單,我們只需封裝一個切換函數(shù)如下
// 添加地面和天空盒
Viewer.prototype.changeSkyBox = function (skydir) {
const that = this
// 創(chuàng)建幾何模型 BoxGeometry('x軸', '軸', 'z軸')
const geometry = new THREE.BoxGeometry(999, 999, 999)
// 創(chuàng)建紋理貼圖 前后 上下 左右
const texture0 = new THREE.TextureLoader().load((gAppPath + `/images/ysThree/sky/${skydir}/px.jpg`))
const texture1 = new THREE.TextureLoader().load((gAppPath + `/images/ysThree/sky/${skydir}/nx.jpg`))
const texture2 = new THREE.TextureLoader().load((gAppPath + `/images/ysThree/sky/${skydir}/py.jpg`))
const texture3 = new THREE.TextureLoader().load((gAppPath + `/images/ysThree/sky/${skydir}/ny.jpg`))
const texture4 = new THREE.TextureLoader().load((gAppPath + `/images/ysThree/sky/${skydir}/pz.jpg`))
const texture5 = new THREE.TextureLoader().load((gAppPath + `/images/ysThree/sky/${skydir}/nz.jpg`))
// 添加材質(zhì)
const material = [
new THREE.MeshBasicMaterial({color: 0xffddff, map: texture0, side: THREE.DoubleSide}),
new THREE.MeshBasicMaterial({color: 0xffddff, map: texture1, side: THREE.DoubleSide}),
new THREE.MeshBasicMaterial({color: 0xffddff, map: texture2, side: THREE.DoubleSide}),
new THREE.MeshBasicMaterial({color: 0xffddff, map: texture3, side: THREE.DoubleSide}),
new THREE.MeshBasicMaterial({color: 0xffddff, map: texture4, side: THREE.DoubleSide}),
new THREE.MeshBasicMaterial({color: 0xffddff, map: texture5, side: THREE.DoubleSide})
]
// 創(chuàng)建網(wǎng)格對象
const cube = new _3d.Mesh(geometry, material)
cube.layers.enableAll()
cube.name = 'skybox'
that.skybox && this.scene.remove(that.skybox)
that.skybox = cube
that.AmbientGroup.add(cube)
}場景編輯方案
不同場景的燈光位置以及圖標點位可能不同,作為一個基礎(chǔ)編輯平臺,我們肯定要考慮如何將我們的場景變成可配置化,根據(jù)不同的需求做出不同的改變。之前的文章介紹過我們將模型通過JSON的形式去配置,那我們?nèi)绾螌鼍爸械狞c位以及燈光位置做出配置呢?
transformControls
變換控制器,這里它的作用主要是對錨點的平移、縮放、旋轉(zhuǎn)操作
初始化控制器
//移動控制器 this.transformControls = new TransformControls(this.camera, this.renderer.domElement) this.transformControls.setSize(0.5) this.scene.add(this.transformControls) //添加入場景
添加可移動對象
我們可以在比如說燈光類中,添加一個transform_attach方法,在啟用編輯后調(diào)用該方法。只有attach后才能夠被拾取,進行平移、旋轉(zhuǎn)、縮放的操作
transformControls.attach(...)
//對象類中
transform_attach(value){
if (value) {
this.transformControls.attach(this.dlight)
}
else {
this.transformControls.detach(this.dlight)
}
}平移、縮放、旋轉(zhuǎn)
gapp.history.execute 這里主要是業(yè)務(wù)邏輯,將編輯后的對象保存起來,主要用于回顯
SetPositionCommand 這里主要的作用是記錄下舊的位置信息與新的位置信息
拋開上面兩個方法,其實只要添加進變換控制器就可以對物體就行操作了,下面我單獨介紹為什么需要保存信息
Viewer.prototype.bindTransformEvent = function () {
this.transformControls.addEventListener('mouseDown', () => { //鼠標拾取到
var object = gapp.transformControls.object //獲取拾取對象
this.objectPositionOnDown = object.position.clone()//保存位置
this.objectRotationOnDown = object.rotation.clone()//保存角度
this.objectScaleOnDown = object.scale.clone()//保存縮放大小
gapp.controls.enabled = false
})
this.transformControls.addEventListener('mouseUp', () => {//鼠標提起
var object = gapp.transformControls.object//獲取拾取對象
if (object !== undefined) {
switch (gapp.transformControls.getMode()) { //這里判斷是要進行平移、縮放、旋轉(zhuǎn)操作
case 'translate':
if (!this.objectPositionOnDown.equals(object.position)) {
gapp.history.execute(new SetPositionCommand(this, object, object.position, this.objectPositionOnDown))
}
break
case 'rotate':
if (!this.objectRotationOnDown.equals(object.rotation)) {
gapp.history.execute(new SetRotationCommand(this, object, object.rotation, this.objectRotationOnDown))
}
break
case 'scale':
if (!this.objectScaleOnDown.equals(object.scale)) {
gapp.history.execute(new SetScaleCommand(this, object, object.scale, this.objectScaleOnDown))
}
break
}
}
gapp.controls.enabled = true
})
}保存對象
其實這里和我Low Code的思想很像,就是我們最終要將所有配置好的物體信息保存成一個JSON的形式。以便于在任意其它項目中做回顯。怎么回顯呢? 假如說我們現(xiàn)在編輯好一個燈光的位置信息以及通過gui調(diào)整好的顏色、亮度等,我們可以將該燈光object對象通過toJSON轉(zhuǎn)成JSON后存儲于我們最終對象中,后續(xù)通過接口取回JSON通過轉(zhuǎn)化重新add到場景中即可
//轉(zhuǎn)化為threejs特有的json格式
scene.toJSON()
(了解過json的同學(xué)可以發(fā)現(xiàn),threejs為了縮小大小,將瓦片對象最大限度的拆分材質(zhì)等,通過id關(guān)聯(lián)并保存為json)
//解析json轉(zhuǎn)為對象
Viewer.prototype.fromJSON = function (json, layeridx, isRayobj) {
return new Promise((resolve, reject) => {
// 解析 json 對象
let loader = new THREE.ObjectLoader();
let loadedMesh = loader.parse(json);
let scene = this.mergeToMaterialsMap(loadedMesh, true)
resolve(scene)
})
}結(jié)語
這篇文章主要介紹思想,相對來說這篇文章比較基礎(chǔ),當然后續(xù)可以根據(jù)自己的要求進行擴展
到此這篇關(guān)于threejs全景圖和錨點編輯的文章就介紹到這了,更多相關(guān)threejs全景圖和錨點編輯內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Webpack打包時將文件內(nèi)聯(lián)方法實現(xiàn)
本文主要介紹了Webpack打包時將文件內(nèi)聯(lián)方法實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友們下面隨著小編來一起學(xué)習學(xué)習吧2023-01-01
js實現(xiàn)控制文件拖拽并獲取拖拽內(nèi)容功能
本片文章主要給大家分享了用JS寫出控制文件拖拽并獲取拖拽內(nèi)容功能實現(xiàn)過程,以及代碼分享,有興趣的一起學(xué)習下。2018-02-02
Javascript的promise,async和await的區(qū)別詳解
這篇文章主要為大家詳細介紹了Javascript的promise,async和await的區(qū)別,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-03-03
JS實現(xiàn)的另類手風琴效果網(wǎng)頁內(nèi)容切換代碼
這篇文章主要介紹了JS實現(xiàn)的另類手風琴效果網(wǎng)頁內(nèi)容切換代碼,通過JavaScript響應(yīng)鼠標事件動態(tài)操作頁面元素樣式屬性實現(xiàn)手風琴效果,具有一定參考借鑒價值,需要的朋友可以參考下2015-09-09

