ThingJS 使用

ThingJS,注意不是 Three.js,是比Three.js 封装度更高得3D框架,但不是开源的,使用得付费。也不是特别成熟,仅调研一波。

1、场景导入

  • 控制台 新建项目保存
  • 下载 CampusBuilder ,创建一个场景并导出为 Thingjs 场景包B,如 hmf.tjs 格式
  • 控制台 "我的资源-我的场景-上传场景"上传导出的场景包B
  • 打开在线开发平台,通过 "资源-场景资源" 引入场景包B

2、模型制作

提供三种方式制作模型

  • 打开在线开发平台,通过 "资源-模型资源" 搜索需要的模型
  • 在资源中心,可找到很多付费和免费的模型,然后通过url创建
  • 个人 obj 模型,将 obj 资源按照以下格式打成zip包



    然后在 CampusBuilder 里的DIY模型库 tab 里点击上传资源

3、常用操作

  • 创建对象
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!");
  }
});
参数含义

创建对象后,设置其世界坐标即可展示在场景中。注意要设置其父元素,否则会直接挂到app下

  • 获取对象
    主要通过 query 方式以及层级关系查询对象,query支持 id,类,属性,正则查询等。查询结果返回的是一个 Selector 对象,查询结果可以相加、排除,也可以直接绑定事件,或一些批量操作
// 查询id是100的对象
app.query("#100")[0];

// 查询名称(name)是 car01 的对象
app.query("car01");

// 查询物体类是Thing的对象
app.query(".Thing");

//有物体类型属性的,无论值是什么
app.query("[alarm]");

//查询物体类型属性是粮仓的对象
app.query("[报警=normal]");
app.query('["userData/物体类型"="粮仓"]');

// 查询levelNum属性大于2的对象,目前支持 <= , < , = , > , >=
app.query("[levelNum>2]");

// 正则表达式(RegExp)对象,目前只是对名称(name)属性值进行正则匹配
app.query(/car/);
// 上例等同于
var reg=new RegExp('car');
app.query(reg);
  • 控制对象
    可控制的有:
    1、物体显示与隐藏 visible;
    2、物体移动 position,localPosition,translate;
    3、物体旋转 angles,localAngles,rotateX,rotateY,rotate Y
    4、缩放 scale
    5、位移、旋转、缩放动画 moveTo,rotateTo,scaleTo
    6、CSS属性控制,如透明度 opacity、描边outline、颜色 color、进出场动画 fadeIn fadeOut
    7、连接操作:通过 add 接口可以添加子元素,添加子元素时,子物体的世界位置不发生变化,并保持那一刻与父物体的相对位置关系进行移动
  • 鼠标交互
    1、picker,结合 mouseenter 和 mouseleave 事件实现鼠标悬浮选中效果
// 鼠标拾取物体显示边框
    app.on(THING.EventType.MouseEnter, '.Thing', function(ev) {
        ev.object.style.outlineColor = '#FF0000';
    });
    // 鼠标离开物体边框取消
    app.on(THING.EventType.MouseLeave, '.Thing', function(ev) {
        ev.object.style.outlineColor = null;
    });

    // 每一帧判断拾取的物体是否发生变化
    app.on('update', function () {
        if (app.picker.isChanged()) {
            console.clear();
            // 打印当前被pick的物体
            if (app.picker.objects[0]) {
                console.log('当前拾取的物体 ' + app.picker.objects[0].name);
            }
            // 打印之前被pick的物体
            if (app.picker.previousObjects[0]) {
                console.log('之前拾取的物体 ' + app.picker.previousObjects[0].name);
            }
        }
    });

2、selection,鼠标点击选中效果,这个跟click事件不一样,selection 相当于在内部给你保存了选中的所有物体

  • 摄像机
    摄像机包含两个重要的位置参数:镜头位置 position 和被拍摄物体的位置 target (又叫目标点)
    1、设置摄像机位置 position,target 和 object 二选一
// 直接设置
app.camera.position = [0, 20, 20]; // 镜头位置
app.camera.target = [-30, 10, 0]; // 目标点位置
// fit 方法设置
app.camera.fit({
  position: [100, 100, 100],
  target: [0, 0, 0]
});
//设置摄像机到物体的“最佳看点”
app.camera.fit(obj);

//当不传参数时,设置摄像机到当前整个场景下的“最佳看点”
app.camera.fit();
// 自定义设置
app.camera.fit({
  'object': obj,
  'xAngle': 60,  //绕物体自身X轴旋转角度
  'yAngle': 30,  //绕物体自身Y轴旋转角度
  'radiusFactor':3,  //物体包围球半径的倍数
});

2、lookAt 设置相机观察的物体

//摄像机一直“盯着”[0,0,0]点看
app.camera.lookAt([0, 0, 0]); //
//摄像机一直“盯着”某物体看
var obj = app.query("car01")[0];
app.camera.lookAt(obj);
//取消摄影机一直盯着物体看
app.camera.lookAt(null);

3、flyTo 让摄像机从当前位置,飞行到将要设置的位置

//以Quartic.In的插值方式 让飞行速度渐增
app.camera.flyTo({
  position: [0, 20, 20],
  target: [-30, 10, 0],
  time: 3 * 1000,
  lerpType: THING.LerpType.Quartic.In
});

//自定义飞到物体的摄像机位置参数(同fit)
app.camera.flyTo({
  object: obj,
  xAngle: 30, //绕物体自身X轴旋转角度
  yAngle: 60, //绕物体自身Y轴旋转角度
  radiusFactor: 3, //物体包围盒半径的倍数
  time: 5 * 1000,
  complete: function() {
    console.log("飞行结束");
  }
});

4、routateAround 设置相机环绕某点飞行

  //环绕[0,0,0]点旋转 180 度,5s 转完
  app.camera.rotateAround({
    target: [0,0,0],//环绕的坐标点
    time: 5*1000,//环绕飞行的时间
    yRotateAngle : 180,//环绕y轴飞行的旋转角度
    complete:function(){
        console.log('结束环绕飞行');
    }
  });

5、followObject 设置相机跟随物体

 app.camera.followObject(obj);

6、move(),zoom(),rotateY(),rotateX()来控制摄像机的移动、缩放、旋转

//摄像机水平移动 10m
app.camera.move(10, 0);
//摄像机垂直移动 10m
app.camera.move(0, 10);
//摄像机向前推进 10m
app.camera.zoom(10);
//设置摄像机target为圆心转在水平方向上旋转的夹角增量
app.camera.rotateY(20);
// 设置摄像机target为圆心转在竖直方向上旋转的夹角增量
app.camera.rotateX(20);
  • 界面元素
    1、3D元素 Marker,Webview,会随着缩放进大远小
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、快捷界面库,一些 panel 控件,也可以绑定到模型上

// 创建UIAnchor面板
    var ui = app.create({
        // 类型
        type: 'UIAnchor',
        // 父节点设置
        parent: obj,
        // 要绑定的页面的 element 对象
        element: panel.domElement,
        // 设置 localPosition 为[0, 0, 0]
        localPosition: [0, 0, 0],
        // 指定页面的哪个点放到 localPosition 位置上
        pivot: [-0.15, 1.8]
    });
  • 数据对接
    1、ajax,在 ThingJS 在线开发环境中,内置了 JQuery 库,可以直接使用 JQurey 封装的 Ajax 方法进行数据对接
$.ajax({
    'url': "http://3dmmd.cn:83/getMonitorDataById", //Ajax请求服务的地址
    'type': "GET", //请求方式 "POST" 或 "GET",默认为 "GET"
    'dataType': "json",    //服务返回的数据类型,推荐使用标准JSON数据格式
    //发送到服务器的数据
    'data': { 'id': 89757 },
    //请求成功后的回调函数
    'success': function (data) {
        console.log(data);
        // 处理返回的数据
    },
    //请求失败时调用的函数 有以下三个参数:XMLHttpRequest 对象、错误信息、(可选)捕获的异常对象
    'error': function (xhr, status, error) {
        console.log(xhr);
    },
});

2、websocket

// 创建一个WebSocket连接
var webSocket = new WebSocket('ws://3dmmd.cn:82');
// 建立 websocket 连接成功 触发open事件
webSocket.onopen = function () {
    console.log("websocket服务器连接成功...");
};

// 接收服务端数据 触发message事件
webSocket.onmessage = function (ev) {
    console.log("websocket接收到的数据:" + ev.data);
};
// 关闭连接后 触发close事件
webSocket.onclose = function (evt) {
    console.log("websocket关闭...");
};
// 通信发生错误时 触发error事件
webSocket.onerror = function () {
    console.log('发生错误')
}
var dataObj = { 'id': 89785 };
// send 数据类型可以是 字符串 或 二进制对象(Blob 对象、ArrayBuffer 对象)
webSocket.send(JSON.stringify(dataObj));

一些概念

  • 资源:场景资源(场景+模型) + 页面资源 + 全景图资源

  • 层级
    1、层级可以让我们方便管理和查询到场景中物体 && 批量操作物体
    2、可以通过 app.level.change(obj) 切换到对应层级,app.level.back() 返回
    3、有两套层级体系:父子树和分类对象属性树
    父子树,通过 children 连接层级:root => campus => building,ground,thing

    父子树

    分类对象属性树:每个对象都内置了一些属性,如 root.campuses,campus.ground,campus.buildings,campus.things,building.facade,building.floors,building.things,floor.rooms,floor.things
    分类对象属性树

    4、当进入层级时会触发 EnterLevel 事件。
    当退出层级时会触发 LeaveLevel 事件。
    当默认的层级切换飞行结束后,会触发 THING.EventType.LevelFlyEnd 事件

  • 坐标系
    1、世界坐标系
    2、父级坐标系
    3、自身坐标系

基本套路

  • 加载场景
  • 创建面板
  • load 事件中处理逻辑
// 加载场景
var app = new THING.App({
    // 场景地址
    "url": "models/silohouse",
    // 天空盒
    "skyBox": "Universal"
});
// load 处理
app.on('load', function (ev) {
    // 获取粮仓
    siloHouse = app.query("[物体类型=粮仓]");
    // 添加粮仓自定义属性monitorData,用来存储监控信息
    siloHouse.forEach(function (obj) {
        obj.monitorData = {};
    });

    // 创建开关控件
    createSwitchControl();
});

你可能感兴趣的:(ThingJS 使用)