Добавление 3D-геометрии в сцену в приложении Forge
В последнем сообщении я представил серию, в которой я рассказываю о пути, который я прошел, чтобы добавить данные скелета в Dasher 360 (что, конечно же, основано на просмотрщике Forge).
Первым шагом, который я предпринял на этом пути, был поиск способа добавления простой 3D-геометрии в существующую сцену внутри Viewer. Это то, что мы делаем ограниченным образом внутри Dasher - мы используем облака точек для представления местоположений датчиков, например, - но я хотел разработать правильный подход для этого для данных, которые могли бы показывать тела людей, когда они ходят. Конечная цель будет заключаться в том, чтобы скелетное позиционирование было основано на базе данных, которая была заполнена нейронной сетью, использующей данные компьютерного зрения, но основная цель для следующих нескольких сообщений - доказать, что средство просмотра Forge способно отображать скелетную геометрию .
Я наткнулся на этот пример расширения от Филиппа Лифсма. Пример оказался полезной отправной точкой: он подсвечивает различные грани сетки объекта, который вы выбираете в просмотрщике. Было несколько изменений, которые я внес для того, чтобы все заработало:
- Вместо добавления геометрии в сцену, я хочу добавить ее в «накладку визуализации», которая управляется отдельно инфраструктурой Forge viewer.
- Есть закомментированный код, если вы хотите попробовать добавить геометрию непосредственно в основную сцену.
- Я обнаружил, что мне было необходимо изменить способ отображения линий: стандартный материал линии не подходил мне, потому приходилось создавать 3D-геометрию (тонкий цилиндр или коробку), для представления каждой линии.
- Мы используем TypeScript для реализации Dasher 360, поэтому я решил использовать его (у нас также есть собственный набор связанных с расширением функций, которые я использовал, поэтому код не может использоваться напрямую для людей, без них).
Вот краткое отображение результатов:
Мы рисуем красные сферы в вершинах, и рисуем края между ними, как зеленые цилиндры. Вы можете увидеть это в анимации:
Вот код, который делает все:
- /// <reference path='../../types/three.d.ts' />
- import { Logger } from '../../core/Logger';
- let logger = Logger.getInstance();
- import { ShowableExtension } from '../../core/ShowableExtension';
- export class SkeletonExtension extends ShowableExtension {
- private _lineMaterial: any = null;
- private _vertexMaterial: any = null;
- private _overlayScene = "DasherSkeletonOverlay";
- private _toRemove: THREE.Object3D[];
- constructor(viewer: Autodesk.Viewing.Private.GuiViewer3D, options: any) {
- super(viewer, options);
- this._toRemove = [];
- }
- public load(): boolean {
- logger.log('SkeletonExtension loaded');
- this.createUI(
- 'toolbar-sensor-skeleton',
- 'Skeletons',
- 'DasherControlSensors',
- 'grain'
- );
- return true;
- }
- public unload(): boolean {
- this.destroyUI('DasherControlSensors');
- logger.log('SkeletonExtension unloaded');
- return true;
- }
- public show(): boolean {
- this.viewer.addEventListener(
- Autodesk.Viewing.SELECTION_CHANGED_EVENT,
- this.onSelectionChanged);
- this._vertexMaterial = this.createVertexMaterial();
- this._lineMaterial = this.createLineMaterial();
- this._toRemove = [];
- this.viewer.impl.createOverlayScene(this._overlayScene);
- this.viewer.getSelection().forEach(fragId => {
- this.drawMeshData(fragId);
- });
- return true;
- }
- public hide(): boolean {
- this.viewer.removeEventListener(
- Autodesk.Viewing.SELECTION_CHANGED_EVENT,
- this.onSelectionChanged);
- this._vertexMaterial = null;
- this._lineMaterial = null;
- this.clearAdditional();
- this.viewer.impl.removeOverlayScene(this._overlayScene);
- return true;
- }
- private addToScene(obj: THREE.Object3D) {
- // this.viewer.impl.scene.add(obj);
- // this.viewer.impl.invalidate(true, true, false);
- this.viewer.impl.addOverlay(this._overlayScene, obj);
- this.viewer.impl.invalidate(false, false, true);
- this._toRemove.push(obj);
- }
- private removeFromScene(obj: THREE.Object3D) {
- // this.viewer.impl.scene.remove(obj);
- // this.viewer.impl.invalidate(true, true, false);
- this.viewer.impl.removeOverlay(this._overlayScene, obj);
- this.viewer.impl.invalidate(false, false, true);
- }
- private clearAdditional() {
- // Очистить предыдущую геометрию
- for(let obj of this._toRemove) {
- this.removeFromScene(obj);
- }
- this._toRemove = [];
- }
- private createVertexMaterial() {
- let material = new THREE.MeshPhongMaterial({ color: 0xff0000 });
- this.viewer.impl.matman().addMaterial(
- 'dasher-material-vertex',
- material,
- true);
- return material;
- }
- private createLineMaterial() {
- let material = new THREE.MeshBasicMaterial( { color: 0x00ff00 });
- this.viewer.impl.matman().addMaterial(
- 'dasher-material-line',
- material,
- true);
- return material;
- }
- private onSelectionChanged = (event) => {
- this.clearAdditional();
- event.fragIdsArray.forEach(fragId => {
- this.drawMeshData(fragId);
- });
- }
- private drawMeshData(fragId) {
- let fragProxy = this.viewer.impl.getFragmentProxy(
- this.viewer.model,
- fragId);
- let renderProxy = this.viewer.impl.getRenderProxy(
- this.viewer.model,
- fragId);
- fragProxy.getAnimTransform();
- let matrix = renderProxy.matrixWorld;
- let geometry = renderProxy.geometry;
- let attributes = geometry.attributes;
- let vA = new THREE.Vector3();
- let vB = new THREE.Vector3();
- let vC = new THREE.Vector3();
- if (attributes.index !== undefined) {
- let indices = attributes.index.array || geometry.ib;
- let positions = geometry.vb ? geometry.vb : attributes.position.array;
- let stride = geometry.vb ? geometry.vbstride : 3;
- let offsets = geometry.offsets;
- if (!offsets || offsets.length === 0) {
- offsets = [{start: 0, count: indices.length, index: 0}];
- }
- for (let oi = 0, ol = offsets.length; oi < ol; ++oi) {
- let start = offsets[oi].start;
- let count = offsets[oi].count;
- let index = offsets[oi].index;
- for (let i = start, il = start + count; i < il; i += 3) {
- let a = index + indices[i];
- let b = index + indices[i + 1];
- let c = index + indices[i + 2];
- vA.fromArray(positions, a * stride);
- vB.fromArray(positions, b * stride);
- vC.fromArray(positions, c * stride);
- vA.applyMatrix4(matrix);
- vB.applyMatrix4(matrix);
- vC.applyMatrix4(matrix);
- const w = 0.5;
- const w2 = w / 2;
- this.drawVertex (vA, w);
- this.drawVertex (vB, w);
- this.drawVertex (vC, w);
- this.drawLine(vA, vB, w2);
- this.drawLine(vB, vC, w2);
- this.drawLine(vC, vA, w2);
- }
- }
- }
- else {
- let positions = geometry.vb ? geometry.vb : attributes.position.array;
- let stride = geometry.vb ? geometry.vbstride : 3;
- for (let i = 0, j = 0, il = positions.length; i < il; i += 3, j += 9) {
- let a = i;
- let b = i + 1;
- let c = i + 2;
- vA.fromArray(positions, a * stride);
- vB.fromArray(positions, b * stride);
- vC.fromArray(positions, c * stride);
- vA.applyMatrix4(matrix);
- vB.applyMatrix4(matrix);
- vC.applyMatrix4(matrix);
- const w = 0.5;
- const w2 = w / 2;
- this.drawVertex (vA, w);
- this.drawVertex (vB, w);
- this.drawVertex (vC, w);
- this.drawLine(vA, vB, w2);
- this.drawLine(vB, vC, w2);
- this.drawLine(vC, vA, w2);
- }
- }
- }
- private geometryBetween(pointX, pointY, width): [THREE.Geometry, THREE.Matrix4] {
- let direction = new THREE.Vector3().subVectors(pointY, pointX);
- let orientation = new THREE.Matrix4();
- orientation.lookAt(pointX, pointY, new THREE.Object3D().up);
- orientation.multiply(new THREE.Matrix4().set(
- 1, 0, 0, 0,
- 0, 0, 1, 0,
- 0, -1, 0, 0,
- 0, 0, 0, 1));
- let length = direction.length();
- // let edgeGeometry = new THREE.BoxGeometry(width, length, width, 1, 1, 1);
- let edgeGeometry = new THREE.CylinderGeometry(width, width, length, 8, 1);
- let translate = new THREE.Matrix4().makeTranslation((pointY.x + pointX.x) / 2, (pointY.y + pointX.y) / 2, (pointY.z + pointX.z) / 2);
- return [edgeGeometry, translate.multiply(orientation)];
- }
- private drawLine(pointX, pointY, radius) {
- let geom = this.geometryBetween(pointX, pointY, radius);
- let edge = new THREE.Mesh(geom[0], this._lineMaterial);
- edge.applyMatrix(geom[1]);
- this.addToScene(edge);
- return edge;
- }
- private drawVertex (v, radius) {
- let vertex = new THREE.Mesh(new THREE.SphereGeometry(radius, 20), this._vertexMaterial);
- vertex.position.set(v.x, v.y, v.z);
- this.addToScene(vertex);
- return vertex;
- }
- }
В следующем посте мы увидим, как мы можем изменить код размещения геометрии, чтобы создать простой скелет по выбранной геометрии.
Источник: http://www.keanw.com/2018/08/adding-3d-geometry-to-a-scene-in-the-forge-viewer.html
Обсуждение: http://adn-cis.org/forum/index.php?topic=
Опубликовано 31.08.2018Отредактировано 31.08.2018 в 15:22:49