ADN Open CIS
Сообщество программистов Autodesk в СНГ

31/08/2018

Добавление 3D-геометрии в сцену в приложении Forge

В последнем сообщении я представил серию, в которой я рассказываю о пути, который я прошел, чтобы добавить данные скелета в Dasher 360 (что, конечно же, основано на просмотрщике Forge).

Первым шагом, который я предпринял на этом пути, был поиск способа добавления простой 3D-геометрии в существующую сцену внутри Viewer. Это то, что мы делаем ограниченным образом внутри Dasher - мы используем облака точек для представления местоположений датчиков, например, - но я хотел разработать правильный подход для этого для данных, которые могли бы показывать тела людей, когда они ходят. Конечная цель будет заключаться в том, чтобы скелетное позиционирование было основано на базе данных, которая была заполнена нейронной сетью, использующей данные компьютерного зрения, но основная цель для следующих нескольких сообщений - доказать, что средство просмотра Forge способно отображать скелетную геометрию .

Я наткнулся на этот пример расширения от Филиппа Лифсма. Пример оказался полезной отправной точкой: он подсвечивает различные грани сетки объекта, который вы выбираете в просмотрщике. Было несколько изменений, которые я внес для того, чтобы все заработало:

  • Вместо добавления геометрии в сцену, я хочу добавить ее в «накладку визуализации», которая управляется отдельно инфраструктурой Forge viewer.
    • Есть закомментированный код, если вы хотите попробовать добавить геометрию непосредственно в основную сцену.
  • Я обнаружил, что мне было необходимо изменить способ отображения линий: стандартный материал линии не подходил мне, потому приходилось создавать 3D-геометрию (тонкий цилиндр или коробку), для представления каждой линии.
  • Мы используем TypeScript для реализации Dasher 360, поэтому я решил использовать его (у нас также есть собственный набор связанных с расширением функций, которые я использовал, поэтому код не может использоваться напрямую для людей, без них).

Вот краткое отображение результатов:

 

Мы рисуем красные сферы в вершинах, и рисуем края между ними, как зеленые цилиндры. Вы можете увидеть это в анимации:

 

Вот код, который делает все:

Код - JavaScript: [Выделить]
  1.     /// <reference path='../../types/three.d.ts' />
  2.                 import { Logger } from '../../core/Logger';
  3.                 let logger = Logger.getInstance();
  4.                 import { ShowableExtension } from '../../core/ShowableExtension';
  5.                
  6.  
  7.                 export class SkeletonExtension extends ShowableExtension {
  8.                
  9.  
  10.                   private _lineMaterial: any = null;
  11.                   private _vertexMaterial: any = null;
  12.                   private _overlayScene = "DasherSkeletonOverlay";
  13.                   private _toRemove: THREE.Object3D[];
  14.                
  15.  
  16.                   constructor(viewer: Autodesk.Viewing.Private.GuiViewer3D, options: any) {
  17.                     super(viewer, options);
  18.                     this._toRemove = [];
  19.   }
  20.                
  21.  
  22.                   public load(): boolean {
  23.                     logger.log('SkeletonExtension loaded');
  24.                     this.createUI(
  25.                       'toolbar-sensor-skeleton',
  26.                       'Skeletons',
  27.                       'DasherControlSensors',
  28.                       'grain'
  29.     );
  30.                
  31.  
  32.                     return true;
  33.   }
  34.                
  35.  
  36.                   public unload(): boolean {
  37.                     this.destroyUI('DasherControlSensors');
  38.                
  39.  
  40.                     logger.log('SkeletonExtension unloaded');
  41.                
  42.  
  43.                     return true;
  44.   }
  45.                
  46.  
  47.                   public show(): boolean {
  48.                
  49.  
  50.                     this.viewer.addEventListener(
  51.                       Autodesk.Viewing.SELECTION_CHANGED_EVENT,
  52.                       this.onSelectionChanged);
  53.                     this._vertexMaterial = this.createVertexMaterial();
  54.                     this._lineMaterial = this.createLineMaterial();
  55.                     this._toRemove = [];
  56.                     this.viewer.impl.createOverlayScene(this._overlayScene);
  57.                
  58.  
  59.                     this.viewer.getSelection().forEach(fragId => {
  60.                       this.drawMeshData(fragId);
  61.     });
  62.                
  63.  
  64.                     return true;
  65.   }
  66.                
  67.  
  68.                   public hide(): boolean {
  69.                
  70.  
  71.                     this.viewer.removeEventListener(
  72.                       Autodesk.Viewing.SELECTION_CHANGED_EVENT,
  73.                       this.onSelectionChanged);
  74.                     this._vertexMaterial = null;
  75.                     this._lineMaterial = null;
  76.                     this.clearAdditional();
  77.                
  78.  
  79.                     this.viewer.impl.removeOverlayScene(this._overlayScene);
  80.                
  81.  
  82.                     return true;
  83.   }
  84.                
  85.  
  86.                   private addToScene(obj: THREE.Object3D) {
  87.                     // this.viewer.impl.scene.add(obj);
  88.                     // this.viewer.impl.invalidate(true, true, false);
  89.                     this.viewer.impl.addOverlay(this._overlayScene, obj);
  90.                     this.viewer.impl.invalidate(false, false, true);
  91.                     this._toRemove.push(obj);
  92.   }
  93.                
  94.  
  95.                   private removeFromScene(obj: THREE.Object3D) {
  96.                     // this.viewer.impl.scene.remove(obj);
  97.                     // this.viewer.impl.invalidate(true, true, false);
  98.                     this.viewer.impl.removeOverlay(this._overlayScene, obj);
  99.                     this.viewer.impl.invalidate(false, false, true);
  100.   }
  101.                
  102.  
  103.                   private clearAdditional() {
  104.                     // Очистить предыдущую геометрию
  105.                
  106.  
  107.                     for(let obj of this._toRemove) {
  108.                       this.removeFromScene(obj);
  109.     }
  110.                     this._toRemove = [];
  111.   }
  112.                
  113.  
  114.                   private createVertexMaterial() {
  115.                
  116.  
  117.                     let material = new THREE.MeshPhongMaterial({ color: 0xff0000 });
  118.                
  119.  
  120.                     this.viewer.impl.matman().addMaterial(
  121.                       'dasher-material-vertex',
  122.                       material,
  123.                       true);
  124.                
  125.  
  126.                     return material;
  127.   }
  128.                
  129.  
  130.                   private createLineMaterial() {
  131.                
  132.  
  133.                     let material = new THREE.MeshBasicMaterial( { color: 0x00ff00 });
  134.                
  135.  
  136.                     this.viewer.impl.matman().addMaterial(
  137.                       'dasher-material-line',
  138.                       material,
  139.                       true);
  140.                
  141.  
  142.                     return material;
  143.   }
  144.                
  145.  
  146.                   private onSelectionChanged = (event) => {
  147.                
  148.  
  149.                     this.clearAdditional();
  150.                
  151.  
  152.                     event.fragIdsArray.forEach(fragId => {
  153.                       this.drawMeshData(fragId);
  154.     });
  155.   }
  156.                
  157.  
  158.                   private drawMeshData(fragId) {
  159.                
  160.  
  161.                     let fragProxy = this.viewer.impl.getFragmentProxy(
  162.                       this.viewer.model,
  163.                       fragId);
  164.                
  165.  
  166.                     let renderProxy = this.viewer.impl.getRenderProxy(
  167.                       this.viewer.model,
  168.                       fragId);
  169.                
  170.  
  171.                     fragProxy.getAnimTransform();
  172.                
  173.  
  174.                     let matrix = renderProxy.matrixWorld;
  175.                
  176.  
  177.                     let geometry = renderProxy.geometry;
  178.                
  179.  
  180.                     let attributes = geometry.attributes;
  181.                
  182.  
  183.                     let vA = new THREE.Vector3();
  184.                     let vB = new THREE.Vector3();
  185.                     let vC = new THREE.Vector3();
  186.                
  187.  
  188.                     if (attributes.index !== undefined) {
  189.                
  190.  
  191.                       let indices = attributes.index.array || geometry.ib;
  192.                       let positions = geometry.vb ? geometry.vb : attributes.position.array;
  193.                       let stride = geometry.vb ? geometry.vbstride : 3;
  194.                       let offsets = geometry.offsets;
  195.                
  196.  
  197.                       if (!offsets || offsets.length === 0) {
  198.                         offsets = [{start: 0, count: indices.length, index: 0}];
  199.       }
  200.                
  201.  
  202.                       for (let oi = 0, ol = offsets.length; oi < ol; ++oi) {
  203.                
  204.  
  205.                         let start = offsets[oi].start;
  206.                         let count = offsets[oi].count;
  207.                         let index = offsets[oi].index;
  208.                
  209.  
  210.                         for (let i = start, il = start + count; i < il; i += 3) {
  211.                
  212.  
  213.                           let a = index + indices[i];
  214.                           let b = index + indices[i + 1];
  215.                           let c = index + indices[i + 2];
  216.                
  217.  
  218.                           vA.fromArray(positions, a * stride);
  219.                           vB.fromArray(positions, b * stride);
  220.                           vC.fromArray(positions, c * stride);
  221.                
  222.  
  223.                           vA.applyMatrix4(matrix);
  224.                           vB.applyMatrix4(matrix);
  225.                           vC.applyMatrix4(matrix);
  226.                
  227.  
  228.                           const w = 0.5;
  229.                           const w2 = w / 2;
  230.                
  231.  
  232.                           this.drawVertex (vA, w);
  233.                           this.drawVertex (vB, w);
  234.                           this.drawVertex (vC, w);
  235.                
  236.  
  237.                           this.drawLine(vA, vB, w2);
  238.                           this.drawLine(vB, vC, w2);
  239.                           this.drawLine(vC, vA, w2);
  240.         }
  241.       }
  242.     }
  243.                     else {
  244.                
  245.  
  246.                       let positions = geometry.vb ? geometry.vb : attributes.position.array;
  247.                       let stride = geometry.vb ? geometry.vbstride : 3;
  248.                
  249.  
  250.                       for (let i = 0, j = 0, il = positions.length; i < il; i += 3, j += 9) {
  251.                
  252.  
  253.                         let a = i;
  254.                         let b = i + 1;
  255.                         let c = i + 2;
  256.                
  257.  
  258.                         vA.fromArray(positions, a * stride);
  259.                         vB.fromArray(positions, b * stride);
  260.                         vC.fromArray(positions, c * stride);
  261.                
  262.  
  263.                         vA.applyMatrix4(matrix);
  264.                         vB.applyMatrix4(matrix);
  265.                         vC.applyMatrix4(matrix);
  266.                
  267.  
  268.                         const w = 0.5;
  269.                         const w2 = w / 2;
  270.                
  271.  
  272.                         this.drawVertex (vA, w);
  273.                         this.drawVertex (vB, w);
  274.                         this.drawVertex (vC, w);
  275.                
  276.  
  277.                         this.drawLine(vA, vB, w2);
  278.                         this.drawLine(vB, vC, w2);
  279.                         this.drawLine(vC, vA, w2);
  280.       }
  281.     }
  282.   }
  283.  
  284.                   private geometryBetween(pointX, pointY, width): [THREE.Geometry, THREE.Matrix4] {
  285.                     let direction = new THREE.Vector3().subVectors(pointY, pointX);
  286.                     let orientation = new THREE.Matrix4();
  287.                     orientation.lookAt(pointX, pointY, new THREE.Object3D().up);
  288.                     orientation.multiply(new THREE.Matrix4().set(
  289.                         1, 0, 0, 0,
  290.                         0, 0, 1, 0,
  291.                         0, -1, 0, 0,
  292.                         0, 0, 0, 1));
  293.                     let length = direction.length();
  294.                     // let edgeGeometry = new THREE.BoxGeometry(width, length, width, 1, 1, 1);
  295.                     let edgeGeometry = new THREE.CylinderGeometry(width, width, length, 8, 1);
  296.                     let translate = new THREE.Matrix4().makeTranslation((pointY.x + pointX.x) / 2, (pointY.y + pointX.y) / 2, (pointY.z + pointX.z) / 2);
  297.                
  298.  
  299.                     return [edgeGeometry, translate.multiply(orientation)];
  300.   }
  301.                
  302.  
  303.                   private drawLine(pointX, pointY, radius) {
  304.                     let geom = this.geometryBetween(pointX, pointY, radius);
  305.                     let edge = new THREE.Mesh(geom[0], this._lineMaterial);
  306.                     edge.applyMatrix(geom[1]);
  307.                
  308.  
  309.                     this.addToScene(edge);
  310.                
  311.  
  312.                     return edge;
  313.   }
  314.                
  315.  
  316.                   private drawVertex (v, radius) {
  317.                
  318.  
  319.                     let vertex = new THREE.Mesh(new THREE.SphereGeometry(radius, 20), this._vertexMaterial);
  320.                     vertex.position.set(v.x, v.y, v.z);
  321.                
  322.  
  323.                     this.addToScene(vertex);
  324.                
  325.  
  326.                     return vertex;
  327.   }
  328.                 }

В следующем посте мы увидим, как мы можем изменить код размещения геометрии, чтобы создать простой скелет по выбранной геометрии.

Источник: http://www.keanw.com/2018/08/adding-3d-geometry-to-a-scene-in-the-forge-viewer.html

 

Автор перевода: Дмитрий Емельянов
Опубликовано 31.08.2018
Отредактировано 31.08.2018 в 15:22:49