对象创建

有了场景,我们就可以添加物体对象了。

创建物体

在ThingJS中,可以动态创建或删除 Thing、Marker、Box等常见物体,他们大多继承自 BaseObject 。本章先以创建 Thing 物体为例,讲解创建对象时所需要的参数,其他各类对象会在相应章节中进行具体讲解。

对象创建与删除

  • 创建物体;

    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!");
    }
    });
     
  • 删除物体

    truck.destroy(); 
    help
    注意事项:

    有时候,我们经常会说制作场景,上传场景,下载场景,加载场景,这里的场景其实就是园区,我们通常也会简称为"场景"。

    示例效果如下图所示:

创建物体参数

创建的物体参数可以分为以下三种:通用参数、特定物体类型(type)的专属参数、系统其他功能。

  • 通用参数:

    • type:该物体用什么物体类来创建
    • id:该物体的编号
    • name:物体的名字
    • position:设置世界位置
    • localPosition:设置在父物体下的相对位置,和 position 只能输入一个
    • angles:设置世界坐标系下三轴旋转角度,例如:angles:[90,45,90] ,代表在世界坐标系下物体沿X轴旋转90度,沿Y轴旋转45度,沿Z轴旋转90度
    • scale:设置相对自身坐标系下的缩放比例
    • parent:设置父物体是谁
    help
    注意事项

    为了更清晰明确的对用户动态创建的物体对象进行管理,建议创建物体对象时,显式指明该物体对象的 parent。如果没有显式填写parent时:

    • 如果没有开启系统层级,则该物体的父亲默认是 root (不会是园区 Campus )
    • 如果开启了层级系统,创建物体时没有填写 parent ,当前层级即作为该物体的父亲

    例如:进入楼层层级后再创建 Thing,如果没有指定 parent ,则 parent 默认为该楼层,示例代码如下:

      var app = new THING.App({
        url: 'models/storehouse'     // 场景地址
    });
    app.on('load', function (ev) {
        var campus = ev.campus;
        var floor = campus.buildings[0].floors[0];
        // 将层级切换到楼层级别
        app.level.change(floor);
        // 第一次进入该楼层后 创建物体
        floor.one(THING.EventType.EnterLevel, function () {
            // 进入楼层层级后再创建 Thing
            // 如果没有指定 parent ,则 parent 默认为该楼层
            var obj = app.create({
                type: 'Thing',
                name: 'truck',
                url: 'https://model.3dmomoda.com/models/66b7f5979ff043afa4e79f7299853a4b/0/gltf/', // 模型地址 
                complete: function (ev) { 
                    // 打印结果:创建的物体父亲为该楼层
                    console.log('thing created: ' + ev.object.parent.id);
                }
            });
        }) 
    }); 
  • 特定物体类型(type)的专属参数,这里只列了 “Thing” 物体专属参数,其他物体种类参数可在 本页下方 中查看

    • url :物体模型资源路径,这个是 “Thing” 物体需要的参数
  • 系统其他功能:

    • complete:初始化完成后的函数回调
BaseObject

创建物体参数

ThingJS 中的大多数对象基本上都是继承自 BaseObject ,BaseObject 提供了 ThingJS 对象的基本能力。

BaseObject 派生出很多子类,常见的物体种类详见如下:

help
注意事项

在 CamBuilder 中摆放的园区、建筑、楼层、房间、物体等,同步到 ThingJS 中,会自行判断物体类,分别对应类为:campus、building、floor、room、thing。也可将默认类转换为自定义类。

在ThingJS 中创建的园区、建筑、楼层、房间、物体等,可创建自定义类

判断对象物体类

每个物体类都有它自己的类识别属性。

比如 `Building` 物体,使用 `instanceof THING.Building` 方法进行判断。

if ( obj instanceof THING.Building ) {
    console.log("This is a building!");
} 

对象属性

对象属性类别:

  • 通用属性:

    • id:一般可作为物体的唯一编号
    • name:用户设置的物体名字,这个属性 ThingJS 系统不要求全局唯一,用户可自行定义

      help
      注意事项

      关于 id 和 name 的使用说明:

      • 一般来说 id 为了保证唯一性,通常是按一定规则生成的编码(如身份证号或UUID)。
      • name 通常是可识别的名字,例如创建一个对象:

        var car = app.create({
        'id': '8EA88A93-3238-446E-B80D-0C61BEFC9950',
        'name': 'myCar01',
        'type': 'Thing',
        'url':'https://model.3dmomoda.com/models/66b7f5979ff043afa4e79f7299853a4b/0/gltf/'
        }); 
    • position:世界坐标系下位置
    • localPosition:父物体坐标下的位置
    • angles:世界坐标系下三轴旋转角度
    • localAngles:世界父物体坐标系下三轴旋转角度
    • scale:自身坐标系下三轴缩放量
    • visible:是否显示
    • style:效果控制
    • children:获取所有子物体
    • brothers:获取所有兄弟(排除自己)
    • parent:获取父物体
    • parents:获取所有父物体(返回的 Selector 结果中,第0位为直属父物体 parent,最后一位为世界根物体)

        对于从 CamBuilder 中导入的物体而言:

      • id 对应为 CamBuilder 中的 “UserID” ;如果用户没有填写 “UserID” , CamBuilder 中会生成的物体的唯一标识
      • name 对应为 “名称” ,如果用户在 CamBuilder 中没有自行填写 “名称” ,则在ThingJS 中 name 与 id 一致
      • 如果创建时,id 和 name 都不填写,则系统生成唯一id
      • 如果创建时,只填写了 name ,没填写 id ,则 id 取 name 的值
      • 如果创建时,用户填写了 id ,则 id 取用户填写的值,此时用户需自行维护 id 的唯一性,也可用 THING.Utils.generateUUID() 生成全局唯一标识
      • 如果创建时,只填了 id ,没填 name ,则 name 取 id 的值
  • 类专属属性

    Thing 类物体有 url 属性,也可在 BaseObject 查看支持的 type 清单以及每个类支持什么属性。

  • CamBuilder 中用户添加的自定义属性

    在 CamBuilder 中我们可以手动添加自定义属性,如下图:

    从 CamBuilder 导入的用户自定义的属性可通过 `userData` 属性访问到

    例如上图中的属性,我们这里可以这样访问:

    obj.userData["物体类型"]; 
  • 用户在程序运行中自行添加的属性

    JS 是一个灵活的语言,允许我们动态为对象添加属性。比如,我们从后台接收到的监控数据,可以直接给对象添加自定义属性 `monitorData` 来进行存储:

    obj.monitorData = {
        温度:10,
        单位:“摄氏度”
    } 

访问自定义属性

正如我们看到的,ThingJS 对象有丰富的属性。其中有的属性可能具有嵌套结构,比如 userData ,以及用户自行添加的 monitorData ,访问它们有时比较麻烦,如下:

if(obj.monitorData && obj.monitorData["温度"] > 0)
..... 

所以我们提供了一些便于访问、设置对象属性和判断对象属性是否存在的方法,例如:

obj.getAttribute("monitorData/温度")
obj.setAttribute("monitorData/温度", 15)
obj.hasAttribute("monitorData/温度")
 

属性查看工具

正如我们看到的,ThingJS 对象有丰富的属性。其中有的属性可能具有嵌套结构,比如 userData ,以及用户自行添加的 monitorData ,访问它们有时比较麻烦,如下:

  • 点击“工具”
  • 点击“场景信息”
  • 选中场景树中的某个物体对象查看属性

模型使用

在开发中我们需要动态创建一个模型,如何获取模型呢?

有两种途径可获取模型:

从模型库中获取

  • 选中“组件”下拉列表,点击选择“模型库”;

  • 点击“立即探索”,进入模型库列表;
  • 从模型库列表点击所需物体;
  • 在弹出层点击复制按钮,复制模型 url ;
  • 在创建物体时用模型 url 创建。

上传个人模型

obj 模型上传 CamBuilder

  • 先准备好需要上传的个人模型,需要满足以下要求:

    • 导入文件格式:zip 文件(建议 zip 包以英文命名);
    • 模型要求:
      • 模型的每个节点的顶点数量不能超过65000;
      • 模型文件、贴图文件、材质文件、缩略图文件必须以英文名命名;
      • 需包含:
        • obj 模型文件,支持 obj 格式
        • 贴图文件,支持 png、jpg、bmp、dds、tga(非压缩格式)格式
        • mtl 材质文件,支持 mtl 格式
        • 缩略图文件,支持 png 格式,命名与 obj 文件一致
        help
        注意事项

        将模型、贴图、材质、缩略图,同级目录压缩为 zip 导入,且 obj 模型文件,mtl 材质文件,缩略图文件三个资源文件同名时,上传到客户端 和 ThingJS 里才可以显示缩略图。

        help
        注意事项

        上传obj模型时需要满足如下条件:

        将模型、贴图、材质、缩略图,同级目录压缩为 zip 导入,且 obj 模型文件,mtl 材质文件,缩略图文件三个资源文件同名时,上传到客户端 和 ThingJS 里才可以显示缩略图

  • 准备好上传文件,上传使用步骤如下:
    1. 选择 CamBuilder 内的 DIY 模型库,选择上传资源下的 OBJ模型上传;
    2. 选择将要上传的OBJ模型压缩包,点击确定,进行上传;
    3. 上传成功后可在已上传的OBJ模型处查看;
    4. 可进入搭建场景使用,上传后即可显示在「个人」,「用户上传」处可见,拖拽至场景中即可使用;
    5. 进入搭建场景,先点击右侧菜单栏中的「个人」,再点击点击上方「添加」按钮,选择需上传的模型,确认后上传;
    6. 上传后即可显示在「个人」,「用户上传」处可见,拖拽至场景中即可使用。
  • 使用后导出tjs包,则会导出obj模型,在导入ThingJS之后,点击 在线开发 里面,点击「工具」下的「自定义模型信息」即可看到用户上传的自定义模型,此时可点击该模型在左侧代码编辑区域快速创建代码。

3ds Max 模型上传

  • 通过3ds Max模型上传插件您可将自己制作的3ds Max模型上传至模模搭中使用;
  • 上传后在 ThingJS 网站 在线开发 里面,点击「工具」下的「自定义模型信息」即可看到用户上传的模型,此时可点击该模型在左侧代码编辑区域快速创建代码。

自定义类

定义与注册

用户可以定义自己的类,通过继承 ThingJS 内部类(比如:Thing 类),对 ThingJS 进行扩展和封装。

我们推荐使用ES6语法定义一个类。例如,自定义汽车类 Car

// 继承 Thing 类
class Car extends THING.Thing {
    constructor(app) {
        super(app);
    }
    // 添加一个 run 方法
    run() {

    }
} 

要在ThingJS中使用自定义的类,还需要对其进行注册。

通过 THING.factory.registerClass 方法,将继承于 ThingJS 内部类的自定义类,注册到系统中。例如:

 // 注册自定义类 
THING.factory.registerClass('Car', Car); 

使用自定义类

用户定义并注册完自己的类后,常见的使用方式有以下两种:

  1. 创建自定义类的物体

    利用 app.create 方法进行创建时,指定type为自定义类

     var car = app.create({
        type: 'Car', // 自定义注册类的名称
        name: 'GMC指挥车',
        url: 'https://model.3dmomoda.com/models/17fc17b416e94527bc607917fc8269a4/0/gltf/',// 模型地址 
        position: [10, 0, 10],
        complete: function () {
            console.log('created: ' + this.name);
        }
    }); 

    此外,同样可对注册后的自定义类进行 query 查询,注册事件等操作

    // 查询得到所有Car类的物体
    var cars=app.query('.Car')
    
    // 给所有Car类的物体 添加Click事件
    app.on('click','.Car',function(ev){
        var obj=ev.object;
        console.log(obj.name);
    }) 

    观察此示例的场景树也可以看出,新创建的物体为自定义的Car类型

  2. 转换已有物体的类型

    通过 THING.Utils.convertObjectClass 方法将场景中物体,转为自定义的类型,例如:

    // 查询得到 name 中包含 car 字符串的物体集合
    var cars=app.query(/car/);
    // 遍历物体集合,逐个转换成自定义的 Car 类
    cars.forEach(function (obj) {
        THING.Utils.convertObjectClass(obj, 'Car')
    }) 

    观察此示例中的场景树可看出

    原本场景中 name 包含“car”的Thing类型物体(即场景中的车),转换成了Car类型。

如何建模

但一个 3D 模型如何制作呢?这一章将为大家介绍一下部分建模软件以及建模软件中用到的技术。

建模软件

当建模可使用建模软件,常用的建模软件有以下两类:

  • 通用商业3D软件
  • cad 软件
  • 上面这两类 3D 软件,都可输出 3D 模型,并导入到 ThingJS 平台使用

建模软件中涉及的技术

  • mesh 建模

    大多数通用商业 3D 软件使用的建模技术,有点像雕塑,使用多边形体,进行编辑,再贴上贴图,模拟表面的材质。

  • Nurbs

    Nurbs,即非均匀有理 B 样条曲线(Non-Uniform Rational B-Splines) ,你只要知道,它是工业建模标准,大部分 3D CAD 软件支持建模方法。它主要是通过数学公式定义每条线,每个曲面,所以可以做到无限细分面,应用于数字机床加工等,我们平时看到汽车,飞机等均由这类技术设计被用于制造。

    但目前 ThingJS 平台还不能直接支持这种数据,需要转换的普通 3Dmesh 格式,并导入到 ThingJS 平台使用,导入后该模型的面数较多。

  • Loft

    这个技术,就是给我一个界面 2D 图形,在给我一条路径,我就能制作一个模型给你。

    ThingJS 平台支持这项技术,比如 PolygonLine这类物体。

  • 3D扫描

    通过激光等技术对物体表面进行 3D 扫描,并进行 3D 重建得到模型。ThingJS 在积极开发这项技术,敬请期待。

  • 多照片自动建模

    CamBuilder 将在后续发布多照片自动建模功能,敬请期待。

    这是采集的雕塑照片

    这是通过照片建模技术生成的模型:

在线咨询
QQ交流群
微信公众号