| @@ -119,9 +119,9 @@ To make changes and run the example, click on the CodePen button on the top righ | |||
| - [@threepipe/plugin-tweakpane](#threepipeplugin-tweakpane) Tweakpane UI Plugin | |||
| - [@threepipe/plugin-blueprintjs](#threepipeplugin-blueprintjs) BlueprintJs UI Plugin | |||
| - [@threepipe/plugin-tweakpane-editor](#threepipeplugin-tweakpane-editor) - Tweakpane Editor Plugin | |||
| - [@threepipe/plugin-extra-importers](#threepipeplugin-extra-importers) - Plugin for loading more file types supported by loaders in three.js | |||
| - [@threepipe/plugins-extra-importers](#threepipeplugins-extra-importers) - Plugin for loading more file types supported by loaders in three.js | |||
| - [@threepipe/plugin-blend-importer](#threepipeplugin-blend-importer) - Blender to add support for loading .blend file | |||
| - [@threepipe/plugin-geometry-generator](#threepipeplugin-extra-importers) - Generate parametric geometry types that can be re-generated from UI/API. | |||
| - [@threepipe/plugin-geometry-generator](#threepipeplugin-geometry-generator) - Generate parametric geometry types that can be re-generated from UI/API. | |||
| ## Getting Started | |||
| @@ -326,7 +326,7 @@ Plugins can add additional formats: | |||
| * ktx - Using [KTXLoadPlugin](#KTXLoadPlugin) | |||
| * ktx2 - Using [KTX2LoadPlugin](#KTX2LoadPlugin) | |||
| Plugins to support more model formats are available in the package [@threepipe/plugin-extra-importers](#threepipeplugin-extra-importers) including .3ds, | |||
| Plugins to support more model formats are available in the package [@threepipe/plugins-extra-importers](#threepipeplugins-extra-importers) including .3ds, | |||
| .3mf, .collada, .amf, .bvh, .vox, .gcode, .mdd, .pcd, .tilt, .wrl, .mpd, .vtk, .xyz | |||
| ## Loading files | |||
| @@ -1824,7 +1824,9 @@ camera.setControlsCtor('customOrbit', (camera, domElement) => new CustomOrbitCon | |||
| camera.controlsMode = 'customOrbit' // this will initialize the controls with the customOrbit constructor and set it on the camera | |||
| // Disable interactions to the camera. (eg when animating) | |||
| camera.interactionsEnabled = false | |||
| camera.setInteractions(false, 'animation') | |||
| // Enable interactions back | |||
| camera.setInteractions(true, 'animation') // this will enable interactions when all the keys have been set to true(which were set to false earlier) | |||
| // Force refresh aspect ratio (this is done automatically with a ResizeObserver on the canvas in the viewer) | |||
| camera.refreshAspect() | |||
| @@ -1857,7 +1859,7 @@ camera.deactivateMain() | |||
| [`camera.setControlsCtor`](https://threepipe.org/docs/classes/PerspectiveCamera2.html#setControlsCtor) - Register a custom camera controls constructor. The controls can be set by setting `controlsMode` to the key/name of the controls. | |||
| [`camera.interactionsEnabled`](https://threepipe.org/docs/classes/PerspectiveCamera2.html#interactionsEnabled) - If `true`, the camera can be interacted with. This is useful when animating the camera or using the window scroll or programmatically automating the viewer. | |||
| [`camera.setInteractions`](https://threepipe.org/docs/classes/PerspectiveCamera2.html#setInteractions) - If `true`, the camera can be interacted with. This is useful when animating the camera or using the window scroll or programmatically automating the viewer. Using this multiple plugins can disable interactions and it will be enabled again when all of them enable it back. | |||
| [`camera.refreshAspect`](https://threepipe.org/docs/classes/PerspectiveCamera2.html#refreshAspect) - Force refresh aspect ratio (this is done automatically with a ResizeObserver on the canvas in the viewer or when `viewer.resize()` is called) | |||
| @@ -2977,7 +2979,7 @@ editor.loadPlugins({ | |||
| }) | |||
| ``` | |||
| ## @threepipe/plugin-extra-importers | |||
| ## @threepipe/plugins-extra-importers | |||
| Exports several plugins to add support for various file types. | |||
| @@ -2985,7 +2987,7 @@ Exports several plugins to add support for various file types. | |||
| [Source Code](./plugins/extra-importers/src/index.ts) — | |||
| [API Reference](https://threepipe.org/plugins/extra-importers/docs) | |||
| NPM: `npm install @threepipe/plugin-extra-importers` | |||
| NPM: `npm install @threepipe/plugins-extra-importers` | |||
| CDN: https://threepipe.org/plugins/extra-importers/dist/index.mjs | |||
| @@ -3009,7 +3011,7 @@ This package exports several plugins to add support for several file types using | |||
| To add all the plugins at once use `extraImporters`. This adds support for loading all the above file types. | |||
| ```typescript | |||
| import {ThreeViewer} from 'threepipe' | |||
| import {extraImporters} from '@threepipe/plugin-extra-importers' | |||
| import {extraImporters} from '@threepipe/plugins-extra-importers' | |||
| const viewer = new ThreeViewer({...}) | |||
| viewer.addPluginsSync(extraImporters) | |||
| @@ -1,9 +1,7 @@ | |||
| // rollup.config.js | |||
| import commonjs from '@rollup/plugin-commonjs'; | |||
| import json from '@rollup/plugin-json'; | |||
| import resolve from '@rollup/plugin-node-resolve'; | |||
| import typescript from '@rollup/plugin-typescript'; | |||
| import license from 'rollup-plugin-license' | |||
| import packageJson from './package.json' assert {type: 'json'}; | |||
| import path from 'path' | |||
| import {fileURLToPath} from 'url'; | |||
| @@ -11,6 +9,8 @@ import postcss from 'rollup-plugin-postcss' | |||
| import glsl from "rollup-plugin-glsl" | |||
| import replace from "@rollup/plugin-replace"; | |||
| import terser from "@rollup/plugin-terser"; | |||
| import commonjs from "@rollup/plugin-commonjs"; | |||
| import license from "rollup-plugin-license"; | |||
| const __filename = fileURLToPath(import.meta.url); | |||
| const __dirname = path.dirname(__filename); | |||
| @@ -21,13 +21,13 @@ const isProduction = process.env.NODE_ENV === 'production' | |||
| const settings = { | |||
| globals: {}, | |||
| sourcemap: true | |||
| sourcemap: isProduction | |||
| } | |||
| export default { | |||
| input: './src/index.ts', | |||
| output: [ | |||
| // { | |||
| // { | |||
| // file: main, | |||
| // name: main, | |||
| // ...settings, | |||
| @@ -45,7 +45,7 @@ export default { | |||
| // preserveModulesRoot: 'src', // optional but useful to create a more plain folder structure | |||
| format: 'es' | |||
| }, | |||
| { | |||
| isProduction ? { | |||
| file: browser, | |||
| ...settings, | |||
| name: name, | |||
| @@ -53,7 +53,7 @@ export default { | |||
| plugins: [ | |||
| isProduction && terser() | |||
| ] | |||
| } | |||
| } : null, | |||
| ], | |||
| external: [], | |||
| plugins: [ | |||
| @@ -1,13 +1,20 @@ | |||
| import {Object3D} from 'three' | |||
| import {Class, serialize} from 'ts-browser-helpers' | |||
| import {Class, onChange, serialize} from 'ts-browser-helpers' | |||
| import {AViewerPluginSync, ThreeViewer} from '../../viewer' | |||
| import {BoxSelectionWidget, ObjectPicker, SelectionWidget} from '../../three' | |||
| import {IObject3D, IObject3DEvent, ISceneEvent} from '../../core' | |||
| import {IUiConfigContainer, UiObjectConfig} from 'uiconfig.js' | |||
| import {FrameFadePlugin} from '../pipeline/FrameFadePlugin' | |||
| export class PickingPlugin extends AViewerPluginSync<'selectedObjectChanged'|'hoverObjectChanged'|'hitObject'> { | |||
| @serialize() enabled = true | |||
| private _enableWidget = true | |||
| @serialize() | |||
| @onChange(PickingPlugin.prototype._enableChange) | |||
| enabled = true | |||
| private _enableChange() { | |||
| if (!this._viewer) return | |||
| if (!this.enabled) this.setSelectedObject(undefined) // todo | |||
| } | |||
| get picker(): ObjectPicker|undefined { | |||
| return this._picker | |||
| @@ -33,6 +40,19 @@ export class PickingPlugin extends AViewerPluginSync<'selectedObjectChanged'|'ho | |||
| // @serialize() // todo | |||
| autoFocusHover = false | |||
| /** | |||
| * Note: this is for runtime use only, not serialized | |||
| */ | |||
| @onChange(PickingPlugin.prototype._widgetEnabledChange) | |||
| widgetEnabled = true | |||
| protected _widgetEnabledChange() { | |||
| if (this.widgetEnabled && this._picker?.selectedObject) | |||
| this._widget?.attach(this._picker.selectedObject) | |||
| else | |||
| this._widget?.detach() | |||
| } | |||
| public setDirty() { | |||
| this._viewer?.setDirty() | |||
| } | |||
| @@ -68,6 +88,7 @@ export class PickingPlugin extends AViewerPluginSync<'selectedObjectChanged'|'ho | |||
| onAdded(viewer: ThreeViewer): void { | |||
| super.onAdded(viewer) | |||
| this._enableChange() | |||
| this._picker = new ObjectPicker(viewer.scene.modelRoot, viewer.canvas, viewer.scene.mainCamera, (obj)=>{ | |||
| const hasMat = obj.material | |||
| if (!hasMat) return false | |||
| @@ -161,12 +182,22 @@ export class PickingPlugin extends AViewerPluginSync<'selectedObjectChanged'|'ho | |||
| private _onObjectSelectEvent = (e: IObject3DEvent)=>{ | |||
| if (e.source === PickingPlugin.PluginType) return | |||
| if (e.object === undefined && e.value === undefined) console.error('e.object or e.value must be set for picking, can be null to unselect') | |||
| else this.setSelectedObject(e.value, this.autoFocus || e.focusCamera) | |||
| else this.setSelectedObject(e.object || e.value, this.autoFocus || e.focusCamera) | |||
| } | |||
| private _selectedObjectChanged = (e: any) => { | |||
| if (!this._viewer) return | |||
| this.dispatchEvent(e) | |||
| const selected = this._picker?.selectedObject || undefined | |||
| const selected = this._picker?.selectedObject || undefined // or use e.object. doing this so that listeners can change the selected object in dispatch above | |||
| const frameFade = this._viewer.getPlugin(FrameFadePlugin) | |||
| if (frameFade) { | |||
| if (selected) frameFade.disable(PickingPlugin.PluginType) | |||
| else frameFade.enable(PickingPlugin.PluginType) | |||
| } | |||
| this._viewer.scene.autoNearFarEnabled = !selected // for widgets etc, this can be removed when they are rendered in a separate pass | |||
| if (this._pickUi) { | |||
| const sUiConfig = (selected as IUiConfigContainer)?.uiConfig | |||
| @@ -177,17 +208,17 @@ export class PickingPlugin extends AViewerPluginSync<'selectedObjectChanged'|'ho | |||
| } | |||
| const widget = this._widget | |||
| if (widget && this._enableWidget) { | |||
| if (widget && this.widgetEnabled) { | |||
| if (selected) widget.attach(selected) | |||
| else widget.detach() | |||
| } | |||
| // if (selected) selected.dispatchEvent({type: 'selected', source: PickingPlugin.PluginType, object: selected}) | |||
| this._viewer?.setDirty() | |||
| this._viewer.setDirty() | |||
| if (this.autoFocus) { | |||
| // this._viewer?.resetCamera({rootObject: selected, centerOffset: new Vector3(4, 4, 4)}) | |||
| // this._viewer.resetCamera({rootObject: selected, centerOffset: new Vector3(4, 4, 4)}) | |||
| this.focusObject(selected) | |||
| } | |||
| @@ -199,7 +230,7 @@ export class PickingPlugin extends AViewerPluginSync<'selectedObjectChanged'|'ho | |||
| const selected = this._picker?.hoverObject || undefined | |||
| const widget = this._hoverWidget | |||
| if (widget && this._enableWidget) { | |||
| if (widget && this.widgetEnabled) { | |||
| if (selected) widget.attach(selected) | |||
| else widget.detach() | |||
| } | |||
| @@ -229,17 +260,6 @@ export class PickingPlugin extends AViewerPluginSync<'selectedObjectChanged'|'ho | |||
| this._viewer?.fitToView(selected, 1.25, 1000, 'easeOut') | |||
| } | |||
| public enableWidget(enable: boolean): void { | |||
| this._enableWidget = enable | |||
| if (enable) { | |||
| const selected = this._picker?.selectedObject || undefined | |||
| if (selected) | |||
| this._widget?.attach(selected) | |||
| } else { | |||
| this._widget?.detach() | |||
| } | |||
| } | |||
| private _uiConfigChildren: UiObjectConfig[] = [ | |||
| { | |||
| label: 'Enabled', | |||
| @@ -267,6 +287,11 @@ export class PickingPlugin extends AViewerPluginSync<'selectedObjectChanged'|'ho | |||
| hidden: ()=>!this.hoverEnabled, | |||
| property: [this, 'autoFocusHover'], | |||
| }, | |||
| { | |||
| label: 'Widget Enabled', | |||
| type: 'checkbox', | |||
| property: [this, 'widgetEnabled'], | |||
| }, | |||
| ] | |||
| uiConfig: UiObjectConfig = { | |||