UNPKG

threepipe

Version:

A modern 3D viewer framework built on top of three.js, written in TypeScript, designed to make creating high-quality, modular, and extensible 3D experiences on the web simple and enjoyable.

177 lines 7.07 kB
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; import { AViewerPluginSync } from '../../viewer'; import { PickingPlugin } from '../interaction/PickingPlugin'; import { uiButton, uiSlider } from 'uiconfig.js'; import { Vector3 } from 'three'; /** * Boilerplate for implementing a plugin for simplifying geometries. * This is a base class and cannot be used directly. * See {@link MeshOptSimplifyModifierPlugin} the [simplify-modifier-plugin](https://threepipe.org/examples/#simplify-modifier-plugin) example for a sample implementation. */ export class SimplifyModifierPlugin extends AViewerPluginSync { constructor() { super(); this.enabled = true; this.toJSON = undefined; /** * Factor of vertices to remove. eg 0.5 will remove half of the vertices. * Default is 0.5 * This is used when no factor or count is provided in the options to simplifyGeometry or simplifyGeometries. */ this.simplifyFactor = 0.5; } get initialized() { return true; } async initialize() { return; } onAdded(viewer) { super.onAdded(viewer); this._pickingPlugin = viewer.getPlugin(PickingPlugin); } simplifyGeometries(geometry, options) { if (!geometry) { const selected = this._pickingPlugin?.getSelectedObject(); if (!selected?.isObject3D) return; const geom = []; selected?.traverse((o) => { if (o.geometry && !geom.includes(o.geometry)) geom.push(o.geometry); }); geometry = geom; if (!geometry || !geometry.length) return; } if (!Array.isArray(geometry)) geometry = [geometry]; const res = []; for (const g of geometry) { res.push(this.simplifyGeometry(g, options)); } return res; } simplifyGeometry(geometry, { factor, count, replace = true, disposeOnReplace = false, } = {}) { if (!geometry) { const selected = this._pickingPlugin?.getSelectedObject(); geometry = selected?.geometry; if (!geometry) return undefined; } if (!geometry.attributes.position) { this._viewer?.console.error('SimplifyModifierPlugin: Geometry does not have position attribute', geometry); return geometry; } factor = factor || this.simplifyFactor; count = count || geometry.attributes.position.count * factor; if (!geometry.boundingBox) geometry.computeBoundingBox(); const simplified = this._simplify(geometry, count); simplified.computeBoundingBox(); simplified.computeBoundingSphere(); simplified.computeVertexNormals(); const bbox = simplified.boundingBox; const size = bbox.getSize(new Vector3()); if (!isFinite(size.x) || !isFinite(size.y) || !isFinite(size.z)) { this._viewer?.console.error('SimplifyModifierPlugin: Unable to simplify', geometry, simplified, size); return geometry; } const oldBB = geometry.boundingBox; const oldSize = oldBB.getSize(new Vector3()); const diff = size.clone().sub(oldSize); const diffPerc = diff.clone().divide(oldSize); if (diffPerc.lengthSq() > 0.001) { // todo: add option to skip this console.warn('Simplify', geometry, simplified, bbox, oldBB, size, oldSize, diff, diffPerc); } // simplified.setDirty() if (!replace) return simplified; // not working? // geometry.copy(simplified) // geometry.setDirty() // simplified.dispose() const meshes = geometry.appliedMeshes; if (!meshes) { console.error('No meshes found for geometry, cannot replace', geometry); return simplified; } for (const mesh of meshes) { mesh.geometry = simplified; } if (disposeOnReplace) { geometry.dispose(true); } return simplified; } async simplifyAll(root, options) { if (!root && this._viewer) root = this._viewer.scene.modelRoot; if (!root) { console.error('SimplifyModifierPlugin: No root found'); return; } if (!this.initialized) { await this.initialize(); if (!this.initialized) { this._viewer?.console.error('SimplifyModifierPlugin cannot be initialized'); return; } } const geometries = []; root.traverse((o) => { if (o.geometry && !geometries.includes(o.geometry)) geometries.push(o.geometry); }); if (!geometries.length) { console.error('SimplifyModifierPlugin: No geometries found'); return; } return this.simplifyGeometries(geometries, options); } async simplifySelected() { if (!this._viewer) return; if (!this.initialized) { await this.initialize(); if (!this.initialized) { await this._viewer.dialog.alert('Simplify: SimplifyModifierPlugin cannot be initialized'); return; } } const selected = this._pickingPlugin?.getSelectedObject(); if (!selected?.isObject3D) { await this._viewer.dialog.alert('Simplify: No Object Selected'); return; } let doAll = false; if (!selected.geometry) doAll = true; else if (selected.children.length === 0) doAll = true; if (!doAll) { const resp = await this._viewer.dialog.confirm('Simplify: Simplify all in hierarchy?'); if (resp) doAll = true; } if (doAll) { this.simplifyGeometries(); } else { this.simplifyGeometry(selected.geometry); } } } SimplifyModifierPlugin.PluginType = 'SimplifyModifierPlugin'; __decorate([ uiSlider('Simplify Factor', [0, 1]) ], SimplifyModifierPlugin.prototype, "simplifyFactor", void 0); __decorate([ uiButton('Simplify All', { sendArgs: false }) ], SimplifyModifierPlugin.prototype, "simplifyAll", null); __decorate([ uiButton('Simplify Selected') ], SimplifyModifierPlugin.prototype, "simplifySelected", null); //# sourceMappingURL=SimplifyModifierPlugin.js.map