ThingJS串结,注意不是 Three.js哑子,是比Three.js 封裝度更高得3D框架,但不是開源的肌割,使用得付費(fèi)卧蜓。也不是特別成熟,僅調(diào)研一波把敞。
1弥奸、場(chǎng)景導(dǎo)入
- 控制臺(tái) 新建項(xiàng)目保存
- 下載 CampusBuilder ,創(chuàng)建一個(gè)場(chǎng)景并導(dǎo)出為 Thingjs 場(chǎng)景包B奋早,如 hmf.tjs 格式
- 控制臺(tái) "我的資源-我的場(chǎng)景-上傳場(chǎng)景"上傳導(dǎo)出的場(chǎng)景包B
- 打開在線開發(fā)平臺(tái)盛霎,通過(guò) "資源-場(chǎng)景資源" 引入場(chǎng)景包B
2、模型制作
提供三種方式制作模型
- 打開在線開發(fā)平臺(tái)耽装,通過(guò) "資源-模型資源" 搜索需要的模型
- 在資源中心愤炸,可找到很多付費(fèi)和免費(fèi)的模型,然后通過(guò)url創(chuàng)建
-
個(gè)人 obj 模型掉奄,將 obj 資源按照以下格式打成zip包
然后在 CampusBuilder 里的DIY模型庫(kù) tab 里點(diǎn)擊上傳資源
3规个、常用操作
- 創(chuàng)建對(duì)象
var truck = app.create({
type: "Thing",
name: "truck",
position: [-5, 0, 0],
url: "https://www.thingjs.com/static/models/truck/",
complete: function() {
console.log("truck created!");
}
});
創(chuàng)建對(duì)象后,設(shè)置其世界坐標(biāo)即可展示在場(chǎng)景中。注意要設(shè)置其父元素诞仓,否則會(huì)直接掛到app下
- 獲取對(duì)象
主要通過(guò) query 方式以及層級(jí)關(guān)系查詢對(duì)象缤苫,query支持 id,類墅拭,屬性活玲,正則查詢等。查詢結(jié)果返回的是一個(gè) Selector 對(duì)象谍婉,查詢結(jié)果可以相加舒憾、排除,也可以直接綁定事件穗熬,或一些批量操作
// 查詢id是100的對(duì)象
app.query("#100")[0];
// 查詢名稱(name)是 car01 的對(duì)象
app.query("car01");
// 查詢物體類是Thing的對(duì)象
app.query(".Thing");
//有物體類型屬性的珍剑,無(wú)論值是什么
app.query("[alarm]");
//查詢物體類型屬性是糧倉(cāng)的對(duì)象
app.query("[報(bào)警=normal]");
app.query('["userData/物體類型"="糧倉(cāng)"]');
// 查詢levelNum屬性大于2的對(duì)象,目前支持 <= , < , = , > , >=
app.query("[levelNum>2]");
// 正則表達(dá)式(RegExp)對(duì)象,目前只是對(duì)名稱(name)屬性值進(jìn)行正則匹配
app.query(/car/);
// 上例等同于
var reg=new RegExp('car');
app.query(reg);
- 控制對(duì)象
可控制的有:
1死陆、物體顯示與隱藏 visible招拙;
2、物體移動(dòng) position措译,localPosition别凤,translate;
3领虹、物體旋轉(zhuǎn) angles规哪,localAngles,rotateX塌衰,rotateY诉稍,rotate Y
4、縮放 scale
5最疆、位移杯巨、旋轉(zhuǎn)、縮放動(dòng)畫 moveTo努酸,rotateTo服爷,scaleTo
6、CSS屬性控制获诈,如透明度 opacity仍源、描邊outline、顏色 color舔涎、進(jìn)出場(chǎng)動(dòng)畫 fadeIn fadeOut
7笼踩、連接操作:通過(guò) add 接口可以添加子元素,添加子元素時(shí)亡嫌,子物體的世界位置不發(fā)生變化嚎于,并保持那一刻與父物體的相對(duì)位置關(guān)系進(jìn)行移動(dòng) - 鼠標(biāo)交互
1桶至、picker,結(jié)合 mouseenter 和 mouseleave 事件實(shí)現(xiàn)鼠標(biāo)懸浮選中效果
// 鼠標(biāo)拾取物體顯示邊框
app.on(THING.EventType.MouseEnter, '.Thing', function(ev) {
ev.object.style.outlineColor = '#FF0000';
});
// 鼠標(biāo)離開物體邊框取消
app.on(THING.EventType.MouseLeave, '.Thing', function(ev) {
ev.object.style.outlineColor = null;
});
// 每一幀判斷拾取的物體是否發(fā)生變化
app.on('update', function () {
if (app.picker.isChanged()) {
console.clear();
// 打印當(dāng)前被pick的物體
if (app.picker.objects[0]) {
console.log('當(dāng)前拾取的物體 ' + app.picker.objects[0].name);
}
// 打印之前被pick的物體
if (app.picker.previousObjects[0]) {
console.log('之前拾取的物體 ' + app.picker.previousObjects[0].name);
}
}
});
2匾旭、selection,鼠標(biāo)點(diǎn)擊選中效果圃郊,這個(gè)跟click事件不一樣价涝,selection 相當(dāng)于在內(nèi)部給你保存了選中的所有物體
- 攝像機(jī)
攝像機(jī)包含兩個(gè)重要的位置參數(shù):鏡頭位置 position 和被拍攝物體的位置 target (又叫目標(biāo)點(diǎn))
1、設(shè)置攝像機(jī)位置 position,target 和 object 二選一
// 直接設(shè)置
app.camera.position = [0, 20, 20]; // 鏡頭位置
app.camera.target = [-30, 10, 0]; // 目標(biāo)點(diǎn)位置
// fit 方法設(shè)置
app.camera.fit({
position: [100, 100, 100],
target: [0, 0, 0]
});
//設(shè)置攝像機(jī)到物體的“最佳看點(diǎn)”
app.camera.fit(obj);
//當(dāng)不傳參數(shù)時(shí)持舆,設(shè)置攝像機(jī)到當(dāng)前整個(gè)場(chǎng)景下的“最佳看點(diǎn)”
app.camera.fit();
// 自定義設(shè)置
app.camera.fit({
'object': obj,
'xAngle': 60, //繞物體自身X軸旋轉(zhuǎn)角度
'yAngle': 30, //繞物體自身Y軸旋轉(zhuǎn)角度
'radiusFactor':3, //物體包圍球半徑的倍數(shù)
});
2色瘩、lookAt 設(shè)置相機(jī)觀察的物體
//攝像機(jī)一直“盯著”[0,0,0]點(diǎn)看
app.camera.lookAt([0, 0, 0]); //
//攝像機(jī)一直“盯著”某物體看
var obj = app.query("car01")[0];
app.camera.lookAt(obj);
//取消攝影機(jī)一直盯著物體看
app.camera.lookAt(null);
3、flyTo 讓攝像機(jī)從當(dāng)前位置逸寓,飛行到將要設(shè)置的位置
//以Quartic.In的插值方式 讓飛行速度漸增
app.camera.flyTo({
position: [0, 20, 20],
target: [-30, 10, 0],
time: 3 * 1000,
lerpType: THING.LerpType.Quartic.In
});
//自定義飛到物體的攝像機(jī)位置參數(shù)(同fit)
app.camera.flyTo({
object: obj,
xAngle: 30, //繞物體自身X軸旋轉(zhuǎn)角度
yAngle: 60, //繞物體自身Y軸旋轉(zhuǎn)角度
radiusFactor: 3, //物體包圍盒半徑的倍數(shù)
time: 5 * 1000,
complete: function() {
console.log("飛行結(jié)束");
}
});
4居兆、routateAround 設(shè)置相機(jī)環(huán)繞某點(diǎn)飛行
//環(huán)繞[0,0,0]點(diǎn)旋轉(zhuǎn) 180 度,5s 轉(zhuǎn)完
app.camera.rotateAround({
target: [0,0,0],//環(huán)繞的坐標(biāo)點(diǎn)
time: 5*1000,//環(huán)繞飛行的時(shí)間
yRotateAngle : 180,//環(huán)繞y軸飛行的旋轉(zhuǎn)角度
complete:function(){
console.log('結(jié)束環(huán)繞飛行');
}
});
5竹伸、followObject 設(shè)置相機(jī)跟隨物體
app.camera.followObject(obj);
6泥栖、move(),zoom()勋篓,rotateY()吧享,rotateX()來(lái)控制攝像機(jī)的移動(dòng)、縮放譬嚣、旋轉(zhuǎn)
//攝像機(jī)水平移動(dòng) 10m
app.camera.move(10, 0);
//攝像機(jī)垂直移動(dòng) 10m
app.camera.move(0, 10);
//攝像機(jī)向前推進(jìn) 10m
app.camera.zoom(10);
//設(shè)置攝像機(jī)target為圓心轉(zhuǎn)在水平方向上旋轉(zhuǎn)的夾角增量
app.camera.rotateY(20);
// 設(shè)置攝像機(jī)target為圓心轉(zhuǎn)在豎直方向上旋轉(zhuǎn)的夾角增量
app.camera.rotateX(20);
- 界面元素
1钢颂、3D元素 Marker,Webview,會(huì)隨著縮放進(jìn)大遠(yuǎn)小
app.create({
type: "Marker",
offset: [0, 2, 0],
size: [4, 4],
url: "https://thingjs.com/static/images/warning1.png",
parent: app.query("car01")[0]
});
2拜银、2D元素UIAnchor殊鞭,需要自己寫 html
var uiAnchor = app.create({
type: "UIAnchor",
parent: app.query("car02")[0],
element: document.getElementById("XXXX"),
localPosition: [0, 2, 0],
pivot: [0.5, 1]
});
uiAnchor.destroy();
uiAnchor.visible = true / false;
3、快捷界面庫(kù)尼桶,一些 panel 控件操灿,也可以綁定到模型上
// 創(chuàng)建UIAnchor面板
var ui = app.create({
// 類型
type: 'UIAnchor',
// 父節(jié)點(diǎn)設(shè)置
parent: obj,
// 要綁定的頁(yè)面的 element 對(duì)象
element: panel.domElement,
// 設(shè)置 localPosition 為[0, 0, 0]
localPosition: [0, 0, 0],
// 指定頁(yè)面的哪個(gè)點(diǎn)放到 localPosition 位置上
pivot: [-0.15, 1.8]
});
- 數(shù)據(jù)對(duì)接
1、ajax泵督,在 ThingJS 在線開發(fā)環(huán)境中牲尺,內(nèi)置了 JQuery 庫(kù),可以直接使用 JQurey 封裝的 Ajax 方法進(jìn)行數(shù)據(jù)對(duì)接
$.ajax({
'url': "http://3dmmd.cn:83/getMonitorDataById", //Ajax請(qǐng)求服務(wù)的地址
'type': "GET", //請(qǐng)求方式 "POST" 或 "GET"幌蚊,默認(rèn)為 "GET"
'dataType': "json", //服務(wù)返回的數(shù)據(jù)類型谤碳,推薦使用標(biāo)準(zhǔn)JSON數(shù)據(jù)格式
//發(fā)送到服務(wù)器的數(shù)據(jù)
'data': { 'id': 89757 },
//請(qǐng)求成功后的回調(diào)函數(shù)
'success': function (data) {
console.log(data);
// 處理返回的數(shù)據(jù)
},
//請(qǐng)求失敗時(shí)調(diào)用的函數(shù) 有以下三個(gè)參數(shù):XMLHttpRequest 對(duì)象、錯(cuò)誤信息溢豆、(可選)捕獲的異常對(duì)象
'error': function (xhr, status, error) {
console.log(xhr);
},
});
2蜒简、websocket
// 創(chuàng)建一個(gè)WebSocket連接
var webSocket = new WebSocket('ws://3dmmd.cn:82');
// 建立 websocket 連接成功 觸發(fā)open事件
webSocket.onopen = function () {
console.log("websocket服務(wù)器連接成功...");
};
// 接收服務(wù)端數(shù)據(jù) 觸發(fā)message事件
webSocket.onmessage = function (ev) {
console.log("websocket接收到的數(shù)據(jù):" + ev.data);
};
// 關(guān)閉連接后 觸發(fā)close事件
webSocket.onclose = function (evt) {
console.log("websocket關(guān)閉...");
};
// 通信發(fā)生錯(cuò)誤時(shí) 觸發(fā)error事件
webSocket.onerror = function () {
console.log('發(fā)生錯(cuò)誤')
}
var dataObj = { 'id': 89785 };
// send 數(shù)據(jù)類型可以是 字符串 或 二進(jìn)制對(duì)象(Blob 對(duì)象、ArrayBuffer 對(duì)象)
webSocket.send(JSON.stringify(dataObj));
一些概念
資源:場(chǎng)景資源(場(chǎng)景+模型) + 頁(yè)面資源 + 全景圖資源
-
層級(jí)
1漩仙、層級(jí)可以讓我們方便管理和查詢到場(chǎng)景中物體 && 批量操作物體
2搓茬、可以通過(guò) app.level.change(obj) 切換到對(duì)應(yīng)層級(jí)犹赖,app.level.back() 返回
3、有兩套層級(jí)體系:父子樹和分類對(duì)象屬性樹
父子樹卷仑,通過(guò) children 連接層級(jí):root => campus => building峻村,ground,thing
父子樹
分類對(duì)象屬性樹:每個(gè)對(duì)象都內(nèi)置了一些屬性锡凝,如 root.campuses粘昨,campus.ground,campus.buildings窜锯,campus.things张肾,building.facade,building.floors锚扎,building.things吞瞪,floor.rooms,floor.things
分類對(duì)象屬性樹
4驾孔、當(dāng)進(jìn)入層級(jí)時(shí)會(huì)觸發(fā) EnterLevel 事件芍秆。
當(dāng)退出層級(jí)時(shí)會(huì)觸發(fā) LeaveLevel 事件。
當(dāng)默認(rèn)的層級(jí)切換飛行結(jié)束后翠勉,會(huì)觸發(fā) THING.EventType.LevelFlyEnd 事件 坐標(biāo)系
1浪听、世界坐標(biāo)系
2、父級(jí)坐標(biāo)系
3眉菱、自身坐標(biāo)系
基本套路
- 加載場(chǎng)景
- 創(chuàng)建面板
- load 事件中處理邏輯
// 加載場(chǎng)景
var app = new THING.App({
// 場(chǎng)景地址
"url": "models/silohouse",
// 天空盒
"skyBox": "Universal"
});
// load 處理
app.on('load', function (ev) {
// 獲取糧倉(cāng)
siloHouse = app.query("[物體類型=糧倉(cāng)]");
// 添加糧倉(cāng)自定義屬性monitorData迹栓,用來(lái)存儲(chǔ)監(jiān)控信息
siloHouse.forEach(function (obj) {
obj.monitorData = {};
});
// 創(chuàng)建開關(guān)控件
createSwitchControl();
});