资源
优诺科技-ThingJS官网
优诺科技-CampusBuilder下载
CampusBuilder使用手册
CampusBuilder使用教程(视频,快捷键,常见问题)
CampusBuilder文档中心
优诺科技-Thingjs在线开发工具
ThingJS入门教程
ThingJS API-在线开发参考手册
ThingJS离线开发包使用说明书
ThingJS离线部署包使用说明书
ThingJS开发3D可视化系统步骤
CampusBuilder(以下简称CB)-3D场景搭建工具
概述
使用CB搭建场景可以依托ThingJS提供的3D模型库,或者上传自定义模型。CB搭建的3D场景会自动同步到ThingJS平台同名账户下(可在在线开发工具-资源-我的园区中看到)
电脑配置要求
系统:Windows 7及以上
CPU:双核 CPU2.8GHz及以上
内存:1G及以上
显卡:最低GTX650,推荐GTX960及以上
硬盘:300GB及以上
3D模型创建对显卡有一定的要求,请务必使用独立显卡,集成显卡会造成使用的过程中有卡顿现象。
CampusBuilder 与 ThingJS的联系
在CB中创建的物体,只有在编辑了UserID、Name或者自定义属性之后,导入到ThingJS中才能成为独立管理的对象,被程序读取或修改。并且CB中UserID和Name与ThingJS中的对象有对应关系。
数据对接
ajax
在ThingJS的在线开发环境中内置了JQuery库,可以直接使用JQuery封装的Ajax方法进行数据对接。
注:如果在ThingJS在线环境中请求用户自己服务器上的静态资源数据或数据服务,或者其他网站的数据服务,就需要解决跨域问题(服务端需要配置response响应头的Access-Control-Allow-Origin属性)。如果是访问用户上传到ThingJS网站的静态JSON数据资源则不存在跨域问题。
集成到React项目中(iframe引入)
使用ThingJS进行离线开发,需要按照 ThingJS离线开发包使用说明书 安装离线开发包,并在插入秘钥U盘的情况下,在CB客户端进行ThingJS第三方调试。
实现一个三维停车场场景
效果展示
第一步:使用CampusBuilder导入参考图(最好是CAD平面图),设置比例和中心点。
利用ThingJS提供的模型,搭建停车场场景,包括但不限于墙,地面,停车位,减速带,警示牌,闸机,根据实际情况调整各个模型的属性。场景搭建的差不多了之后,要给需要程序读取或控制的模型加上UserID,比如在停车场这个场景里需要程序读取或控制的是一个个停车位,所以需要给每个停车位的UserID属性都输入值。
第二步:在ThingJS在线开发工具中创建自己的项目。
创建App对象并加载场景
var app = new THING.App({
// 场景地址
"url": "/api/scene/f2837fb2825733ec2f34aaa9",
//背景设置
"skyBox" : "BlueSky"
});
动态创建车辆(在指定的停车位渲染指定的车) ```javascript // 停车位假数据示例 var spaceData = [ {
id: 'parkingSpace01', // 这个id需要跟CampusBuilder中的UserID一致
carModelUrl: '/api/models/A2425FF719264EA8A74440115640184A/0/gltf/' // 模型地址
}, {
id: 'parkingSpace11',
carModelUrl: '/api/models/54728749A90F43CC874CE869B5028F65/0/gltf/'
}, {
id: 'parkingSpace16',
carModelUrl: '/api/models/91FACB0F809240539A0143BC468A82ED/0/gltf/'
} ];
function renderCars (spaceData) {
var parkingSpace = null;
var car = null;
spaceData.forEach((item)=>{
if (item.carModelUrl.length > 0) {
// 获取停车位对象
parkingSpace = app.query(#${item.id}
);
// 创建车辆对象
car = app.create({
type: ‘Thing’, // 对象类型
url: item.carModelUrl, // 模型地址
position: parkingSpace[0].position, // 位置
angles: parkingSpace[0].angles, // 缩放
scale: parkingSpace[0].scale, // 旋转角度
complete: function () {
console.log(‘thing created: ‘ + this.id);
}
});
}
});
};
// 场景加载事件 app.on(‘load’, function(){ // 加载场景之后执行 renderCars(spaceData); });
3. 渲染小车沿路径移动动画
实现效果:小车沿着固定路径循环移动。路径坐标点数组和模型position数组可以使用 ThingJS在线开发-工具-拾取坐标工具,在场景中使用鼠标点击获取坐标数据。
```javascript
function renderMovingCar () {
var moveCar = app.create({
type: 'Thing',
url: '/api/models/D12DF3998C9149D5A9B44652AB78BD99/0/gltf/',
position: [6.63, 0, 2.051],
scale:[0.184,0.461,0.22], // 这里的缩放数据是在CB里面查看的停车位的缩放数据,可根据实际情况调整
complete: function () {
// console.log('thing created: ' + this.id);
var path = [[ 6.93, 0, 2.08], [ -4.743, 0.1, 1.971],[ -4.407, 0.01, -7.752]];
moveCar.movePath({
orientToPath: true, // 物体移动时沿向路径方向
path: path, // 路径坐标点数组
time: 15 * 1000, // 路径总时间 毫秒
delayTime: 500, // 延时 0.5s 执行
lerpType: null, // 插值类型(默认为线性插值)此处设置为不插值
loopType: 'repeat', // 循环类型 'no':不循环 'repeat': 循环 'pingpong': '来回不断循环'
});
}
});
};
- 渲染闸机杆抬起放下动画
实现效果:小车进入停车场前,入口闸机杆抬起,进入后入口闸机杆落下;小车离开前,出口闸机杆抬起,离开后出口闸机杆落下。特别说明:由于ThingJS提供的闸机杆模型的轴心点在中间,旋转的时候是绕着轴心点去旋转,如果旋转角度过大(比如90度),闸机杆与闸机就脱离了,所以在这我设置的旋转角度为20度。如果想要修改模型的轴心点,需要在3DMax里面去修改模型。
function renderMovingCar () {
var turnstile01 = app.query('#turnstile01'); // 在CB中给闸机杆编写UserID,使用query获取到闸机杆对象
var turnstile02 = app.query('#turnstile02');
var moveCar = app.create({
type: 'Thing',
url: '/api/models/D12DF3998C9149D5A9B44652AB78BD99/0/gltf/',
position: [6.63, 0, 2.051],
scale:[0.184,0.461,0.22],
complete: function () {
// console.log('thing created: ' + this.id);
var path = [[ 6.93, 0, 2.08], [ -4.743, 0.1, 1.971],[ -4.407, 0.01, -7.752]];
moveCar.movePath({
orientToPath: true, // 物体移动时沿向路径方向
path: path, // 路径坐标点数组
time: 15 * 1000, // 路径总时间 毫秒
delayTime: 500, // 延时 0.5s 执行
lerpType: null, // 插值类型(默认为线性插值)此处设置为不插值
loopType: 'repeat', // 循环类型
update: function(e) {
// 监听小车的移动过程(移动数据为0-1的浮点数)
var numStr = e.progress.toString();
var index = numStr.indexOf('.');
// 在这里处理移动数据时,需要注意力度,如果截取的小数点后的位数过大的话,有可能监听不到,亲测截取小数点后两位是刚刚好的。如果截取小数点后三位,在场景初始加载时有很大概率监听不到。
var result = numStr.slice(0, index + 3);
if (Number(result) === 0) {
// console.log(e.progress + `----` + result);
turnstile01[0].rotateTo({
// 这个角度需要在CB中多尝试,如果对坐标系的概念比较模糊的话
angles: [0, 90, 20],
time: 2000,
complete: function () {
turnstile01[0].rotateTo({
angles: [0, 90, 0],
time: 1000,
complete: function () {
// console.log('rotateto completed');
}
});
}
});
}
if (Number(result) === 0.7) {
// console.log(e.progress + `----` + result);
turnstile02[0].rotateTo({
angles: [0, 0, 20],
time: 5000,
complete: function () {
turnstile02[0].rotateTo({
angles: [0, 0, 0],
time: 1000,
complete: function () {
// console.log('rotateto completed');
}
});
}
});
}
}
});
}
});
};
// 加载场景之后执行
app.on('load', function(){
renderCars(spaceData);
renderMovingCar();
});
第三步:对接数据
使用感受
- CB工具使用起来还不是特别的顺手,尤其是建立墙体的时候,有些拐弯的地方,不好控制,把握不好的话,两面墙之间会有窟窿
- 如果程序需要读取的物体比较多,比如说停车场的停车位比较多的话,在CB里面去编写UserID是很费时间的,因为要一个一个地去编写UserID
- 目前搭建场景时使用的模型都是ThingJS官方提供的,如果遇到需要修改模型的问题,比如说停车场场景里的闸机杆的轴心点需要改,我们是没有办法改的,所以如果没有建模相关的专业人才的话,效果的实现还是有一些受限的
- 如果想要把ThingJS搭建的场景集成到现有的数字孪生系统中,不管是在线还是离线,都需要使用Iframe引入的方式进行集成。如果没有正式部署,使用iframe引入场景背景中是有”Thingjs by uinnova”水印的。