分享
查看: 1858|回复: 0

[分享] ThingJS教你开发物体爆炸图,3D创业团队松一口气啦!

[复制链接]

ThingJS教你开发物体爆炸图,3D创业团队松一口气啦!

发表于 2020-9-15 20:20:30 来自 分享 阅读模式 倒序浏览
zzv_icon1858 zzr_icon0 查看全部

ThingJS教你开发物体爆炸图,3D创业团队松一口气啦!

塌陷不能把模型变小,但是可以减少对内存的占用。ThingJS是做3D轻量化开发的平台,在模型导入后进行更多事件控制。


今天来讲讲如何基于js语法来开发一个物体模型拆解展开的效果,专业名称叫“物体爆炸图”,标准ThingJS体系模型出于互动模型性能考虑,都要求在模型上传前做塌陷,这种建模细节对于提升3D开发效率很有必要,目的是减少模型对内存的占用。


在3D开发之前,模型本身会重叠很多命令,占用很大一部分内存和CPU,拖慢电脑,所以针对模型进行塌陷后(指的是把很多个物体合并成一个,转换为一个命令可编辑多边形或可编辑网格),就会去除这些多余的命令参数,不再花时间记录和存储,从而加快运行速度。


制作物体模型时,根据爆炸图中各个零件的拆分需要,针对子模型或子节点定义并命名物体子对象,在3DMAX等建模软件里就能创建子对象。这些子对象在ThingJS在线开发中可作为模型子节点来控制,能够像单独模型对象物体一样进行移动、添加事件等操作。

拆分后磨性子节点如果有多材质或点数超过上限,那在ThingJS开发中会继续拆分,并在子节点中被命名成组,组内继续拆分“01”、“02”等对象。例如:3dmax命名, 一个子节点名字为“box”,由于该子节点使用了多种材质,该子节点在在线开发中会被命名成组,组内会被拆分并命名为“box_0”,“box_1”等对象。


注意经塌陷的模型不再有子节点保留,只有上述分项控制模型局部要求,保留已命名的子对象信息,最大程度上提高开发性能,又满足模型拆分的特殊需要。


官方示例请各位看官参考:

  1. // 加载场景代码
  2. var app = new THING.App({
  3. url: '/api/scene/406e419fae9000a47a4a8899'
  4. });
  5. // 发电机模型节点数据
  6. var nodeObjData = {
  7. '1': {name: '机座', offset: [0, 0, -1]},
  8. '2': {name: '保护装置', offset: [0, -1, 0]},
  9. '3': {name: '电瓶', offset: [0, -1, 0]},
  10. '4': {name: '排气口', offset: [0, 0, 1]},
  11. '5_0': {name: '过滤器', offset: [0, 0, 1]},
  12. '5_1': {name: '过滤网', offset: [0.5, 0, 1]},
  13. '6': {name: '供给装置', offset: [0, 0, 1]},
  14. '7': {name: '烟囱', offset: [-1, 0, 0]},
  15. '8': {name: '发电机'},
  16. '9': {name: '控制器', offset: [0, 1, 0]}
  17. }
  18. // 发电机模型节点对象
  19. var nodeJsonData = null;
  20. // 发电机对象
  21. var generatorObj = null;
  22. // 发电机展开状态
  23. var expandState = false;
  24. // 发电机展开次数
  25. var expandCount = 0;
  26. // 场景加载完成后执行
  27. app.on('load', function (ev) {
  28. // 查询发电机对象
  29. generatorObj = app.query('#generator')[0]
  30. // 获取发电机模型节点对象
  31. nodeJsonData = getNode(generatorObj);
  32. // 创建测试按钮
  33. new THING.widget.Button('展开', expandObj);
  34. new THING.widget.Button('还原', unexpandObj);
  35. new THING.widget.Button('顶牌显示', createAllPanel);
  36. new THING.widget.Button('顶牌隐藏', hiddenAllPanel);
  37. })
  38. /**
  39. * 说明:显示所有顶牌
  40. */
  41. function createAllPanel(){
  42. for (let key in nodeObjData) {
  43. nodeJsonData[key].name = nodeObjData[key].name;
  44. createPanel(nodeJsonData[key]);
  45. }
  46. }
  47. /**
  48. * 说明:隐藏所有顶牌
  49. */
  50. function hiddenAllPanel(){
  51. for (let key in nodeObjData) {
  52. hiddenPanel(nodeJsonData[key]);
  53. }
  54. }
  55. /**
  56. * 说明:展开物体
  57. */
  58. function expandObj() {
  59. // 防止发电机在执行一次展开过程中多次点击
  60. if (expandState) {
  61. return;
  62. }
  63. expandState = true;
  64. expandCount++;
  65. for (let key in nodeObjData) {
  66. // 各子节点进行偏移
  67. objOffset(nodeJsonData[key], nodeObjData[key].offset);
  68. }
  69. }
  70. /**
  71. * 说明:还原物体
  72. */
  73. function unexpandObj() {
  74. // 展开次数为0,代表未展开
  75. if (expandCount == 0) {
  76. return;
  77. }
  78. for (let key in nodeObjData) {
  79. if(nodeObjData[key].offset){
  80. // 计算还原时子节点需要进行的偏移量,数值为 -1 * 展开次数 * nodeObjData中定义的该子节点对应的偏移量
  81. let offsetValue = [-1 * expandCount * nodeObjData[key].offset[0], -1 * expandCount * nodeObjData[key].offset[1], -1 * expandCount * nodeObjData[key].offset[2]]
  82. objOffset(nodeJsonData[key], offsetValue);
  83. }
  84. }
  85. expandCount = 0;
  86. }
  87. /**
  88. * 说明:获取节点对象
  89. */
  90. function getNode(obj) {
  91. let nodeJson = {};
  92. // obj.subNodes 即可获取到一个物体的所有子节点
  93. for (let i = 0; i < obj.subNodes.length; i++) {
  94. let subnode = obj.subNodes[i];
  95. // 获取物体子节点对象中node属性的type值,只有当type值为Mesh时,才能对物体添加事件
  96. let type = subnode.node.type;
  97. if(type == 'Mesh'){
  98. nodeJson[subnode.name] = subnode;
  99. }
  100. }
  101. return nodeJson;
  102. }
  103. /**
  104. * 说明:物体偏移
  105. */
  106. function objOffset(obj, value) {
  107. if (!value) {
  108. return;
  109. }
  110. // 物体移动
  111. obj.moveTo({
  112. offsetPosition: value, // 自身坐标系下的相对位置
  113. time: 500, // 移动完成需要的时间
  114. complete: function () {
  115. expandState = false;
  116. }
  117. });
  118. }
  119. /**
  120. * 说明:创建面板
  121. */
  122. function createPanel(obj) {
  123. // 判断是否已经创建过面板,如果已创建,显示,否则创建面板
  124. var panel = obj.getAttribute('panel');
  125. if (panel != null) {
  126. panel.visible = true;
  127. return;
  128. }
  129. // 创建panel
  130. panel = new THING.widget.Panel({
  131. // 设置面板宽度
  132. width: '100px',
  133. // 没有角标 none ,没有线的角标 noline ,折线角标 polyline
  134. cornerType: 'polyline'
  135. })
  136. // 绑定物体身上相应的属性数据
  137. panel.addString(obj, 'name').caption('');
  138. // 创建UIAnchor面板
  139. var uiAnchor = app.create({
  140. // 类型
  141. type: 'UIAnchor',
  142. // 设置父物体
  143. parent: obj,
  144. // 要绑定的dom元素对象
  145. element: panel.domElement,
  146. // 设置 localPosition 为 [0, 0, 0]
  147. localPosition: [0, 0, 0],
  148. // 相对于面板左上角的偏移像素值,当前用值是角标的中心点
  149. pivotPixel: [-16, 109]
  150. });
  151. // 更改面板文本样式
  152. $('.ThingJS_wrap .main .ThingJS_UI .ThingJS_string-value').css('text-align', 'center');
  153. obj.setAttribute('panel', uiAnchor);
  154. }
  155. /**
  156. * 说明:隐藏面板
  157. */
  158. function hiddenPanel(obj) {
  159. var panel = obj.getAttribute('panel');
  160. if (panel != null) {
  161. panel.visible = false;
  162. }
  163. }
复制代码


ThingJS让3D开发更加简单,让3D创业团队松一口气啦!


avatar
游客~
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

130700ppkpl8x3t7tt1b1t