| 'ecmaVersion': 2021, // Allows for the parsing of modern ECMAScript features | 'ecmaVersion': 2021, // Allows for the parsing of modern ECMAScript features | ||||
| 'sourceType': 'module', // Allows for the use of imports | 'sourceType': 'module', // Allows for the use of imports | ||||
| 'project': ['./tsconfig.json', './examples/tsconfig.json', | 'project': ['./tsconfig.json', './examples/tsconfig.json', | ||||
| './plugins/tweakpane-editor/tsconfig.json', | |||||
| './plugins/tweakpane/tsconfig.json', | |||||
| './plugins/**/tsconfig.json', | |||||
| ], | ], | ||||
| 'tsconfigRootDir': './', | 'tsconfigRootDir': './', | ||||
| }, | }, |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>Rhino 3DM To GLB</title> | <title>Rhino 3DM To GLB</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>Camera UiConfig</title> | <title>Camera UiConfig</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>Custom Pipeline</title> | <title>Custom Pipeline</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>Depth Buffer Plugin</title> | <title>Depth Buffer Plugin</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>Directional Light</title> | <title>Directional Light</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>DRACO(DRC) Load</title> | <title>DRACO(DRC) Load</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>Dropzone Plugin</title> | <title>Dropzone Plugin</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>EXR Load</title> | <title>EXR Load</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <!DOCTYPE html> | |||||
| <html lang="en"> | |||||
| <head> | |||||
| <meta charset="UTF-8"> | |||||
| <title>Extra importer plugins</title> | |||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | |||||
| <!-- Remove this when import maps will be widely supported --> | |||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | |||||
| <script type="importmap"> | |||||
| { | |||||
| "imports": { | |||||
| "three": "./../../dist/index.mjs", | |||||
| "threepipe": "./../../dist/index.mjs", | |||||
| "@threepipe/plugin-extra-importers": "./../../plugins/extra-importers/dist/index.mjs" | |||||
| } | |||||
| } | |||||
| </script> | |||||
| <style id="example-style"> | |||||
| html, body, #canvas-container, #mcanvas { | |||||
| width: 100%; | |||||
| height: 100%; | |||||
| margin: 0; | |||||
| overflow: hidden; | |||||
| } | |||||
| p{ | |||||
| position: absolute; | |||||
| top: 5%; | |||||
| left: 50%; | |||||
| transform: translate(-50%, -50%); | |||||
| font-size: 1.25em; | |||||
| color: #8cd55b; | |||||
| font-family: sans-serif; | |||||
| pointer-events: none; | |||||
| } | |||||
| </style> | |||||
| <script type="module" src="../examples-utils/simple-code-preview.mjs"></script> | |||||
| <script id="example-script" type="module" src="./script.js" data-scripts="./script.ts;./script.js"></script> | |||||
| </head> | |||||
| <body> | |||||
| <div id="canvas-container"> | |||||
| <p>Drop .3ds .3mf .collada .amf .bvh .vox .gcode .mdd .pcd .tilt .wrl .mpd .vtk .xyz files here</p> | |||||
| <canvas id="mcanvas"></canvas> | |||||
| </div> | |||||
| </body> |
| import {_testFinish, GLTFAnimationPlugin, HemisphereLight, ImportAddOptions, IObject3D, ThreeViewer} from 'threepipe' | |||||
| import { | |||||
| AMFLoadPlugin, | |||||
| BVHLoadPlugin, | |||||
| ColladaLoadPlugin, | |||||
| GCodeLoadPlugin, | |||||
| LDrawLoadPlugin, | |||||
| MDDLoadPlugin, | |||||
| PCDLoadPlugin, | |||||
| TDSLoadPlugin, | |||||
| ThreeMFLoadPlugin, | |||||
| TiltLoadPlugin, | |||||
| VOXLoadPlugin, | |||||
| VRMLLoadPlugin, | |||||
| VTKLoadPlugin, | |||||
| XYZLoadPlugin, | |||||
| } from '@threepipe/plugin-extra-importers' | |||||
| async function init() { | |||||
| const viewer = new ThreeViewer({ | |||||
| canvas: document.getElementById('mcanvas') as HTMLCanvasElement, | |||||
| msaa: true, | |||||
| dropzone: { | |||||
| addOptions: { | |||||
| disposeSceneObjects: true, | |||||
| }, | |||||
| }, | |||||
| }) | |||||
| viewer.addPluginsSync([ | |||||
| GLTFAnimationPlugin, | |||||
| TDSLoadPlugin, | |||||
| ThreeMFLoadPlugin, | |||||
| ColladaLoadPlugin, | |||||
| AMFLoadPlugin, | |||||
| GCodeLoadPlugin, | |||||
| BVHLoadPlugin, | |||||
| VOXLoadPlugin, | |||||
| MDDLoadPlugin, | |||||
| PCDLoadPlugin, | |||||
| TiltLoadPlugin, | |||||
| VRMLLoadPlugin, | |||||
| LDrawLoadPlugin, | |||||
| VTKLoadPlugin, | |||||
| XYZLoadPlugin, | |||||
| ]) | |||||
| viewer.getPlugin(GLTFAnimationPlugin)!.autoplayOnLoad = true | |||||
| viewer.scene.mainCamera.autoNearFar = false | |||||
| viewer.scene.setBackgroundColor('#555555') | |||||
| viewer.scene.addObject(new HemisphereLight(0xffffff, 0x444444, 2)) | |||||
| await viewer.setEnvironmentMap('https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr') | |||||
| const urls = [ | |||||
| 'https://threejs.org/examples/models/3ds/portalgun/portalgun.3ds', | |||||
| 'https://threejs.org/examples/models/3mf/cube_gears.3mf', | |||||
| 'https://threejs.org/examples/models/collada/elf/elf.dae', | |||||
| 'https://threejs.org/examples/models/amf/rook.amf', | |||||
| 'https://threejs.org/examples/models/gcode/benchy.gcode', | |||||
| 'https://threejs.org/examples/models/bvh/pirouette.bvh', | |||||
| 'https://threejs.org/examples/models/vox/monu10.vox', | |||||
| 'https://threejs.org/examples/models/mdd/cube.mdd', | |||||
| 'https://threejs.org/examples/models/pcd/binary/Zaghetto.pcd', | |||||
| 'https://threejs.org/examples/models/tilt/BRUSH_DOME.tilt', | |||||
| 'https://threejs.org/examples/models/ldraw/officialLibrary/models/car.ldr_Packed.mpd', | |||||
| 'https://threejs.org/examples/models/vtk/bunny.vtk', | |||||
| 'https://threejs.org/examples/models/vtk/cube_binary.vtp', | |||||
| 'https://threejs.org/examples/models/xyz/helix_201.xyz', | |||||
| ] | |||||
| const options: ImportAddOptions = { | |||||
| autoScale: true, | |||||
| autoCenter: true, | |||||
| autoScaleRadius: 0.5, | |||||
| clearSceneObjects: false, | |||||
| } | |||||
| let i = 0 | |||||
| const models = await Promise.allSettled(urls.map(async url => | |||||
| viewer.load<IObject3D>(url, options).then(res => { | |||||
| if (!res) return | |||||
| res.position.set(i % 4 - 1.5, 0, Math.floor(i / 4) - 1.5).multiplyScalar(1) | |||||
| res.setDirty() | |||||
| i++ | |||||
| return res | |||||
| }))) | |||||
| console.log(models) | |||||
| } | |||||
| init().then(_testFinish) | |||||
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>FBX Load</title> | <title>FBX Load</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>Frame Fade Plugin</title> | <title>Frame Fade Plugin</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>Fullscreen Plugin</title> | <title>Fullscreen Plugin</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <!DOCTYPE html> | |||||
| <html lang="en"> | |||||
| <head> | |||||
| <meta charset="UTF-8"> | |||||
| <title>Render Target Preview</title> | |||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | |||||
| <!-- Remove this when import maps will be widely supported --> | |||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | |||||
| <script type="importmap"> | |||||
| { | |||||
| "imports": { | |||||
| "threepipe": "./../../dist/index.mjs" | |||||
| } | |||||
| } | |||||
| </script> | |||||
| <style id="example-style"> | |||||
| html, body, #canvas-container, #mcanvas { | |||||
| width: 100%; | |||||
| height: 100%; | |||||
| margin: 0; | |||||
| overflow: hidden; | |||||
| } | |||||
| </style> | |||||
| <script type="module" src="../examples-utils/simple-code-preview.mjs"></script> | |||||
| <script id="example-script" type="module" src="./script.js" data-scripts="./script.ts;./script.js"></script> | |||||
| </head> | |||||
| <body> | |||||
| <div id="canvas-container"> | |||||
| <canvas id="mcanvas"></canvas> | |||||
| </div> | |||||
| </body> |
| import {_testFinish, GeometryUVPreviewPlugin, IObject3D, ThreeViewer} from 'threepipe' | |||||
| const viewer = new ThreeViewer({ | |||||
| canvas: document.getElementById('mcanvas') as HTMLCanvasElement, | |||||
| rgbm: true, | |||||
| }) | |||||
| async function init() { | |||||
| const uvPreview = viewer.addPluginSync(GeometryUVPreviewPlugin) | |||||
| await viewer.setEnvironmentMap('https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr') | |||||
| const result = await viewer.load<IObject3D>('https://threejs.org/examples/models/gltf/IridescentDishWithOlives.glb', { | |||||
| autoCenter: true, | |||||
| autoScale: true, | |||||
| }) | |||||
| const added = false | |||||
| result?.traverse((obj) => { | |||||
| if (obj.geometry && !added) { | |||||
| // added = true | |||||
| uvPreview.addGeometry(obj.geometry, obj.name) | |||||
| } | |||||
| }) | |||||
| // uvPreview.add(()=>depth.target, 'depth', false, true) | |||||
| // uvPreview.add(()=>normal.target, 'normal', false, false) | |||||
| // uvPreview.add(()=>viewer.renderManager.composerTarget, 'composer-1', false, false) | |||||
| // uvPreview.add(()=>viewer.renderManager.composerTarget2, 'composer-2', false, false) | |||||
| } | |||||
| init().then(_testFinish) |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>GLB Export</title> | <title>GLB Export</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>GLTF Animation Page Scroll</title> | <title>GLTF Animation Page Scroll</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>GLTF Animation Plugin</title> | <title>GLTF Animation Plugin</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>GLTF Camera Animation</title> | <title>GLTF Camera Animation</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>GLTF Load</title> | <title>GLTF Load</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>GLTF Transmission Test</title> | <title>GLTF Transmission Test</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>Half float HDR Test</title> | <title>Half float HDR Test</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>HDR Load</title> | <title>HDR Load</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>HDR To EXR</title> | <title>HDR To EXR</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>Image Load</title> | <title>Image Load</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>Image Snapshot Export</title> | <title>Image Snapshot Export</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>Basic Lib Import Test</title> | <title>Basic Lib Import Test</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <li><a href="./hdr-load/">HDR Load </a></li> | <li><a href="./hdr-load/">HDR Load </a></li> | ||||
| <li><a href="./exr-load/">EXR Load </a></li> | <li><a href="./exr-load/">EXR Load </a></li> | ||||
| <li><a href="./image-load/">Image(png, jpeg, svg, ico, webp, avif) Load </a></li> | <li><a href="./image-load/">Image(png, jpeg, svg, ico, webp, avif) Load </a></li> | ||||
| <li><a href="./usdz-load/">USDZ, USDA Load </a></li> | |||||
| <li><a href="./ply-load/">PLY Load </a></li> | <li><a href="./ply-load/">PLY Load </a></li> | ||||
| <li><a href="./stl-load/">STL Load </a></li> | <li><a href="./stl-load/">STL Load </a></li> | ||||
| <li><a href="./ktx2-load/">KTX2 Load </a></li> | <li><a href="./ktx2-load/">KTX2 Load </a></li> | ||||
| <li><a href="./ktx-load/">KTX Load </a></li> | <li><a href="./ktx-load/">KTX Load </a></li> | ||||
| <li><a href="./extra-importer-plugins/">Extra(3ds, 3mf, collada, amf, bvh, vox, gcode, mdd, pcd, tilt, wrl, ldraw, vtk, xyz) Load </a></li> | |||||
| </ul> | </ul> | ||||
| <h2 class="category">Export</h2> | <h2 class="category">Export</h2> | ||||
| <ul> | <ul> | ||||
| <h2 class="category">Animation</h2> | <h2 class="category">Animation</h2> | ||||
| <ul> | <ul> | ||||
| <li><a href="./gltf-animation-plugin/">glTF Animation Plugin </a></li> | <li><a href="./gltf-animation-plugin/">glTF Animation Plugin </a></li> | ||||
| <li><a href="./gltf-animation-plugin/">Popmotion Plugin </a></li> | |||||
| <li><a href="./popmotion-plugin/">Popmotion Plugin </a></li> | |||||
| <li><a href="./gltf-camera-animation/">glTF Camera Animation </a></li> | <li><a href="./gltf-camera-animation/">glTF Camera Animation </a></li> | ||||
| <li><a href="./gltf-animation-page-scroll/">glTF Animation Page Scroll </a></li> | <li><a href="./gltf-animation-page-scroll/">glTF Animation Page Scroll </a></li> | ||||
| </ul> | </ul> | ||||
| <h2 class="category">Utils</h2> | <h2 class="category">Utils</h2> | ||||
| <ul> | <ul> | ||||
| <li><a href="./render-target-preview/">Render Target Preview Plugin </a></li> | <li><a href="./render-target-preview/">Render Target Preview Plugin </a></li> | ||||
| <li><a href="./geometry-uv-preview/">Geometry UV Preview Plugin </a></li> | |||||
| <li><a href="./parallel-asset-import/">Parallel Asset Import </a></li> | <li><a href="./parallel-asset-import/">Parallel Asset Import </a></li> | ||||
| <li><a href="./obj-to-glb/">Convert OBJ to GLB </a></li> | <li><a href="./obj-to-glb/">Convert OBJ to GLB </a></li> | ||||
| <li><a href="./3dm-to-glb/">Convert 3DM to GLB </a></li> | <li><a href="./3dm-to-glb/">Convert 3DM to GLB </a></li> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>KTX Texture Load</title> | <title>KTX Texture Load</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>KTX2 Texture Load</title> | <title>KTX2 Texture Load</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>Material UiConfig</title> | <title>Material UiConfig</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>Depth Buffer Plugin</title> | <title>Depth Buffer Plugin</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>OBJ MTL Load</title> | <title>OBJ MTL Load</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>OBJ To GLB</title> | <title>OBJ To GLB</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>Object UiConfig</title> | <title>Object UiConfig</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>Parallel Asset Import/Download</title> | <title>Parallel Asset Import/Download</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>PLY Load</title> | <title>PLY Load</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>PMAT(Physical) Material export</title> | <title>PMAT(Physical) Material export</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>Popmotion Plugin</title> | <title>Popmotion Plugin</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>Progressive Plugin</title> | <title>Progressive Plugin</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>Image Snapshot Export</title> | <title>Image Snapshot Export</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>Render Target Preview</title> | <title>Render Target Preview</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>Rhino 3DM Load</title> | <title>Rhino 3DM Load</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>Scene UiConfig</title> | <title>Scene UiConfig</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>Half float render pipeline test</title> | <title>Half float render pipeline test</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>MSAA Test</title> | <title>MSAA Test</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>RGBM Render pipeline test</title> | <title>RGBM Render pipeline test</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>STL Load</title> | <title>STL Load</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>Tonemap Plugin</title> | <title>Tonemap Plugin</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>Tweakpane Editor</title> | <title>Tweakpane Editor</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | ||||
| <script type="importmap"> | <script type="importmap"> | ||||
| { | { | ||||
| "imports": { | "imports": { | ||||
| "three": "./../../dist/index.mjs", | |||||
| "threepipe": "./../../dist/index.mjs", | "threepipe": "./../../dist/index.mjs", | ||||
| "@threepipe/plugin-tweakpane": "./../../plugins/tweakpane/dist/index.mjs", | "@threepipe/plugin-tweakpane": "./../../plugins/tweakpane/dist/index.mjs", | ||||
| "@threepipe/plugin-tweakpane-editor": "./../../plugins/tweakpane-editor/dist/index.mjs" | |||||
| "@threepipe/plugin-tweakpane-editor": "./../../plugins/tweakpane-editor/dist/index.mjs", | |||||
| "@threepipe/plugin-extra-importers": "./../../plugins/extra-importers/dist/index.mjs" | |||||
| } | } | ||||
| } | } | ||||
| STLLoadPlugin, | STLLoadPlugin, | ||||
| ThreeViewer, | ThreeViewer, | ||||
| TonemapPlugin, | TonemapPlugin, | ||||
| USDZLoadPlugin, | |||||
| ViewerUiConfigPlugin, | ViewerUiConfigPlugin, | ||||
| } from 'threepipe' | } from 'threepipe' | ||||
| import {TweakpaneUiPlugin} from '@threepipe/plugin-tweakpane' | import {TweakpaneUiPlugin} from '@threepipe/plugin-tweakpane' | ||||
| import {TweakpaneEditorPlugin} from '@threepipe/plugin-tweakpane-editor' | import {TweakpaneEditorPlugin} from '@threepipe/plugin-tweakpane-editor' | ||||
| import {extraImportPlugins} from '@threepipe/plugin-extra-importers' | |||||
| async function init() { | async function init() { | ||||
| new NormalBufferPlugin(HalfFloatType, false), | new NormalBufferPlugin(HalfFloatType, false), | ||||
| new RenderTargetPreviewPlugin(false), | new RenderTargetPreviewPlugin(false), | ||||
| new FrameFadePlugin(), | new FrameFadePlugin(), | ||||
| new KTX2LoadPlugin(), | |||||
| new KTXLoadPlugin(), | |||||
| new PLYLoadPlugin(), | |||||
| new Rhino3dmLoadPlugin(), | |||||
| new STLLoadPlugin(), | |||||
| KTX2LoadPlugin, | |||||
| KTXLoadPlugin, | |||||
| PLYLoadPlugin, | |||||
| Rhino3dmLoadPlugin, | |||||
| STLLoadPlugin, | |||||
| USDZLoadPlugin, | |||||
| ...extraImportPlugins, | |||||
| ]) | ]) | ||||
| const rt = viewer.getOrAddPluginSync(RenderTargetPreviewPlugin) | const rt = viewer.getOrAddPluginSync(RenderTargetPreviewPlugin) |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>Uint8 RGBM HDR Test</title> | <title>Uint8 RGBM HDR Test</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <!DOCTYPE html> | |||||
| <html lang="en"> | |||||
| <head> | |||||
| <meta charset="UTF-8"> | |||||
| <title>USDZ / USDA Load</title> | |||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | |||||
| <!-- Remove this when import maps will be widely supported --> | |||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | |||||
| <script type="importmap"> | |||||
| { | |||||
| "imports": { | |||||
| "threepipe": "./../../dist/index.mjs" | |||||
| } | |||||
| } | |||||
| </script> | |||||
| <style id="example-style"> | |||||
| html, body, #canvas-container, #mcanvas { | |||||
| width: 100%; | |||||
| height: 100%; | |||||
| margin: 0; | |||||
| overflow: hidden; | |||||
| } | |||||
| </style> | |||||
| <script type="module" src="../examples-utils/simple-code-preview.mjs"></script> | |||||
| <script id="example-script" type="module" src="./script.js" data-scripts="./script.ts;./script.js"></script> | |||||
| </head> | |||||
| <body> | |||||
| <div id="canvas-container"> | |||||
| <canvas id="mcanvas"></canvas> | |||||
| </div> | |||||
| </body> |
| import {_testFinish, IObject3D, ThreeViewer, USDZLoadPlugin} from 'threepipe' | |||||
| async function init() { | |||||
| const viewer = new ThreeViewer({ | |||||
| canvas: document.getElementById('mcanvas') as HTMLCanvasElement, | |||||
| msaa: true, | |||||
| dropzone: { | |||||
| allowedExtensions: ['usdz', 'usda', 'hdr', 'exr'], | |||||
| addOptions: { | |||||
| disposeSceneObjects: true, | |||||
| autoSetEnvironment: true, // when hdr is dropped | |||||
| autoSetBackground: true, | |||||
| }, | |||||
| }, | |||||
| }) | |||||
| viewer.addPluginSync(USDZLoadPlugin) | |||||
| const options = { | |||||
| autoCenter: true, | |||||
| autoScale: true, | |||||
| } | |||||
| await Promise.all([ | |||||
| viewer.setEnvironmentMap('https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr'), | |||||
| viewer.load<IObject3D>('https://threejs.org/examples/models/usdz/saeukkang.usdz', options), | |||||
| ]) | |||||
| } | |||||
| init().then(_testFinish) |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>Viewer UiConfig</title> | <title>Viewer UiConfig</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>Z-Prepass test</title> | <title>Z-Prepass test</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> | ||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> |
| { | { | ||||
| "name": "threepipe", | "name": "threepipe", | ||||
| "version": "0.0.12", | |||||
| "version": "0.0.14", | |||||
| "lockfileVersion": 2, | "lockfileVersion": 2, | ||||
| "requires": true, | "requires": true, | ||||
| "packages": { | "packages": { | ||||
| "": { | "": { | ||||
| "name": "threepipe", | "name": "threepipe", | ||||
| "version": "0.0.12", | |||||
| "version": "0.0.14", | |||||
| "license": "Apache-2.0", | "license": "Apache-2.0", | ||||
| "dependencies": { | "dependencies": { | ||||
| "@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1012/package.tgz", | |||||
| "@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1014/package.tgz", | |||||
| "@types/webxr": "^0.5.1", | "@types/webxr": "^0.5.1", | ||||
| "@types/wicg-file-system-access": "^2020.9.5", | "@types/wicg-file-system-access": "^2020.9.5", | ||||
| "ts-browser-helpers": "^0.8.0" | "ts-browser-helpers": "^0.8.0" | ||||
| "dev": true | "dev": true | ||||
| }, | }, | ||||
| "node_modules/@types/three": { | "node_modules/@types/three": { | ||||
| "version": "0.152.1012", | |||||
| "resolved": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1012/package.tgz", | |||||
| "integrity": "sha512-G3Hyma5qGM+Wc1F2dapnIrdNY2uPr33eNYMzaDPbrvHJMHmoZyshrrl9tAodVpND+BVxXSvGiXpfunRGYPOtJg==", | |||||
| "version": "0.152.1014", | |||||
| "resolved": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1014/package.tgz", | |||||
| "integrity": "sha512-1sR9iALwIFtfSXxJshAglvMjLy5litWF2hTbh0JQ+44d+21D2t0nppRZBnWtNQP5XsBYdhCNygnDQNeF6kd+NQ==", | |||||
| "dependencies": { | "dependencies": { | ||||
| "@tweenjs/tween.js": "~18.6.4", | "@tweenjs/tween.js": "~18.6.4", | ||||
| "fflate": "~0.6.9", | "fflate": "~0.6.9", | ||||
| "dev": true | "dev": true | ||||
| }, | }, | ||||
| "@types/three": { | "@types/three": { | ||||
| "version": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1012/package.tgz", | |||||
| "integrity": "sha512-G3Hyma5qGM+Wc1F2dapnIrdNY2uPr33eNYMzaDPbrvHJMHmoZyshrrl9tAodVpND+BVxXSvGiXpfunRGYPOtJg==", | |||||
| "version": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1014/package.tgz", | |||||
| "integrity": "sha512-1sR9iALwIFtfSXxJshAglvMjLy5litWF2hTbh0JQ+44d+21D2t0nppRZBnWtNQP5XsBYdhCNygnDQNeF6kd+NQ==", | |||||
| "requires": { | "requires": { | ||||
| "@tweenjs/tween.js": "~18.6.4", | "@tweenjs/tween.js": "~18.6.4", | ||||
| "fflate": "~0.6.9", | "fflate": "~0.6.9", |
| { | { | ||||
| "name": "threepipe", | "name": "threepipe", | ||||
| "version": "0.0.12", | |||||
| "version": "0.0.13", | |||||
| "description": "A 3D viewer framework built on top of three.js in TypeScript with a focus on quality rendering, modularity and extensibility.", | "description": "A 3D viewer framework built on top of three.js in TypeScript with a focus on quality rendering, modularity and extensibility.", | ||||
| "main": "src/index.ts", | "main": "src/index.ts", | ||||
| "module": "dist/index.mjs", | "module": "dist/index.mjs", | ||||
| "popmotion": "^11.0.5" | "popmotion": "^11.0.5" | ||||
| }, | }, | ||||
| "dependencies": { | "dependencies": { | ||||
| "@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1012/package.tgz", | |||||
| "@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1014/package.tgz", | |||||
| "@types/webxr": "^0.5.1", | "@types/webxr": "^0.5.1", | ||||
| "@types/wicg-file-system-access": "^2020.9.5", | "@types/wicg-file-system-access": "^2020.9.5", | ||||
| "ts-browser-helpers": "^0.8.0" | "ts-browser-helpers": "^0.8.0" | ||||
| "ts-browser-helpers": "^0.8.0", | "ts-browser-helpers": "^0.8.0", | ||||
| "three": "https://github.com/repalash/three.js-modded/releases/download/v0.152.2012/package.tgz", | "three": "https://github.com/repalash/three.js-modded/releases/download/v0.152.2012/package.tgz", | ||||
| "three-f": "https://github.com/repalash/three.js-modded/archive/refs/tags/v0.152.2012.tar.gz", | "three-f": "https://github.com/repalash/three.js-modded/archive/refs/tags/v0.152.2012.tar.gz", | ||||
| "@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1012/package.tgz", | |||||
| "@types/three-f": "https://github.com/repalash/three-ts-types/archive/refs/tags/v0.152.1012.tar.gz", | |||||
| "@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1014/package.tgz", | |||||
| "@types/three-f": "https://github.com/repalash/three-ts-types/archive/refs/tags/v0.152.1014.tar.gz", | |||||
| "@types/three-pkg": "https://gitpkg.now.sh/repalash/three-ts-types/types/three?modded_three" | "@types/three-pkg": "https://gitpkg.now.sh/repalash/three-ts-types/types/three?modded_three" | ||||
| }, | }, | ||||
| "local_dependencies": { | "local_dependencies": { |
| { | |||||
| "name": "@threepipe/plugins-extra-importers", | |||||
| "version": "0.1.0", | |||||
| "lockfileVersion": 2, | |||||
| "requires": true, | |||||
| "packages": { | |||||
| "": { | |||||
| "name": "@threepipe/plugins-extra-importers", | |||||
| "version": "0.1.0", | |||||
| "license": "Apache-2.0", | |||||
| "dependencies": { | |||||
| "threepipe": "file:./../../src/" | |||||
| }, | |||||
| "devDependencies": {} | |||||
| }, | |||||
| "../../src": {}, | |||||
| "../tweakpane/src": { | |||||
| "extraneous": true | |||||
| }, | |||||
| "node_modules/threepipe": { | |||||
| "resolved": "../../src", | |||||
| "link": true | |||||
| } | |||||
| }, | |||||
| "dependencies": { | |||||
| "threepipe": { | |||||
| "version": "file:../../src" | |||||
| } | |||||
| } | |||||
| } |
| { | |||||
| "name": "@threepipe/plugins-extra-importers", | |||||
| "description": "Extra Threepipe plugins for importing several file types.", | |||||
| "version": "0.1.0", | |||||
| "devDependencies": { | |||||
| }, | |||||
| "dependencies": { | |||||
| "threepipe": "file:./../../src/" | |||||
| }, | |||||
| "clean-package": { | |||||
| "remove": [ | |||||
| "clean-package", | |||||
| "scripts", | |||||
| "devDependencies", | |||||
| "//", | |||||
| "markdown-to-html" | |||||
| ], | |||||
| "replace": { | |||||
| "dependencies": { | |||||
| "threepipe": "^0.0.14" | |||||
| } | |||||
| } | |||||
| }, | |||||
| "type": "module", | |||||
| "main": "dist/index.js", | |||||
| "module": "dist/index.mjs", | |||||
| "types": "dist/index.d.ts", | |||||
| "files": [ | |||||
| "dist", | |||||
| "src" | |||||
| ], | |||||
| "scripts": { | |||||
| "new:pack": "npm run prepare && clean-package && npm pack && clean-package restore", | |||||
| "new:publish": "npm run prepare && clean-package && npm publish --access public && clean-package restore", | |||||
| "prepare": "npm run build", | |||||
| "build": "rimraf dist && NODE_ENV=production rollup -c", | |||||
| "dev": "rollup -c -w", | |||||
| "docs": "rimraf docs && npx typedoc" | |||||
| }, | |||||
| "author": "repalash <palash@shaders.app>", | |||||
| "license": "Apache-2.0", | |||||
| "keywords": [ | |||||
| "three", | |||||
| "three.js", | |||||
| "threepipe", | |||||
| "tweakpane", | |||||
| "editor", | |||||
| "plugin" | |||||
| ], | |||||
| "bugs": { | |||||
| "url": "https://github.com/repalash/threepipe/issues" | |||||
| }, | |||||
| "homepage": "https://github.com/repalash/threepipe#readme", | |||||
| "repository": { | |||||
| "type": "git", | |||||
| "url": "git://github.com/repalash/threepipe.git" | |||||
| } | |||||
| } |
| // 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'; | |||||
| import postcss from 'rollup-plugin-postcss' | |||||
| import replace from 'rollup-plugin-replace' | |||||
| import terser from "@rollup/plugin-terser"; | |||||
| const __filename = fileURLToPath(import.meta.url); | |||||
| const __dirname = path.dirname(__filename); | |||||
| const {name, version, author} = packageJson | |||||
| // const {main, module, browser} = packageJson["clean-package"].replace | |||||
| const isProduction = process.env.NODE_ENV === 'production' | |||||
| const settings = { | |||||
| globals: { | |||||
| "threepipe": "threepipe", | |||||
| "three": "threepipe" | |||||
| }, | |||||
| sourcemap: true | |||||
| } | |||||
| export default { | |||||
| input: './src/index.ts', | |||||
| output: [ | |||||
| // { | |||||
| // file: main, | |||||
| // name: main, | |||||
| // ...settings, | |||||
| // format: 'cjs', | |||||
| // plugins: [ | |||||
| // isProduction && terser() | |||||
| // ] | |||||
| // }, | |||||
| { | |||||
| file: './dist/index.mjs', | |||||
| ...settings, | |||||
| name: name, | |||||
| format: 'es', | |||||
| plugins: [ | |||||
| isProduction && terser() | |||||
| ] | |||||
| }, | |||||
| { | |||||
| file: './dist/index.js', | |||||
| ...settings, | |||||
| name: name, | |||||
| format: 'umd', | |||||
| plugins: [ | |||||
| isProduction && terser() | |||||
| ] | |||||
| } | |||||
| ], | |||||
| external: Object.keys(settings.globals), | |||||
| plugins: [ | |||||
| replace({ | |||||
| // If you would like DEV messages, specify 'development' | |||||
| // Otherwise use 'production' | |||||
| 'process.env.NODE_ENV': JSON.stringify('production') // for tippy.js | |||||
| }), | |||||
| postcss({ | |||||
| modules: false, | |||||
| autoModules: true, // todo; issues with typescript import css, because inject is false | |||||
| inject: false, | |||||
| minimize: isProduction, | |||||
| // Or with custom options for `postcss-modules` | |||||
| }), | |||||
| json(), | |||||
| resolve({}), | |||||
| typescript({ | |||||
| }), | |||||
| commonjs({ | |||||
| include: 'node_modules/**', | |||||
| extensions: ['.js'], | |||||
| ignoreGlobal: false, | |||||
| sourceMap: false | |||||
| }), | |||||
| license({ | |||||
| banner: ` | |||||
| @license | |||||
| ${name} v${version} | |||||
| Copyright 2022<%= moment().format('YYYY') > 2022 ? '-' + moment().format('YYYY') : null %> ${author} | |||||
| ${packageJson.license} License | |||||
| `, | |||||
| thirdParty: { | |||||
| output: path.join(__dirname, 'dist', 'dependencies.txt'), | |||||
| includePrivate: true, // Default is false. | |||||
| }, | |||||
| }) | |||||
| ] | |||||
| } |
| declare module '*.txt' { | |||||
| const content: string | |||||
| export default content | |||||
| } | |||||
| declare module '*.glsl' { | |||||
| const content: string | |||||
| export default content | |||||
| } | |||||
| declare module '*.vert' { | |||||
| const content: string | |||||
| export default content | |||||
| } | |||||
| declare module '*.frag' { | |||||
| const content: string | |||||
| export default content | |||||
| } | |||||
| declare module '*.module.scss' { | |||||
| const content: any | |||||
| export default content | |||||
| export const stylesheet: string | |||||
| } | |||||
| declare module '*.module.css' { | |||||
| const content: any | |||||
| export default content | |||||
| export const stylesheet: string | |||||
| } | |||||
| declare module '*.css' { | |||||
| const content: string | |||||
| export default content | |||||
| } | |||||
| // export {} | |||||
| // hack for typedoc | |||||
| // eslint-disable-next-line @typescript-eslint/naming-convention | |||||
| // declare type OffscreenCanvas = HTMLCanvasElement |
| import { | |||||
| AnyOptions, | |||||
| BaseImporterPlugin, | |||||
| BoxGeometry, | |||||
| BufferGeometry, | |||||
| Color, | |||||
| Group, | |||||
| ILoader, | |||||
| Importer, | |||||
| Mesh, | |||||
| Object3D, | |||||
| PhysicalMaterial, | |||||
| Points, | |||||
| PointsMaterial, | |||||
| Scene, | |||||
| SkeletonHelper, | |||||
| } from 'threepipe' | |||||
| import {TDSLoader} from 'three/examples/jsm/loaders/TDSLoader.js' | |||||
| import {ThreeMFLoader} from 'three/examples/jsm/loaders/3MFLoader.js' | |||||
| import {Collada, ColladaLoader} from 'three/examples/jsm/loaders/ColladaLoader.js' | |||||
| import {AMFLoader} from 'three/examples/jsm/loaders/AMFLoader.js' | |||||
| import {GCodeLoader} from 'three/examples/jsm/loaders/GCodeLoader.js' | |||||
| import {BVH, BVHLoader} from 'three/examples/jsm/loaders/BVHLoader.js' | |||||
| import {Chunk, VOXLoader, VOXMesh} from 'three/examples/jsm/loaders/VOXLoader.js' | |||||
| import {MDD, MDDLoader} from 'three/examples/jsm/loaders/MDDLoader.js' | |||||
| import {PCDLoader} from 'three/examples/jsm/loaders/PCDLoader.js' | |||||
| import {TiltLoader} from 'three/examples/jsm/loaders/TiltLoader.js' | |||||
| import {VRMLLoader} from 'three/examples/jsm/loaders/VRMLLoader.js' | |||||
| import {LDrawLoader} from 'three/examples/jsm/loaders/LDrawLoader.js' | |||||
| import {VTKLoader} from 'three/examples/jsm/loaders/VTKLoader.js' | |||||
| import {XYZLoader} from 'three/examples/jsm/loaders/XYZLoader.js' | |||||
| // 3ds | |||||
| /** | |||||
| * Adds support for loading Autodesk 3ds `.3ds`, `application/x-3ds` files and data uris | |||||
| */ | |||||
| export class TDSLoadPlugin extends BaseImporterPlugin { | |||||
| public static readonly PluginType = 'TDSLoadPlugin' | |||||
| protected _importer = new Importer(TDSLoader, ['3ds'], ['image/x-3ds', 'application/x-3ds'], false) | |||||
| } | |||||
| // 3mf | |||||
| /** | |||||
| * Adds support for loading `.3mf`, `model/3mf` files and data uris | |||||
| */ | |||||
| export class ThreeMFLoadPlugin extends BaseImporterPlugin { | |||||
| public static readonly PluginType = 'ThreeMFLoadPlugin' | |||||
| protected _importer = new Importer(ThreeMFLoader, ['3mf'], ['model/3mf'], false) | |||||
| } | |||||
| // collada | |||||
| /** | |||||
| * Adds support for loading Collada `.dae`, `model/vnd.collada+xml` files and data uris | |||||
| */ | |||||
| export class ColladaLoadPlugin extends BaseImporterPlugin { | |||||
| public static readonly PluginType = 'ColladaLoadPlugin' | |||||
| protected _importer = new Importer(class extends ColladaLoader implements ILoader { | |||||
| transform(res: Collada, _: AnyOptions): Scene { | |||||
| res.scene.userData.kinematics = res.kinematics | |||||
| res.scene.userData.library = res.library | |||||
| return res.scene | |||||
| } | |||||
| }, ['dae'], ['model/vnd.collada+xml'], false) | |||||
| } | |||||
| // amf | |||||
| /** | |||||
| * Adds support for loading Additive Manufacturing files `.amf`, `application/amf` files and data uris | |||||
| */ | |||||
| export class AMFLoadPlugin extends BaseImporterPlugin { | |||||
| public static readonly PluginType = 'AMFLoadPlugin' | |||||
| protected _importer = new Importer(AMFLoader, ['amf'], ['application/amf'], false) | |||||
| } | |||||
| // gcode | |||||
| /** | |||||
| * Adds support for loading `.gcode`, `application/gcode` files and data uris | |||||
| */ | |||||
| export class GCodeLoadPlugin extends BaseImporterPlugin { | |||||
| public static readonly PluginType = 'GCodeLoadPlugin' | |||||
| protected _importer = new Importer(GCodeLoader, ['gcode'], ['application/gcode'], false) | |||||
| } | |||||
| // bvh | |||||
| /** | |||||
| * Adds support for loading `.bvh`, `application/bvh` files and data uris | |||||
| */ | |||||
| export class BVHLoadPlugin extends BaseImporterPlugin { | |||||
| public static readonly PluginType = 'BVHLoadPlugin' | |||||
| protected _importer = new Importer(class extends BVHLoader implements ILoader { | |||||
| transform(res: BVH, _: AnyOptions): Object3D { | |||||
| const obj = new Object3D() | |||||
| const helper = new SkeletonHelper(res.skeleton.bones[0]) | |||||
| obj.add(res.skeleton.bones[0]) | |||||
| obj.add(helper) | |||||
| obj.animations = [res.clip] | |||||
| obj.scale.set(0.1, 0.1, 0.1) // todo: autoScale and autoCenter not working | |||||
| return obj | |||||
| } | |||||
| }, ['bvh'], ['application/bvh'], false) | |||||
| } | |||||
| // vox | |||||
| /** | |||||
| * Adds support for loading Magica Voxel `.vox` files and data uris | |||||
| */ | |||||
| export class VOXLoadPlugin extends BaseImporterPlugin { | |||||
| public static readonly PluginType = 'VOXLoadPlugin' | |||||
| protected _importer = new Importer(class extends VOXLoader implements ILoader { | |||||
| transform(chunks: Chunk[], _: AnyOptions): Object3D { | |||||
| const obj = new Object3D() | |||||
| for (const chunk of chunks) { | |||||
| // displayPalette( chunk.palette ); | |||||
| const mesh = new VOXMesh(chunk) | |||||
| mesh.scale.setScalar(0.0015) | |||||
| obj.add(mesh) | |||||
| } | |||||
| return obj | |||||
| } | |||||
| }, ['vox'], [''], false) | |||||
| } | |||||
| // mdd | |||||
| /** | |||||
| * Adds support for loading animation `.mdd`, `application/mdd` files and data uris | |||||
| */ | |||||
| export class MDDLoadPlugin extends BaseImporterPlugin { | |||||
| public static readonly PluginType = 'MDDLoadPlugin' | |||||
| protected _importer = new Importer(class extends MDDLoader implements ILoader { | |||||
| transform(res: MDD, _: AnyOptions): Object3D { | |||||
| const morphTargets = res.morphTargets | |||||
| const geometry = new BoxGeometry() | |||||
| geometry.morphAttributes.position = morphTargets // apply morph targets | |||||
| const mesh = new Mesh(geometry, new PhysicalMaterial()) | |||||
| const obj = new Object3D() | |||||
| obj.add(mesh) | |||||
| res.clip.tracks.forEach(track=> track.name = mesh.uuid + track.name) | |||||
| obj.animations = [res.clip] | |||||
| return obj | |||||
| } | |||||
| }, ['mdd'], ['application/mdd'], false) | |||||
| } | |||||
| // pcd | |||||
| /** | |||||
| * Adds support for loading Point cloud data `.pcd`, `application/pcd` files and data uris | |||||
| */ | |||||
| export class PCDLoadPlugin extends BaseImporterPlugin { | |||||
| public static readonly PluginType = 'PCDLoadPlugin' | |||||
| protected _importer = new Importer(class extends PCDLoader implements ILoader { | |||||
| transform(points: Points, options: AnyOptions): any { | |||||
| if (options.autoCenter) points.geometry.center() | |||||
| points.geometry.rotateX(Math.PI) | |||||
| return points | |||||
| } | |||||
| }, ['pcd'], ['application/pcd'], false) | |||||
| } | |||||
| // tilt | |||||
| /** | |||||
| * Adds support for loading Tilt brush `.tilt`, `application/tilt` files and data uris | |||||
| */ | |||||
| export class TiltLoadPlugin extends BaseImporterPlugin { | |||||
| public static readonly PluginType = 'TiltLoadPlugin' | |||||
| protected _importer = new Importer(TiltLoader, ['tilt'], ['application/tilt'], false) | |||||
| } | |||||
| // vrml | |||||
| /** | |||||
| * Adds support for loading VRML `.wrl`, `model/vrml` files and data uris | |||||
| */ | |||||
| export class VRMLLoadPlugin extends BaseImporterPlugin { | |||||
| public static readonly PluginType = 'VRMLLoadPlugin' | |||||
| protected _importer = new Importer(VRMLLoader, ['wrl'], ['model/vrml'], false) | |||||
| } | |||||
| // ldraw | |||||
| /** | |||||
| * Adds support for loading LDraw `.mpd`, `application/mpd` files and data uris. see https://ldraw.org | |||||
| */ | |||||
| export class LDrawLoadPlugin extends BaseImporterPlugin { | |||||
| public static readonly PluginType = 'LDrawLoadPlugin' | |||||
| protected _importer = new Importer(class extends LDrawLoader implements ILoader { | |||||
| transform(res: Group, _: AnyOptions): any { | |||||
| // Convert from LDraw coordinates: rotate 180 degrees around OX | |||||
| res.rotation.x = Math.PI | |||||
| return res | |||||
| } | |||||
| }, ['mpd'], ['application/ldraw'], false) | |||||
| } | |||||
| // vtk | |||||
| /** | |||||
| * Adds support for loading VTK `.vtk`, '.vtp', `application/vtk` files and data uris | |||||
| **/ | |||||
| export class VTKLoadPlugin extends BaseImporterPlugin { | |||||
| public static readonly PluginType = 'VTKLoadPlugin' | |||||
| protected _importer = new Importer(class extends VTKLoader implements ILoader { | |||||
| transform(res: BufferGeometry, _: AnyOptions): Mesh|undefined { | |||||
| if (!res.attributes?.normal) res.computeVertexNormals() | |||||
| // todo set mesh name from options/path | |||||
| return res ? new Mesh(res, new PhysicalMaterial({ | |||||
| color: new Color(1, 1, 1), | |||||
| vertexColors: res.hasAttribute('color'), | |||||
| })) : undefined | |||||
| } | |||||
| }, ['vtk', 'vtp'], ['application/vtk'], false) | |||||
| } | |||||
| // xyz | |||||
| /** | |||||
| * Adds support for loading XYZ `.xyz`, `text/plain+xyz` files and data uris | |||||
| */ | |||||
| export class XYZLoadPlugin extends BaseImporterPlugin { | |||||
| public static readonly PluginType = 'XYZLoadPlugin' | |||||
| protected _importer = new Importer(class extends XYZLoader implements ILoader { | |||||
| transform(res: BufferGeometry, options: AnyOptions): Points|undefined { | |||||
| if (!res.attributes?.normal) res.computeVertexNormals() | |||||
| if (options.autoCenter) res.center() | |||||
| return res ? new Points(res, new PointsMaterial({ | |||||
| size: 0.1, | |||||
| vertexColors: res.hasAttribute('color'), | |||||
| })) : undefined | |||||
| } | |||||
| }, ['xyz'], ['text/plain+xyz'], false) | |||||
| } | |||||
| export const extraImportPlugins = [ | |||||
| TDSLoadPlugin, | |||||
| ThreeMFLoadPlugin, | |||||
| ColladaLoadPlugin, | |||||
| AMFLoadPlugin, | |||||
| GCodeLoadPlugin, | |||||
| BVHLoadPlugin, | |||||
| VOXLoadPlugin, | |||||
| MDDLoadPlugin, | |||||
| PCDLoadPlugin, | |||||
| TiltLoadPlugin, | |||||
| VRMLLoadPlugin, | |||||
| LDrawLoadPlugin, | |||||
| VTKLoadPlugin, | |||||
| XYZLoadPlugin, | |||||
| ] as const |
| { | |||||
| "compilerOptions": { | |||||
| "baseUrl": "./src", | |||||
| "rootDir": "./src", | |||||
| "allowJs": false, | |||||
| "checkJs": false, | |||||
| "skipLibCheck": true, | |||||
| "allowSyntheticDefaultImports": true, | |||||
| "experimentalDecorators": true, | |||||
| "isolatedModules": true, | |||||
| "module": "es2020", | |||||
| "noImplicitAny": true, | |||||
| "declaration": true, | |||||
| "declarationMap": true, | |||||
| "declarationDir": "dist", | |||||
| "outDir": "dist", | |||||
| "noImplicitThis": true, | |||||
| "noUnusedLocals": true, | |||||
| "noUnusedParameters": true, | |||||
| "removeComments": false, | |||||
| "preserveConstEnums": true, | |||||
| "moduleResolution": "node", | |||||
| "emitDecoratorMetadata": false, | |||||
| "sourceMap": true, | |||||
| "target": "ES2020", | |||||
| "strictNullChecks": true, | |||||
| "lib": [ | |||||
| "es2020", | |||||
| "esnext", | |||||
| "dom" | |||||
| ] | |||||
| }, | |||||
| "include": [ | |||||
| "src/**/*" | |||||
| ], | |||||
| "exclude": [ | |||||
| "node_modules", | |||||
| "**/*.spec.ts", | |||||
| "dist" | |||||
| ] | |||||
| } |
| { | |||||
| "extends": [ | |||||
| "../../typedoc.json" | |||||
| ], | |||||
| "entryPoints": [ | |||||
| "src/index.ts" | |||||
| ], | |||||
| "name": "Threepipe Extra Importer Plugins", | |||||
| "readme": "none" | |||||
| } |
| { | |||||
| "name": "threepipe-plugin-template-rollup", | |||||
| "version": "0.0.1", | |||||
| "lockfileVersion": 2, | |||||
| "requires": true, | |||||
| "packages": { | |||||
| "": { | |||||
| "name": "threepipe-plugin-template-rollup", | |||||
| "version": "0.0.1", | |||||
| "license": "Apache-2.0", | |||||
| "dependencies": { | |||||
| "@threepipe/plugin-tweakpane": "file:./../tweakpane/src/", | |||||
| "threepipe": "file:./../../src/" | |||||
| }, | |||||
| "devDependencies": {} | |||||
| }, | |||||
| "../../src": {}, | |||||
| "../tweakpane/src": {}, | |||||
| "node_modules/@threepipe/plugin-tweakpane": { | |||||
| "resolved": "../tweakpane/src", | |||||
| "link": true | |||||
| }, | |||||
| "node_modules/threepipe": { | |||||
| "resolved": "../../src", | |||||
| "link": true | |||||
| } | |||||
| }, | |||||
| "dependencies": { | |||||
| "@threepipe/plugin-tweakpane": { | |||||
| "version": "file:../tweakpane/src" | |||||
| }, | |||||
| "threepipe": { | |||||
| "version": "file:../../src" | |||||
| } | |||||
| } | |||||
| } |
| { | |||||
| "name": "threepipe-plugin-template-rollup", | |||||
| "description": "Sample Threepipe plugin using rollup", | |||||
| "version": "0.1.0", | |||||
| "devDependencies": { | |||||
| }, | |||||
| "dependencies": { | |||||
| "threepipe": "file:./../../src/", | |||||
| "@threepipe/plugin-tweakpane": "file:./../tweakpane/src/" | |||||
| }, | |||||
| "clean-package": { | |||||
| "remove": [ | |||||
| "clean-package", | |||||
| "scripts", | |||||
| "devDependencies", | |||||
| "//", | |||||
| "markdown-to-html" | |||||
| ], | |||||
| "replace": { | |||||
| "dependencies": { | |||||
| "threepipe": "^0.0.8", | |||||
| "@threepipe/plugin-tweakpane": "^0.1.2" | |||||
| } | |||||
| } | |||||
| }, | |||||
| "type": "module", | |||||
| "main": "dist/index.js", | |||||
| "module": "dist/index.mjs", | |||||
| "types": "dist/index.d.ts", | |||||
| "files": [ | |||||
| "dist", | |||||
| "src" | |||||
| ], | |||||
| "scripts": { | |||||
| "new:pack": "npm run prepare && clean-package && npm pack && clean-package restore", | |||||
| "new:publish": "npm run prepare && clean-package && npm publish --access public && clean-package restore", | |||||
| "prepare": "npm run build", | |||||
| "build": "rimraf dist && NODE_ENV=production rollup -c", | |||||
| "dev": "rollup -c -w", | |||||
| "docs": "rimraf docs && npx typedoc" | |||||
| }, | |||||
| "author": "repalash <palash@shaders.app>", | |||||
| "license": "Apache-2.0", | |||||
| "keywords": [ | |||||
| "three", | |||||
| "three.js", | |||||
| "threepipe", | |||||
| "tweakpane", | |||||
| "editor", | |||||
| "plugin" | |||||
| ], | |||||
| "bugs": { | |||||
| "url": "https://github.com/repalash/threepipe/issues" | |||||
| }, | |||||
| "homepage": "https://github.com/repalash/threepipe#readme", | |||||
| "repository": { | |||||
| "type": "git", | |||||
| "url": "git://github.com/repalash/threepipe.git" | |||||
| } | |||||
| } |
| // 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'; | |||||
| import postcss from 'rollup-plugin-postcss' | |||||
| import replace from 'rollup-plugin-replace' | |||||
| import terser from "@rollup/plugin-terser"; | |||||
| const __filename = fileURLToPath(import.meta.url); | |||||
| const __dirname = path.dirname(__filename); | |||||
| const {name, version, author} = packageJson | |||||
| // const {main, module, browser} = packageJson["clean-package"].replace | |||||
| const isProduction = process.env.NODE_ENV === 'production' | |||||
| const settings = { | |||||
| globals: { | |||||
| "threepipe": "threepipe", | |||||
| "@threepipe/plugin-tweakpane": "@threepipe/plugin-tweakpane" | |||||
| }, | |||||
| sourcemap: true | |||||
| } | |||||
| export default { | |||||
| input: './src/index.ts', | |||||
| output: [ | |||||
| // { | |||||
| // file: main, | |||||
| // name: main, | |||||
| // ...settings, | |||||
| // format: 'cjs', | |||||
| // plugins: [ | |||||
| // isProduction && terser() | |||||
| // ] | |||||
| // }, | |||||
| { | |||||
| file: './dist/index.mjs', | |||||
| ...settings, | |||||
| name: name, | |||||
| format: 'es', | |||||
| plugins: [ | |||||
| isProduction && terser() | |||||
| ] | |||||
| }, | |||||
| { | |||||
| file: './dist/index.js', | |||||
| ...settings, | |||||
| name: name, | |||||
| format: 'umd', | |||||
| plugins: [ | |||||
| isProduction && terser() | |||||
| ] | |||||
| } | |||||
| ], | |||||
| external: Object.keys(settings.globals), | |||||
| plugins: [ | |||||
| replace({ | |||||
| // If you would like DEV messages, specify 'development' | |||||
| // Otherwise use 'production' | |||||
| 'process.env.NODE_ENV': JSON.stringify('production') // for tippy.js | |||||
| }), | |||||
| postcss({ | |||||
| modules: false, | |||||
| autoModules: true, // todo; issues with typescript import css, because inject is false | |||||
| inject: false, | |||||
| minimize: isProduction, | |||||
| // Or with custom options for `postcss-modules` | |||||
| }), | |||||
| json(), | |||||
| resolve({}), | |||||
| typescript({ | |||||
| }), | |||||
| commonjs({ | |||||
| include: 'node_modules/**', | |||||
| extensions: ['.js'], | |||||
| ignoreGlobal: false, | |||||
| sourceMap: false | |||||
| }), | |||||
| license({ | |||||
| banner: ` | |||||
| @license | |||||
| ${name} v${version} | |||||
| Copyright 2022<%= moment().format('YYYY') > 2022 ? '-' + moment().format('YYYY') : null %> ${author} | |||||
| ${packageJson.license} License | |||||
| `, | |||||
| thirdParty: { | |||||
| output: path.join(__dirname, 'dist', 'dependencies.txt'), | |||||
| includePrivate: true, // Default is false. | |||||
| }, | |||||
| }) | |||||
| ] | |||||
| } |
| html{ | |||||
| } |
| import {AViewerPluginSync, createStyles, ThreeViewer,} from 'threepipe' | |||||
| import {TweakpaneUiPlugin} from '@threepipe/plugin-tweakpane' | |||||
| import styles from './SamplePlugin.css' | |||||
| console.log(TweakpaneUiPlugin) | |||||
| export class SamplePlugin extends AViewerPluginSync<string> { | |||||
| public static readonly PluginType: string = 'SamplePlugin' | |||||
| enabled = true | |||||
| dependencies = [] | |||||
| constructor() { | |||||
| super() | |||||
| } | |||||
| onAdded(viewer: ThreeViewer) { | |||||
| super.onAdded(viewer) | |||||
| createStyles(styles) | |||||
| } | |||||
| } |
| declare module '*.txt' { | |||||
| const content: string | |||||
| export default content | |||||
| } | |||||
| declare module '*.glsl' { | |||||
| const content: string | |||||
| export default content | |||||
| } | |||||
| declare module '*.vert' { | |||||
| const content: string | |||||
| export default content | |||||
| } | |||||
| declare module '*.frag' { | |||||
| const content: string | |||||
| export default content | |||||
| } | |||||
| declare module '*.module.scss' { | |||||
| const content: any | |||||
| export default content | |||||
| export const stylesheet: string | |||||
| } | |||||
| declare module '*.module.css' { | |||||
| const content: any | |||||
| export default content | |||||
| export const stylesheet: string | |||||
| } | |||||
| declare module '*.css' { | |||||
| const content: string | |||||
| export default content | |||||
| } | |||||
| // export {} | |||||
| // hack for typedoc | |||||
| // eslint-disable-next-line @typescript-eslint/naming-convention | |||||
| // declare type OffscreenCanvas = HTMLCanvasElement |
| export {SamplePlugin} from './SamplePlugin' |
| { | |||||
| "compilerOptions": { | |||||
| "baseUrl": "./src", | |||||
| "rootDir": "./src", | |||||
| "allowJs": false, | |||||
| "checkJs": false, | |||||
| "skipLibCheck": true, | |||||
| "allowSyntheticDefaultImports": true, | |||||
| "experimentalDecorators": true, | |||||
| "isolatedModules": true, | |||||
| "module": "es2020", | |||||
| "noImplicitAny": true, | |||||
| "declaration": true, | |||||
| "declarationMap": true, | |||||
| "declarationDir": "dist", | |||||
| "outDir": "dist", | |||||
| "noImplicitThis": true, | |||||
| "noUnusedLocals": true, | |||||
| "noUnusedParameters": true, | |||||
| "removeComments": false, | |||||
| "preserveConstEnums": true, | |||||
| "moduleResolution": "node", | |||||
| "emitDecoratorMetadata": false, | |||||
| "sourceMap": true, | |||||
| "target": "ES2020", | |||||
| "strictNullChecks": true, | |||||
| "lib": [ | |||||
| "es2020", | |||||
| "esnext", | |||||
| "dom" | |||||
| ] | |||||
| }, | |||||
| "include": [ | |||||
| "src/**/*" | |||||
| ], | |||||
| "exclude": [ | |||||
| "node_modules", | |||||
| "**/*.spec.ts", | |||||
| "dist" | |||||
| ] | |||||
| } |
| { | |||||
| "extends": [ | |||||
| "../../typedoc.json" | |||||
| ], | |||||
| "entryPoints": [ | |||||
| "src/index.ts" | |||||
| ], | |||||
| "name": "Threepipe Tweakpane Editor Plugin", | |||||
| "readme": "none" | |||||
| } |
| import { | import { | ||||
| CustomContextMenu, | CustomContextMenu, | ||||
| DataTexture, | |||||
| EXRExporter2, | EXRExporter2, | ||||
| FloatType, | FloatType, | ||||
| generateUUID, | generateUUID, | ||||
| } from 'threepipe' | } from 'threepipe' | ||||
| import type {UiObjectConfig} from 'uiconfig.js' | import type {UiObjectConfig} from 'uiconfig.js' | ||||
| import {TweakpaneUiPlugin} from './TweakpaneUiPlugin' | import {TweakpaneUiPlugin} from './TweakpaneUiPlugin' | ||||
| import {DataTexture} from 'three' | |||||
| const staticData = { | const staticData = { | ||||
| placeholderVal: 'placeholder', | placeholderVal: 'placeholder', | ||||
| // } | // } | ||||
| if (cc.isTexture) { | if (cc.isTexture) { | ||||
| // console.warn('here') | // console.warn('here') | ||||
| // todo: use textureToCanvas for data texture | |||||
| if (cc.image && !cc.image.tp_src) { | if (cc.image && !cc.image.tp_src) { | ||||
| if (cc.image instanceof ImageBitmap || cc.image instanceof HTMLImageElement || cc.image instanceof HTMLVideoElement) { // todo: support playback in video | if (cc.image instanceof ImageBitmap || cc.image instanceof HTMLImageElement || cc.image instanceof HTMLVideoElement) { // todo: support playback in video | ||||
| cc.image.tp_src = imageBitmapToBase64(cc.image, 160) | cc.image.tp_src = imageBitmapToBase64(cc.image, 160) | ||||
| // data texture | // data texture | ||||
| if (!src && tex.isDataTexture) { | if (!src && tex.isDataTexture) { | ||||
| if (tex.type !== HalfFloatType && tex.type !== FloatType) { | if (tex.type !== HalfFloatType && tex.type !== FloatType) { | ||||
| // todo: use textureToCanvas for data texture | |||||
| console.error('Only Float and HalfFloat Data texture export is supported', vcv, tex, config) | console.error('Only Float and HalfFloat Data texture export is supported', vcv, tex, config) | ||||
| return | return | ||||
| } | } |
| const pluginDir = path.join(pluginsDir, pluginFolder) | const pluginDir = path.join(pluginsDir, pluginFolder) | ||||
| const packageJsonPath = path.join(pluginDir, 'package.json') | const packageJsonPath = path.join(pluginDir, 'package.json') | ||||
| if (!fs.existsSync(packageJsonPath)) continue; | if (!fs.existsSync(packageJsonPath)) continue; | ||||
| callback(pluginDir) | |||||
| callback(pluginDir, pluginFolder) | |||||
| } | } | ||||
| } | } | ||||
| export function execEachPlugin(command){ | |||||
| loopPluginDirs((pluginDir) => { | |||||
| export function execEachPlugin(command, templates = false){ | |||||
| loopPluginDirs((pluginDir, pluginFolder) => { | |||||
| if(!templates && pluginFolder.startsWith('plugin-template-')) return; | |||||
| console.log(`Executing ${command} in ${pluginDir}`) | console.log(`Executing ${command} in ${pluginDir}`) | ||||
| execSync(command, {cwd: pluginDir, stdio: 'inherit'}) | execSync(command, {cwd: pluginDir, stdio: 'inherit'}) | ||||
| }) | }) |
| * @category Asset Manager | * @category Asset Manager | ||||
| */ | */ | ||||
| export class AssetManager extends EventDispatcher<BaseEvent&{data: ImportResult}, 'loadAsset'> { | export class AssetManager extends EventDispatcher<BaseEvent&{data: ImportResult}, 'loadAsset'> { | ||||
| static readonly PluginType = 'AssetManager' | |||||
| readonly viewer: ThreeViewer | readonly viewer: ThreeViewer | ||||
| readonly importer: AssetImporter | readonly importer: AssetImporter | ||||
| readonly exporter: AssetExporter | readonly exporter: AssetExporter | ||||
| return this.viewer?.loadConfigResources(json, extraResources) | return this.viewer?.loadConfigResources(json, extraResources) | ||||
| } | } | ||||
| /** | |||||
| * @deprecated not a plugin anymore | |||||
| */ | |||||
| static readonly PluginType = 'AssetManager' | |||||
| // endregion | // endregion | ||||
| } | } |
| rgbm?: boolean, | rgbm?: boolean, | ||||
| msaa?: boolean, | msaa?: boolean, | ||||
| depthBuffer?: boolean, | depthBuffer?: boolean, | ||||
| renderScale?: number, | |||||
| } | } | ||||
| export interface IWebGLRenderer<TManager extends IRenderManager=IRenderManager> extends WebGLRenderer { | export interface IWebGLRenderer<TManager extends IRenderManager=IRenderManager> extends WebGLRenderer { |
| // region deprecated | // region deprecated | ||||
| /** | /** | ||||
| * @deprecated use {@link IObject3D.getObjectByName} instead | |||||
| @deprecated use {@link getObjectByName} instead | |||||
| * @param name | * @param name | ||||
| * @param parent | * @param parent | ||||
| */ | */ |
| readonly modelRoot: IObject3D | readonly modelRoot: IObject3D | ||||
| @uiColor<RootScene>('Background Color', (s)=>({ | @uiColor<RootScene>('Background Color', (s)=>({ | ||||
| onChange: ()=>s?._onBackgroundChange(), | |||||
| onChange: ()=>s?.onBackgroundChange(), | |||||
| })) | })) | ||||
| @serialize() @onChange2(RootScene.prototype._onBackgroundChange) | |||||
| @serialize() @onChange2(RootScene.prototype.onBackgroundChange) | |||||
| backgroundColor: Color | null = null // read in three.js WebGLBackground | backgroundColor: Color | null = null // read in three.js WebGLBackground | ||||
| @onChange2(RootScene.prototype._onBackgroundChange) | |||||
| @onChange2(RootScene.prototype.onBackgroundChange) | |||||
| @serialize() @uiImage('Background Image') | @serialize() @uiImage('Background Image') | ||||
| background: null | Color | ITexture | 'environment' = null | background: null | Color | ITexture | 'environment' = null | ||||
| /** | /** | ||||
| this.refreshUi?.() | this.refreshUi?.() | ||||
| } | } | ||||
| private _onBackgroundChange() { | |||||
| onBackgroundChange() { | |||||
| this.dispatchEvent({type: 'backgroundChanged', background: this.background, backgroundColor: this.backgroundColor}) | this.dispatchEvent({type: 'backgroundChanged', background: this.background, backgroundColor: this.backgroundColor}) | ||||
| this.setDirty({refreshScene: true, geometryChanged: false}) | this.setDirty({refreshScene: true, geometryChanged: false}) | ||||
| this.refreshUi?.() | this.refreshUi?.() | ||||
| return | return | ||||
| } | } | ||||
| /** | |||||
| * Find objects by name exact match in the complete hierarchy. | |||||
| * @param name - name | |||||
| * @param parent - optional root node to start search from | |||||
| * @returns Array of found objects | |||||
| */ | |||||
| public findObjectsByName(name: string, parent?: IObject3D): IObject3D[] { | |||||
| const o: IObject3D[] = []; | |||||
| (parent ?? this).traverse(object => { | |||||
| if (object.name === name) o.push(object) | |||||
| }) | |||||
| return o | |||||
| } | |||||
| /** | /** | ||||
| * Returns the bounding box of the scene model root. | * Returns the bounding box of the scene model root. | ||||
| * @param precise | * @param precise | ||||
| return this | return this | ||||
| } | } | ||||
| /** | |||||
| * @deprecated | |||||
| * Sets the camera pointing towards the object at a specific distance. | |||||
| * @param rootObject - The object to point at. | |||||
| * @param centerOffset - The distance offset from the object to point at. | |||||
| * @param targetOffset - The distance offset for the target from the center of object to point at. | |||||
| * @param options - Not used yet. | |||||
| */ | |||||
| resetCamera(rootObject:Object3D|undefined = undefined, centerOffset = new Vector3(1, 1, 1), targetOffset = new Vector3(0, 0, 0)): void { | |||||
| if (this._mainCamera) { | |||||
| this.matrixWorldNeedsUpdate = true | |||||
| this.updateMatrixWorld(true) | |||||
| const bounds = rootObject ? new Box3B().expandByObject(rootObject, true, true) : this.getBounds(true) | |||||
| const center = bounds.getCenter(new Vector3()) | |||||
| const radius = bounds.getSize(new Vector3()).length() * 0.5 | |||||
| center.add(targetOffset.clone().multiplyScalar(radius)) | |||||
| this._mainCamera.position = new Vector3( // todo: for nested cameras? | |||||
| center.x + centerOffset.x * radius, | |||||
| center.y + centerOffset.y * radius, | |||||
| center.z + centerOffset.z * radius, | |||||
| ) | |||||
| this._mainCamera.target = center | |||||
| // this.scene.mainCamera.controls?.targetOffset.set(0, 0, 0) | |||||
| this.setDirty() | |||||
| } | |||||
| } | |||||
| /** | /** | ||||
| * Serialize the scene properties | * Serialize the scene properties | ||||
| * @param meta | * @param meta | ||||
| super.addEventListener(type, listener) | super.addEventListener(type, listener) | ||||
| } | } | ||||
| /** | |||||
| * Minimum Camera near plane | |||||
| * @deprecated - use camera.userData.minNearPlane instead | |||||
| */ | |||||
| get minNearDistance(): number { | |||||
| console.error('minNearDistance is deprecated. Use camera.userData.minNearPlane instead') | |||||
| return this.mainCamera.userData.minNearPlane ?? 0.02 | |||||
| } | |||||
| /** | |||||
| * @deprecated - use camera.userData.minNearPlane instead | |||||
| */ | |||||
| set minNearDistance(value: number) { | |||||
| console.error('minNearDistance is deprecated. Use camera.userData.minNearPlane instead') | |||||
| if (this.mainCamera) | |||||
| this.mainCamera.userData.minNearPlane = value | |||||
| } | |||||
| /** | |||||
| * @deprecated | |||||
| */ | |||||
| get activeCamera(): ICamera { | |||||
| console.error('activeCamera is deprecated. Use mainCamera instead.') | |||||
| return this.mainCamera | |||||
| } | |||||
| /** | |||||
| * @deprecated | |||||
| */ | |||||
| set activeCamera(camera: ICamera | undefined) { | |||||
| console.error('activeCamera is deprecated. Use mainCamera instead.') | |||||
| this.mainCamera = camera | |||||
| } | |||||
| /** | |||||
| * Get the threejs scene object | |||||
| * @deprecated | |||||
| */ | |||||
| get modelObject(): this { | |||||
| return this as any | |||||
| } | |||||
| // region inherited type fixes | // region inherited type fixes | ||||
| // re-declaring from IObject3D because: https://github.com/microsoft/TypeScript/issues/16936 | // re-declaring from IObject3D because: https://github.com/microsoft/TypeScript/issues/16936 | ||||
| // } | // } | ||||
| /** | |||||
| * Find objects by name exact match in the complete hierarchy. | |||||
| * @deprecated Use {@link getObjectByName} instead. | |||||
| * @param name - name | |||||
| * @param parent - optional root node to start search from | |||||
| * @returns Array of found objects | |||||
| */ | |||||
| public findObjectsByName(name: string, parent?: IObject3D): IObject3D[] { | |||||
| const o: IObject3D[] = []; | |||||
| (parent ?? this).traverse(object => { | |||||
| if (object.name === name) o.push(object) | |||||
| }) | |||||
| return o | |||||
| } | |||||
| /** | |||||
| * @deprecated | |||||
| * Sets the camera pointing towards the object at a specific distance. | |||||
| * @param rootObject - The object to point at. | |||||
| * @param centerOffset - The distance offset from the object to point at. | |||||
| * @param targetOffset - The distance offset for the target from the center of object to point at. | |||||
| * @param options - Not used yet. | |||||
| */ | |||||
| resetCamera(rootObject:Object3D|undefined = undefined, centerOffset = new Vector3(1, 1, 1), targetOffset = new Vector3(0, 0, 0)): void { | |||||
| if (this._mainCamera) { | |||||
| this.matrixWorldNeedsUpdate = true | |||||
| this.updateMatrixWorld(true) | |||||
| const bounds = rootObject ? new Box3B().expandByObject(rootObject, true, true) : this.getBounds(true) | |||||
| const center = bounds.getCenter(new Vector3()) | |||||
| const radius = bounds.getSize(new Vector3()).length() * 0.5 | |||||
| center.add(targetOffset.clone().multiplyScalar(radius)) | |||||
| this._mainCamera.position = new Vector3( // todo: for nested cameras? | |||||
| center.x + centerOffset.x * radius, | |||||
| center.y + centerOffset.y * radius, | |||||
| center.z + centerOffset.z * radius, | |||||
| ) | |||||
| this._mainCamera.target = center | |||||
| // this.scene.mainCamera.controls?.targetOffset.set(0, 0, 0) | |||||
| this.setDirty() | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Minimum Camera near plane | |||||
| * @deprecated - use camera.userData.minNearPlane instead | |||||
| */ | |||||
| get minNearDistance(): number { | |||||
| console.error('minNearDistance is deprecated. Use camera.userData.minNearPlane instead') | |||||
| return this.mainCamera.userData.minNearPlane ?? 0.02 | |||||
| } | |||||
| /** | |||||
| * @deprecated - use camera.userData.minNearPlane instead | |||||
| */ | |||||
| set minNearDistance(value: number) { | |||||
| console.error('minNearDistance is deprecated. Use camera.userData.minNearPlane instead') | |||||
| if (this.mainCamera) | |||||
| this.mainCamera.userData.minNearPlane = value | |||||
| } | |||||
| /** | |||||
| * @deprecated | |||||
| */ | |||||
| get activeCamera(): ICamera { | |||||
| console.error('activeCamera is deprecated. Use mainCamera instead.') | |||||
| return this.mainCamera | |||||
| } | |||||
| /** | |||||
| * @deprecated | |||||
| */ | |||||
| set activeCamera(camera: ICamera | undefined) { | |||||
| console.error('activeCamera is deprecated. Use mainCamera instead.') | |||||
| this.mainCamera = camera | |||||
| } | |||||
| /** | |||||
| * Get the threejs scene object | |||||
| * @deprecated | |||||
| */ | |||||
| get modelObject(): this { | |||||
| return this as any | |||||
| } | |||||
| /** | |||||
| * @deprecated use {@link envMapIntensity} instead | |||||
| */ | |||||
| get environmentIntensity(): number { | |||||
| return this.envMapIntensity | |||||
| } | |||||
| /** | |||||
| * @deprecated use {@link envMapIntensity} instead | |||||
| */ | |||||
| set environmentIntensity(value: number) { | |||||
| this.envMapIntensity = value | |||||
| } | |||||
| /** | /** | ||||
| * Add any processed scene object to the scene. | * Add any processed scene object to the scene. | ||||
| * @deprecated renamed to {@link addObject} | * @deprecated renamed to {@link addObject} |
| import {IViewerPluginSync, ThreeViewer} from '../../viewer' | |||||
| import {Importer} from '../../assetmanager' | |||||
| export abstract class BaseImporterPlugin implements IViewerPluginSync { | |||||
| declare ['constructor']: typeof BaseImporterPlugin | |||||
| public static readonly PluginType: string | |||||
| protected abstract _importer: Importer | |||||
| toJSON: any = null // disable serialization | |||||
| onAdded(viewer: ThreeViewer) { | |||||
| viewer.assetManager.importer.addImporter(this._importer) | |||||
| } | |||||
| onRemove(viewer: ThreeViewer) { | |||||
| viewer.assetManager.importer.removeImporter(this._importer) | |||||
| } | |||||
| dispose() { | |||||
| return | |||||
| } | |||||
| } |
| import {IViewerPluginSync, ThreeViewer} from '../../viewer' | |||||
| import {ThreeViewer} from '../../viewer' | |||||
| import {GLTFWriter2, ILoader, Importer, ImportResultExtras} from '../../assetmanager' | import {GLTFWriter2, ILoader, Importer, ImportResultExtras} from '../../assetmanager' | ||||
| import {KTX2Loader} from 'three/examples/jsm/loaders/KTX2Loader.js' | import {KTX2Loader} from 'three/examples/jsm/loaders/KTX2Loader.js' | ||||
| import {CompressedTexture} from 'three' | import {CompressedTexture} from 'three' | ||||
| import {serializeTextureInExtras} from '../../utils' | import {serializeTextureInExtras} from '../../utils' | ||||
| import {ITexture} from '../../core' | import {ITexture} from '../../core' | ||||
| import {BaseImporterPlugin} from '../base/BaseImporterPlugin' | |||||
| /** | /** | ||||
| * Adds support for loading Compressed Textures of format `.ktx2`, `image/ktx2` files and data uris. | * Adds support for loading Compressed Textures of format `.ktx2`, `image/ktx2` files and data uris. | ||||
| * @category Plugins | * @category Plugins | ||||
| */ | */ | ||||
| export class KTX2LoadPlugin implements IViewerPluginSync { | |||||
| declare ['constructor']: typeof KTX2LoadPlugin | |||||
| export class KTX2LoadPlugin extends BaseImporterPlugin { | |||||
| public static readonly PluginType = 'KTX2LoadPlugin' | public static readonly PluginType = 'KTX2LoadPlugin' | ||||
| private _importer = new Importer(KTX2Loader2, ['ktx2'], ['image/ktx2'], false) | |||||
| protected _importer = new Importer(KTX2Loader2, ['ktx2'], ['image/ktx2'], false) | |||||
| public static TRANSCODER_LIBRARY_PATH = 'https://cdn.jsdelivr.net/gh/BinomialLLC/basis_universal@1.16.4/webgl/transcoder/build/' | public static TRANSCODER_LIBRARY_PATH = 'https://cdn.jsdelivr.net/gh/BinomialLLC/basis_universal@1.16.4/webgl/transcoder/build/' | ||||
| this._importer.onCtor = (l: KTX2Loader2) => l | this._importer.onCtor = (l: KTX2Loader2) => l | ||||
| .setTranscoderPath(KTX2LoadPlugin.TRANSCODER_LIBRARY_PATH) | .setTranscoderPath(KTX2LoadPlugin.TRANSCODER_LIBRARY_PATH) | ||||
| .detectSupport(viewer.renderManager.renderer) | .detectSupport(viewer.renderManager.renderer) | ||||
| viewer.assetManager.importer.addImporter(this._importer) | |||||
| super.onAdded(viewer) | |||||
| viewer.assetManager.exporter.getExporter('gltf', 'glb')?.extensions?.push(glTFTextureBasisUExtensionExport) | viewer.assetManager.exporter.getExporter('gltf', 'glb')?.extensions?.push(glTFTextureBasisUExtensionExport) | ||||
| } | } | ||||
| onRemove(viewer: ThreeViewer) { | onRemove(viewer: ThreeViewer) { | ||||
| viewer.assetManager.importer.removeImporter(this._importer) | |||||
| super.onRemove(viewer) | |||||
| const exporter = viewer.assetManager.exporter.getExporter('gltf', 'glb') | const exporter = viewer.assetManager.exporter.getExporter('gltf', 'glb') | ||||
| const index = exporter?.extensions?.indexOf(glTFTextureBasisUExtensionExport) | const index = exporter?.extensions?.indexOf(glTFTextureBasisUExtensionExport) | ||||
| if (index !== undefined && index !== -1) exporter?.extensions?.splice(index, 1) | if (index !== undefined && index !== -1) exporter?.extensions?.splice(index, 1) | ||||
| } | } | ||||
| dispose() { | |||||
| return | |||||
| } | |||||
| } | } | ||||
| import {IViewerPluginSync, ThreeViewer} from '../../viewer' | |||||
| import {Importer} from '../../assetmanager' | import {Importer} from '../../assetmanager' | ||||
| import {KTXLoader} from 'three/examples/jsm/loaders/KTXLoader.js' | import {KTXLoader} from 'three/examples/jsm/loaders/KTXLoader.js' | ||||
| import {BaseImporterPlugin} from '../base/BaseImporterPlugin' | |||||
| /** | /** | ||||
| * Adds support for loading `.ktx`, `image/ktx` files and data uris. | * Adds support for loading `.ktx`, `image/ktx` files and data uris. | ||||
| * @category Plugins | * @category Plugins | ||||
| */ | */ | ||||
| export class KTXLoadPlugin implements IViewerPluginSync { | |||||
| declare ['constructor']: typeof KTXLoadPlugin | |||||
| export class KTXLoadPlugin extends BaseImporterPlugin { | |||||
| public static readonly PluginType = 'KTXLoadPlugin' | public static readonly PluginType = 'KTXLoadPlugin' | ||||
| private _importer = new Importer(KTXLoader, ['ktx'], ['image/ktx'], false) | |||||
| onAdded(viewer: ThreeViewer) { | |||||
| viewer.assetManager.importer.addImporter(this._importer) | |||||
| } | |||||
| onRemove(viewer: ThreeViewer) { | |||||
| viewer.assetManager.importer.removeImporter(this._importer) | |||||
| } | |||||
| dispose() { | |||||
| return | |||||
| } | |||||
| protected _importer = new Importer(KTXLoader, ['ktx'], ['image/ktx'], false) | |||||
| } | } |
| import {IViewerPluginSync, ThreeViewer} from '../../viewer' | |||||
| import {ILoader, Importer} from '../../assetmanager' | import {ILoader, Importer} from '../../assetmanager' | ||||
| import {PLYLoader} from 'three/examples/jsm/loaders/PLYLoader.js' | import {PLYLoader} from 'three/examples/jsm/loaders/PLYLoader.js' | ||||
| import {AnyOptions} from 'ts-browser-helpers' | import {AnyOptions} from 'ts-browser-helpers' | ||||
| import {BufferGeometry, Color, Mesh} from 'three' | import {BufferGeometry, Color, Mesh} from 'three' | ||||
| import {PhysicalMaterial} from '../../core' | import {PhysicalMaterial} from '../../core' | ||||
| import {BaseImporterPlugin} from '../base/BaseImporterPlugin' | |||||
| /** | /** | ||||
| * Adds support for loading `.ply`, `text/plain+ply` files and data uris | * Adds support for loading `.ply`, `text/plain+ply` files and data uris | ||||
| * @category Plugins | * @category Plugins | ||||
| */ | */ | ||||
| export class PLYLoadPlugin implements IViewerPluginSync { | |||||
| declare ['constructor']: typeof PLYLoadPlugin | |||||
| export class PLYLoadPlugin extends BaseImporterPlugin { | |||||
| public static readonly PluginType = 'PLYLoadPlugin' | public static readonly PluginType = 'PLYLoadPlugin' | ||||
| private _importer = new Importer(class extends PLYLoader implements ILoader { | |||||
| protected _importer = new Importer(class extends PLYLoader implements ILoader { | |||||
| transform(res: BufferGeometry, _: AnyOptions): Mesh|undefined { | transform(res: BufferGeometry, _: AnyOptions): Mesh|undefined { | ||||
| if (!res.attributes?.normal) res.computeVertexNormals() | if (!res.attributes?.normal) res.computeVertexNormals() | ||||
| // todo set mesh name from options/path | // todo set mesh name from options/path | ||||
| return res ? new Mesh(res, new PhysicalMaterial({color: new Color(1, 1, 1)})) : undefined | |||||
| return res ? new Mesh(res, new PhysicalMaterial({ | |||||
| color: new Color(1, 1, 1), | |||||
| vertexColors: res.hasAttribute('color'), | |||||
| })) : undefined | |||||
| } | } | ||||
| }, ['ply'], ['text/plain+ply'], false) | }, ['ply'], ['text/plain+ply'], false) | ||||
| onAdded(viewer: ThreeViewer) { | |||||
| viewer.assetManager.importer.addImporter(this._importer) | |||||
| } | |||||
| onRemove(viewer: ThreeViewer) { | |||||
| viewer.assetManager.importer.removeImporter(this._importer) | |||||
| } | |||||
| dispose() { | |||||
| return | |||||
| } | |||||
| } | } |
| import {IViewerPluginSync, ThreeViewer} from '../../viewer' | |||||
| import {Importer, Rhino3dmLoader2} from '../../assetmanager' | import {Importer, Rhino3dmLoader2} from '../../assetmanager' | ||||
| import {BaseImporterPlugin} from '../base/BaseImporterPlugin' | |||||
| /** | /** | ||||
| * Adds support for loading Rhino `.3dm`, `model/vnd.3dm`, `model/3dm` files and data uris. | * Adds support for loading Rhino `.3dm`, `model/vnd.3dm`, `model/3dm` files and data uris. | ||||
| * @category Plugins | * @category Plugins | ||||
| */ | */ | ||||
| export class Rhino3dmLoadPlugin implements IViewerPluginSync { | |||||
| declare ['constructor']: typeof Rhino3dmLoadPlugin | |||||
| export class Rhino3dmLoadPlugin extends BaseImporterPlugin { | |||||
| public static readonly PluginType = 'Rhino3dmLoadPlugin' | public static readonly PluginType = 'Rhino3dmLoadPlugin' | ||||
| private _importer = new Importer(Rhino3dmLoader2, ['3dm'], ['model/vnd.3dm', 'model/3dm'], true) | |||||
| onAdded(viewer: ThreeViewer) { | |||||
| viewer.assetManager.importer.addImporter(this._importer) | |||||
| } | |||||
| onRemove(viewer: ThreeViewer) { | |||||
| viewer.assetManager.importer.removeImporter(this._importer) | |||||
| } | |||||
| dispose() { | |||||
| return | |||||
| } | |||||
| protected _importer = new Importer(Rhino3dmLoader2, ['3dm'], ['model/vnd.3dm', 'model/3dm'], true) | |||||
| } | } |
| import {IViewerPluginSync, ThreeViewer} from '../../viewer' | |||||
| import {ILoader, Importer} from '../../assetmanager' | import {ILoader, Importer} from '../../assetmanager' | ||||
| import {STLLoader} from 'three/examples/jsm/loaders/STLLoader.js' | import {STLLoader} from 'three/examples/jsm/loaders/STLLoader.js' | ||||
| import {BufferGeometry, Color, Mesh} from 'three' | import {BufferGeometry, Color, Mesh} from 'three' | ||||
| import {AnyOptions} from 'ts-browser-helpers' | import {AnyOptions} from 'ts-browser-helpers' | ||||
| import {PhysicalMaterial} from '../../core' | import {PhysicalMaterial} from '../../core' | ||||
| import {BaseImporterPlugin} from '../base/BaseImporterPlugin' | |||||
| /** | /** | ||||
| * Adds support for loading `.stl`, `model/stl` files and data uris. | * Adds support for loading `.stl`, `model/stl` files and data uris. | ||||
| * @category Plugins | * @category Plugins | ||||
| */ | */ | ||||
| export class STLLoadPlugin implements IViewerPluginSync { | |||||
| declare ['constructor']: typeof STLLoadPlugin | |||||
| export class STLLoadPlugin extends BaseImporterPlugin { | |||||
| public static readonly PluginType = 'STLLoadPlugin' | public static readonly PluginType = 'STLLoadPlugin' | ||||
| private _importer = new Importer(class extends STLLoader implements ILoader { | |||||
| protected _importer = new Importer(class extends STLLoader implements ILoader { | |||||
| transform(res: BufferGeometry, _: AnyOptions): Mesh|undefined { | transform(res: BufferGeometry, _: AnyOptions): Mesh|undefined { | ||||
| if (!res.attributes?.normal) res.computeVertexNormals() | if (!res.attributes?.normal) res.computeVertexNormals() | ||||
| // todo set mesh name from options/path | // todo set mesh name from options/path | ||||
| return res ? new Mesh(res, new PhysicalMaterial({color: new Color(1, 1, 1)})) : undefined | |||||
| return res ? new Mesh(res, new PhysicalMaterial({ | |||||
| color: new Color(1, 1, 1), | |||||
| vertexColors: res.hasAttribute('color'), | |||||
| })) : undefined | |||||
| } | } | ||||
| }, ['stl'], ['model/stl', 'model/x.stl-binary', 'model/x.stl-ascii'], false) | }, ['stl'], ['model/stl', 'model/x.stl-binary', 'model/x.stl-ascii'], false) | ||||
| onAdded(viewer: ThreeViewer) { | |||||
| viewer.assetManager.importer.addImporter(this._importer) | |||||
| } | |||||
| onRemove(viewer: ThreeViewer) { | |||||
| viewer.assetManager.importer.removeImporter(this._importer) | |||||
| } | |||||
| dispose() { | |||||
| return | |||||
| } | |||||
| } | } |
| import {Importer} from '../../assetmanager' | |||||
| import {USDZLoader} from 'three/examples/jsm/loaders/USDZLoader.js' | |||||
| import {Group, Mesh} from 'three' | |||||
| import {Zippable, zipSync} from 'three/examples/jsm/libs/fflate.module.js' | |||||
| import {BaseImporterPlugin} from '../base/BaseImporterPlugin' | |||||
| /** | |||||
| * Adds support for loading `.usdz`, `model/vnd.usd+zip` and `.usda`, `model/vnd.usda` files and data uris | |||||
| * @category Plugins | |||||
| */ | |||||
| export class USDZLoadPlugin extends BaseImporterPlugin { | |||||
| public static readonly PluginType = 'USDZLoadPlugin' | |||||
| protected _importer = new Importer(class extends USDZLoader { | |||||
| currentUrl = '' | |||||
| async loadAsync(url: string, onProgress?: (event: ProgressEvent) => void): Promise<Mesh> { | |||||
| this.currentUrl = url | |||||
| const res = await super.loadAsync(url, onProgress) | |||||
| this.currentUrl = '' | |||||
| return res | |||||
| } | |||||
| parse(buffer: ArrayBuffer|string): Group { | |||||
| // todo make changes in three.js to allow passing unzipped buffer directly for usda | |||||
| if (this.currentUrl.endsWith('.usda') && typeof buffer !== 'string') { | |||||
| const filename = this.currentUrl.split('/').pop() | |||||
| if (filename) { | |||||
| const zip: Zippable = {} | |||||
| zip[filename] = new Uint8Array(buffer) | |||||
| buffer = zipSync(zip).buffer | |||||
| } | |||||
| } | |||||
| return super.parse(buffer) | |||||
| } | |||||
| }, ['usdz', 'usda'], ['model/vnd.usd+zip', 'model/vnd.usdz+zip', 'model/vnd.usda'], false) | |||||
| } |
| // base | // base | ||||
| export {PipelinePassPlugin} from './base/PipelinePassPlugin' | export {PipelinePassPlugin} from './base/PipelinePassPlugin' | ||||
| export {BaseImporterPlugin} from './base/BaseImporterPlugin' | |||||
| // pipeline | // pipeline | ||||
| export {ProgressivePlugin} from './pipeline/ProgressivePlugin' | export {ProgressivePlugin} from './pipeline/ProgressivePlugin' | ||||
| // ui | // ui | ||||
| export {RenderTargetPreviewPlugin} from './ui/RenderTargetPreviewPlugin' | export {RenderTargetPreviewPlugin} from './ui/RenderTargetPreviewPlugin' | ||||
| export {GeometryUVPreviewPlugin} from './ui/GeometryUVPreviewPlugin' | |||||
| export {ViewerUiConfigPlugin} from './ui/ViewerUiConfigPlugin' | export {ViewerUiConfigPlugin} from './ui/ViewerUiConfigPlugin' | ||||
| export {SceneUiConfigPlugin} from './ui/SceneUiConfigPlugin' | export {SceneUiConfigPlugin} from './ui/SceneUiConfigPlugin' | ||||
| // import | // import | ||||
| export {Rhino3dmLoadPlugin} from './import/Rhino3dmLoadPlugin' | export {Rhino3dmLoadPlugin} from './import/Rhino3dmLoadPlugin' | ||||
| export {USDZLoadPlugin} from './import/USDZLoadPlugin' | |||||
| export {PLYLoadPlugin} from './import/PLYLoadPlugin' | export {PLYLoadPlugin} from './import/PLYLoadPlugin' | ||||
| export {STLLoadPlugin} from './import/STLLoadPlugin' | export {STLLoadPlugin} from './import/STLLoadPlugin' | ||||
| export {KTXLoadPlugin} from './import/KTXLoadPlugin' | export {KTXLoadPlugin} from './import/KTXLoadPlugin' |
| #GeometryUVPreviewPluginContainer{ | |||||
| position: absolute; | |||||
| left: 0; | |||||
| bottom: 0; | |||||
| width: 100%; | |||||
| z-index: 1000; | |||||
| display: flex; | |||||
| flex-wrap: wrap; | |||||
| flex-direction: row; | |||||
| gap: 5px; | |||||
| padding: 5px; | |||||
| pointer-events: none; | |||||
| height: auto; | |||||
| } | |||||
| .GeometryUVPreviewPluginTarget{ | |||||
| position: relative; | |||||
| width: 200px; | |||||
| height: 200px; | |||||
| } | |||||
| .GeometryUVPreviewPluginCollapsed{ | |||||
| height: 25px; | |||||
| } | |||||
| .GeometryUVPreviewPluginTargetHeader{ | |||||
| position: absolute; | |||||
| top: 0; | |||||
| left: 0; | |||||
| right: 0; | |||||
| background: rgba(0,0,0,0.5); | |||||
| color: white; | |||||
| padding: 2px; | |||||
| font-size: 16px; | |||||
| height: 20px; | |||||
| font-family: monospace; | |||||
| text-align: center; | |||||
| pointer-events: auto; | |||||
| cursor: pointer; | |||||
| } | |||||
| .GeometryUVPreviewPluginTargetHeader::after{ | |||||
| content: '-'; | |||||
| position: absolute; | |||||
| right: 2px; | |||||
| width: 20px; | |||||
| height: 20px; | |||||
| line-height: 16px; | |||||
| } | |||||
| .GeometryUVPreviewPluginCollapsed .GeometryUVPreviewPluginTargetHeader::after{ | |||||
| content: '+'; | |||||
| line-height: 20px; | |||||
| } |
| import {AViewerPluginSync, ThreeViewer} from '../../viewer' | |||||
| import {createDiv, createStyles, getOrCall, onChange, ValOrFunc} from 'ts-browser-helpers' | |||||
| import styles from './GeometryUVPreviewPlugin.css' | |||||
| import {CustomContextMenu} from '../../utils' | |||||
| import {uiFolderContainer, uiToggle} from 'uiconfig.js' | |||||
| import {IGeometry} from '../../core' | |||||
| import {UVsDebug} from 'three/examples/jsm/utils/UVsDebug.js' | |||||
| export interface TargetBlock { | |||||
| target: ValOrFunc<IGeometry|undefined> | |||||
| name: string | |||||
| visible: boolean | |||||
| div: HTMLDivElement | |||||
| uvCanvas?: HTMLCanvasElement | |||||
| } | |||||
| @uiFolderContainer('Render Target Preview Plugin') | |||||
| export class GeometryUVPreviewPlugin<TEvent extends string> extends AViewerPluginSync<TEvent> { | |||||
| static readonly PluginType = 'GeometryUVPreviewPlugin' | |||||
| @uiToggle('Enabled') | |||||
| @onChange(GeometryUVPreviewPlugin.prototype.refreshUi) enabled = true | |||||
| toJSON: any = null | |||||
| mainDiv: HTMLDivElement = createDiv({id: 'GeometryUVPreviewPluginContainer', addToBody: false}) | |||||
| stylesheet?: HTMLStyleElement | |||||
| constructor(enabled = true) { | |||||
| super() | |||||
| this.enabled = enabled | |||||
| } | |||||
| targetBlocks: TargetBlock[] = [] | |||||
| onAdded(viewer: ThreeViewer): void { | |||||
| super.onAdded(viewer) | |||||
| viewer.addEventListener('postRender', this._postRender) | |||||
| this.stylesheet = createStyles(styles, viewer.container) | |||||
| this.refreshUi() | |||||
| } | |||||
| onRemove(viewer: ThreeViewer): void { | |||||
| viewer.removeEventListener('postRender', this._postRender) | |||||
| this.stylesheet?.remove() | |||||
| this.stylesheet = undefined | |||||
| this.refreshUi() | |||||
| super.onRemove(viewer) | |||||
| } | |||||
| private _postRender = () => { | |||||
| if (!this._viewer) return | |||||
| for (const target of this.targetBlocks) { | |||||
| if (!target.visible) continue | |||||
| const geo = getOrCall(target.target) | |||||
| if (!geo?.attributes?.uv) { | |||||
| // todo draw white or pink | |||||
| continue | |||||
| } | |||||
| if (!target.uvCanvas) { | |||||
| target.uvCanvas = UVsDebug(geo, 1024) | |||||
| target.uvCanvas.style.width = '100%' | |||||
| target.uvCanvas.style.height = '100%' | |||||
| } | |||||
| if (target.uvCanvas && target.uvCanvas.parentElement !== target.div) target.div.appendChild(target.uvCanvas) | |||||
| // const rect = target.div.getBoundingClientRect() | |||||
| // const canvasRect = this._viewer.canvas.getBoundingClientRect() | |||||
| // rect.x = rect.x - canvasRect.x | |||||
| // rect.y = canvasRect.height + canvasRect.y - rect.y - rect.height | |||||
| // if (Array.isArray(tex)) { | |||||
| // // todo support multi target | |||||
| // this._viewer.console.warn('Multi target preview not supported yet') | |||||
| // continue | |||||
| // } | |||||
| // const outputColorSpace = this._viewer.renderManager.webglRenderer.outputColorSpace | |||||
| // if (!target.originalColorSpace) this._viewer.renderManager.webglRenderer.outputColorSpace = SRGBColorSpace | |||||
| // this._viewer.renderManager.blit(null, { | |||||
| // source: tex, | |||||
| // clear: !target.transparent, | |||||
| // respectColorSpace: !target.originalColorSpace, | |||||
| // viewport: new Vector4(rect.x, rect.y, rect.width, rect.height), | |||||
| // }) | |||||
| // this._viewer.renderManager.webglRenderer.outputColorSpace = outputColorSpace | |||||
| } | |||||
| } | |||||
| addGeometry(target: ValOrFunc<IGeometry|undefined>, name: string, visible = true): this { | |||||
| if (!target) return this | |||||
| const div = document.createElement('div') | |||||
| const targetDef: TargetBlock = {target, name, div, visible} | |||||
| div.classList.add('GeometryUVPreviewPluginTarget') | |||||
| if (!targetDef.visible) div.classList.add('GeometryUVPreviewPluginCollapsed') | |||||
| const header = document.createElement('div') | |||||
| header.classList.add('GeometryUVPreviewPluginTargetHeader') | |||||
| header.innerText = name | |||||
| header.onclick = () => { | |||||
| targetDef.visible = !targetDef.visible | |||||
| if (!targetDef.visible) div.classList.add('GeometryUVPreviewPluginCollapsed') | |||||
| else div.classList.remove('GeometryUVPreviewPluginCollapsed') | |||||
| this._viewer?.setDirty() | |||||
| } | |||||
| header.oncontextmenu = (e) => { | |||||
| e.preventDefault() | |||||
| e.stopPropagation() | |||||
| CustomContextMenu.Create({ | |||||
| 'Download': () => this.downloadGeometryUV(targetDef), | |||||
| 'Remove': () => this.removeGeometry(target), | |||||
| }, e.clientX, e.clientY) | |||||
| } | |||||
| div.appendChild(header) | |||||
| this.mainDiv.appendChild(div) | |||||
| this.targetBlocks.push(targetDef) | |||||
| this.refreshUi() | |||||
| return this | |||||
| } | |||||
| removeGeometry(target: ValOrFunc<IGeometry|undefined>): this { | |||||
| const index = this.targetBlocks.findIndex(t => t.target === target) | |||||
| if (index >= 0) { | |||||
| const t = this.targetBlocks[index] | |||||
| this.targetBlocks.splice(index, 1) | |||||
| t.div.remove() | |||||
| } | |||||
| this.refreshUi() | |||||
| return this | |||||
| } | |||||
| downloadGeometryUV(targetDef: TargetBlock): this { | |||||
| if (!this._viewer) return this | |||||
| if (!targetDef.uvCanvas) return this | |||||
| const canvas = targetDef.uvCanvas | |||||
| const url = canvas.toDataURL('image/png') | |||||
| const link = document.createElement('a') | |||||
| document.body.appendChild(link) | |||||
| link.style.display = 'none' | |||||
| link.href = url | |||||
| link.download = 'renderTarget.' + 'png' | |||||
| link.click() | |||||
| document.body.removeChild(link) | |||||
| URL.revokeObjectURL(url) | |||||
| return this | |||||
| } | |||||
| refreshUi(): void { | |||||
| if (!this.mainDiv) return | |||||
| if (!this._viewer) { | |||||
| if (this.mainDiv.parentElement) this.mainDiv.remove() | |||||
| this.mainDiv.style.display = 'none' | |||||
| this.mainDiv.style.zIndex = '1000' | |||||
| return | |||||
| } | |||||
| if (!this.mainDiv.parentElement) this._viewer.container?.appendChild(this.mainDiv) | |||||
| this.mainDiv.style.display = this.enabled ? 'flex' : 'none' | |||||
| this.mainDiv.style.zIndex = parseInt(this._viewer.canvas.style.zIndex || '0') + 1 + '' | |||||
| this._viewer?.setDirty() | |||||
| } | |||||
| dispose() { | |||||
| for (const target of this.targetBlocks) { | |||||
| this.removeGeometry(target.target) | |||||
| } | |||||
| super.dispose() | |||||
| } | |||||
| } |
| this.dispatchEvent({type: 'animationLoop', deltaTime, time, renderer: this._renderer, xrFrame: frame}) | this.dispatchEvent({type: 'animationLoop', deltaTime, time, renderer: this._renderer, xrFrame: frame}) | ||||
| } | } | ||||
| constructor({canvas, alpha = true, targetOptions}:IRenderManagerOptions) { | |||||
| constructor({canvas, alpha = true, renderScale = 1, targetOptions}:IRenderManagerOptions) { | |||||
| super() | super() | ||||
| this._animationLoop = this._animationLoop.bind(this) | this._animationLoop = this._animationLoop.bind(this) | ||||
| // this._xrPreAnimationLoop = this._xrPreAnimationLoop.bind(this) | // this._xrPreAnimationLoop = this._xrPreAnimationLoop.bind(this) | ||||
| this._renderSize = new Vector2(canvas.clientWidth, canvas.clientHeight) | this._renderSize = new Vector2(canvas.clientWidth, canvas.clientHeight) | ||||
| this._renderScale = renderScale | |||||
| this._renderer = this._initWebGLRenderer(canvas, alpha) | this._renderer = this._initWebGLRenderer(canvas, alpha) | ||||
| this._context = this._renderer.getContext() | this._context = this._renderer.getContext() | ||||
| this._isWebGL2 = this._renderer.capabilities.isWebGL2 | this._isWebGL2 = this._renderer.capabilities.isWebGL2 | ||||
| return this._context | return this._context | ||||
| } | } | ||||
| /** | |||||
| * Same as {@link renderer} | |||||
| */ | |||||
| get webglRenderer(): WebGLRenderer { | get webglRenderer(): WebGLRenderer { | ||||
| return this._renderer | return this._renderer | ||||
| } | } | ||||
| // region Utils | // region Utils | ||||
| /** | /** | ||||
| * | |||||
| * blit - blits a texture to the screen or another render target. | |||||
| * @param destination - destination target, or screen if undefined or null | * @param destination - destination target, or screen if undefined or null | ||||
| * @param source - source Texture | * @param source - source Texture | ||||
| * @param viewport - viewport and scissor | * @param viewport - viewport and scissor | ||||
| return string | return string | ||||
| } | } | ||||
| /** | |||||
| * Rend pixels from a render target into a new Uint8Array|Uint16Array|Float32Array buffer | |||||
| * @param target | |||||
| */ | |||||
| renderTargetToBuffer(target: WebGLRenderTarget): Uint8Array|Uint16Array|Float32Array { | renderTargetToBuffer(target: WebGLRenderTarget): Uint8Array|Uint16Array|Float32Array { | ||||
| const buffer = | const buffer = | ||||
| target.texture.type === HalfFloatType ? | target.texture.type === HalfFloatType ? | ||||
| return buffer | return buffer | ||||
| } | } | ||||
| /** | |||||
| * Exports a render target to a blob. The type is automatically picked from exr to png based on the render target. | |||||
| * @param target - render target to export | |||||
| * @param mimeType - mime type to use. | |||||
| * If auto (default), then it will be picked based on the render target type. | |||||
| */ | |||||
| exportRenderTarget(target: WebGLRenderTarget, mimeType = 'auto'): BlobExt { | exportRenderTarget(target: WebGLRenderTarget, mimeType = 'auto'): BlobExt { | ||||
| const hdrFormats = ['image/x-exr'] | const hdrFormats = ['image/x-exr'] | ||||
| let hdr = target.texture.type === HalfFloatType || target.texture.type === FloatType | let hdr = target.texture.type === HalfFloatType || target.texture.type === FloatType |
| import styles from './CustomContextMenu.css' | import styles from './CustomContextMenu.css' | ||||
| /** | |||||
| * Represents a custom context menu that can be created and managed dynamically. | |||||
| */ | |||||
| export class CustomContextMenu { | export class CustomContextMenu { | ||||
| /** | |||||
| * The HTML element representing the context menu. | |||||
| */ | |||||
| public static Element: HTMLDivElement | undefined = undefined | public static Element: HTMLDivElement | undefined = undefined | ||||
| /** | |||||
| * Indicates whether the context menu has been initialized. | |||||
| */ | |||||
| private static _inited = false | private static _inited = false | ||||
| /** | |||||
| * Initializes the context menu by adding event listeners. | |||||
| * This method should be called before creating a context menu. | |||||
| */ | |||||
| private static _initialize(): void { | private static _initialize(): void { | ||||
| this._inited = true | this._inited = true | ||||
| document.addEventListener('pointerdown', (e) => { | document.addEventListener('pointerdown', (e) => { | ||||
| }) | }) | ||||
| } | } | ||||
| public static Create(items: Record<string, () => void>, x: number, y: number, show = true, removeOnSelect = true): HTMLDivElement { | |||||
| /** | |||||
| * Creates a custom context menu with specified items and options. | |||||
| * | |||||
| * @param items - An object containing menu item labels and corresponding callback functions. | |||||
| * @param x - The horizontal position of the context menu. | |||||
| * @param y - The vertical position of the context menu. | |||||
| * @param show - Indicates whether the context menu should be displayed immediately. | |||||
| * @param removeOnSelect - Indicates whether the context menu should be removed after an item is selected. | |||||
| * @returns The HTML element representing the created context menu. | |||||
| */ | |||||
| public static Create( | |||||
| items: Record<string, () => void>, | |||||
| x: number, | |||||
| y: number, | |||||
| show = true, | |||||
| removeOnSelect = true | |||||
| ): HTMLDivElement { | |||||
| if (!this._inited) this._initialize() | if (!this._inited) this._initialize() | ||||
| if (this.Element) this.Remove() | if (this.Element) this.Remove() | ||||
| return container | return container | ||||
| } | } | ||||
| /** | |||||
| * Removes the context menu from the DOM. | |||||
| */ | |||||
| public static Remove(): void { | public static Remove(): void { | ||||
| this.Element?.remove() | this.Element?.remove() | ||||
| this.Element = undefined | this.Element = undefined |
| if (res._context) delete res._context | if (res._context) delete res._context | ||||
| return res | return res | ||||
| } | } | ||||
| export function metaFromResources(resources?: Partial<SerializationResourcesType>, viewer?: ThreeViewer): SerializationMetaType { | export function metaFromResources(resources?: Partial<SerializationResourcesType>, viewer?: ThreeViewer): SerializationMetaType { | ||||
| return { | return { | ||||
| ...resources, | ...resources, |
| const warnEnabled = true | const warnEnabled = true | ||||
| /** | |||||
| * Replace a string in a shader function with added options to prepend, append, show warning when not found, and replace all occurrences. | |||||
| * @param shader - shader code | |||||
| * @param str - string to replace | |||||
| * @param newStr - new string to replace with | |||||
| * @param replaceAll - replace all occurrences | |||||
| * @param prepend - prepend new string to old string | |||||
| * @param append - append new string to old string | |||||
| */ | |||||
| export function shaderReplaceString(shader: string, str: string, newStr: string, { | export function shaderReplaceString(shader: string, str: string, newStr: string, { | ||||
| replaceAll = false, | replaceAll = false, | ||||
| prepend = false, | prepend = false, |
| */ | */ | ||||
| msaa?: boolean, | msaa?: boolean, | ||||
| /** | /** | ||||
| * Use RGBM HDR Pipeline | |||||
| * Use Uint8 RGBM HDR Render Pipeline. | |||||
| * Provides better performance with post-processing. | |||||
| * RenderManager Uses Half-float if set to false. | |||||
| */ | */ | ||||
| rgbm?: boolean | rgbm?: boolean | ||||
| /** | /** | ||||
| */ | */ | ||||
| zPrepass?: boolean | zPrepass?: boolean | ||||
| /* | |||||
| * Render scale, 1 = full resolution, 0.5 = half resolution, 2 = double resolution. | |||||
| * Same as pixelRatio in three.js | |||||
| * Can be set to `window.devicePixelRatio` to render at device resolution in browsers. | |||||
| * An optimal value is `Math.min(2, window.devicePixelRatio)` to prevent issues on mobile. | |||||
| */ | |||||
| renderScale?: number | |||||
| debug?: boolean | debug?: boolean | ||||
| /** | /** | ||||
| } | } | ||||
| static Dialog: IDialogWrapper = windowDialogWrapper | static Dialog: IDialogWrapper = windowDialogWrapper | ||||
| renderStats: GLStatsJS | |||||
| readonly assetManager: AssetManager | |||||
| get console(): IConsoleWrapper { | |||||
| return ThreeViewer.Console | |||||
| } | |||||
| get dialog(): IDialogWrapper { | |||||
| return ThreeViewer.Dialog | |||||
| } | |||||
| @serialize() readonly type = 'ThreeViewer' | |||||
| private readonly _canvas: HTMLCanvasElement | |||||
| // this can be used by other plugins to add ui elements alongside the canvas | |||||
| private readonly _container: HTMLElement // todo: add a way to move the canvas to a new container... and dispatch event... | |||||
| @uiConfig() @serialize('renderManager') | |||||
| readonly renderManager: ViewerRenderManager | |||||
| /** | |||||
| * The Scene attached to the viewer, this cannot be changed. | |||||
| * @type {RootScene} | |||||
| */ | |||||
| @uiConfig() @serialize('scene') | |||||
| private readonly _scene: RootScene | |||||
| public readonly plugins: Record<string, IViewerPlugin> = {} | |||||
| private _needsResize = false | |||||
| /** | /** | ||||
| * If the viewer is enabled. Set this `false` to disable RAF loop. | * If the viewer is enabled. Set this `false` to disable RAF loop. | ||||
| * @type {boolean} | * @type {boolean} | ||||
| */ | */ | ||||
| enabled = true | enabled = true | ||||
| /** | /** | ||||
| * Enable or disable all rendering, Animation loop including any frame/render events won't be fired when this is false. | * Enable or disable all rendering, Animation loop including any frame/render events won't be fired when this is false. | ||||
| */ | */ | ||||
| @onChange(ThreeViewer.prototype._renderEnabledChanged) | @onChange(ThreeViewer.prototype._renderEnabledChanged) | ||||
| renderEnabled = true | renderEnabled = true | ||||
| private _isRenderingFrame = false | |||||
| renderStats: GLStatsJS | |||||
| readonly assetManager: AssetManager | |||||
| @uiConfig() @serialize('renderManager') | |||||
| readonly renderManager: ViewerRenderManager | |||||
| public readonly plugins: Record<string, IViewerPlugin> = {} | |||||
| /** | |||||
| * Scene with object hierarchy used for rendering | |||||
| */ | |||||
| get scene(): RootScene { | |||||
| return this._scene | |||||
| } | |||||
| /** | /** | ||||
| * Specifies how many frames to render in a single request animation frame. Keep to 1 for realtime rendering. | * Specifies how many frames to render in a single request animation frame. Keep to 1 for realtime rendering. | ||||
| * Note: should be max (screen refresh rate / animation frame rate) like 60Hz / 30fps | * Note: should be max (screen refresh rate / animation frame rate) like 60Hz / 30fps | ||||
| * @type {number} | * @type {number} | ||||
| */ | */ | ||||
| public maxFramePerLoop = 1 | public maxFramePerLoop = 1 | ||||
| readonly debug: boolean | |||||
| get scene(): RootScene { | |||||
| return this._scene | |||||
| /** | |||||
| * Get the HTML Element containing the canvas | |||||
| * @returns {HTMLElement} | |||||
| */ | |||||
| get container(): HTMLElement { | |||||
| return this._container | |||||
| } | |||||
| /** | |||||
| * Get the HTML Canvas Element where the viewer is rendering | |||||
| * @returns {HTMLCanvasElement} | |||||
| */ | |||||
| get canvas(): HTMLCanvasElement { | |||||
| return this._canvas | |||||
| } | |||||
| get console(): IConsoleWrapper { | |||||
| return ThreeViewer.Console | |||||
| } | } | ||||
| get dialog(): IDialogWrapper { | |||||
| return ThreeViewer.Dialog | |||||
| } | |||||
| @serialize() readonly type = 'ThreeViewer' | |||||
| /** | /** | ||||
| * The ResizeObserver observing the canvas element. Add more elements to this observer to resize viewer on their size change. | * The ResizeObserver observing the canvas element. Add more elements to this observer to resize viewer on their size change. | ||||
| */ | */ | ||||
| readonly resizeObserver = window?.ResizeObserver ? new window.ResizeObserver(_ => this.resize()) : undefined | readonly resizeObserver = window?.ResizeObserver ? new window.ResizeObserver(_ => this.resize()) : undefined | ||||
| private readonly _canvas: HTMLCanvasElement | |||||
| // this can be used by other plugins to add ui elements alongside the canvas | |||||
| private readonly _container: HTMLElement // todo: add a way to move the canvas to a new container... and dispatch event... | |||||
| /** | |||||
| * The Scene attached to the viewer, this cannot be changed. | |||||
| * @type {RootScene} | |||||
| */ | |||||
| @uiConfig() @serialize('scene') | |||||
| private readonly _scene: RootScene | |||||
| private _needsResize = false | |||||
| private _isRenderingFrame = false | |||||
| private _objectProcessor: IObjectProcessor = { | |||||
| processObject: (object: IObject3D)=>{ | |||||
| if (object.material) { | |||||
| if (Array.isArray(object.material)) this.assetManager.materials.registerMaterials(object.material) | |||||
| else this.assetManager.materials.registerMaterial(object.material) | |||||
| } | |||||
| }, | |||||
| } | |||||
| private _needsReset = true // renderer needs reset | |||||
| // Helpers for tracking main camera change and setting dirty automatically | |||||
| private _lastCameraPosition: Vector3 = new Vector3() | private _lastCameraPosition: Vector3 = new Vector3() | ||||
| private _lastCameraQuat: Quaternion = new Quaternion() | private _lastCameraQuat: Quaternion = new Quaternion() | ||||
| private _lastCameraTarget: Vector3 = new Vector3() | private _lastCameraTarget: Vector3 = new Vector3() | ||||
| private _tempVec: Vector3 = new Vector3() | private _tempVec: Vector3 = new Vector3() | ||||
| private _tempQuat: Quaternion = new Quaternion() | private _tempQuat: Quaternion = new Quaternion() | ||||
| readonly debug: boolean | |||||
| /** | /** | ||||
| * Create a viewer instance for using the webgi viewer SDK. | * Create a viewer instance for using the webgi viewer SDK. | ||||
| * @param options - {@link ThreeViewerOptions} | * @param options - {@link ThreeViewerOptions} | ||||
| zPrepass: options.zPrepass ?? options.useGBufferDepth ?? false, | zPrepass: options.zPrepass ?? options.useGBufferDepth ?? false, | ||||
| depthBuffer: !(options.zPrepass ?? options.useGBufferDepth ?? false), | depthBuffer: !(options.zPrepass ?? options.useGBufferDepth ?? false), | ||||
| screenShader: options.screenShader, | screenShader: options.screenShader, | ||||
| renderScale: options.renderScale, | |||||
| }) | }) | ||||
| this.renderManager.addEventListener('animationLoop', this._animationLoop as any) | this.renderManager.addEventListener('animationLoop', this._animationLoop as any) | ||||
| this.renderManager.addEventListener('resize', ()=> this._scene.mainCamera.refreshAspect()) | this.renderManager.addEventListener('resize', ()=> this._scene.mainCamera.refreshAspect()) | ||||
| } | } | ||||
| private _objectProcessor: IObjectProcessor = { | |||||
| processObject: (object: IObject3D)=>{ | |||||
| if (object.material) { | |||||
| if (Array.isArray(object.material)) this.assetManager.materials.registerMaterials(object.material) | |||||
| else this.assetManager.materials.registerMaterial(object.material) | |||||
| } | |||||
| }, | |||||
| } | |||||
| // todo: find a better fix for context loss and restore? | |||||
| private _lastSize = new Vector2() | |||||
| private _onContextRestore = (_: Event) => { | |||||
| this.enabled = true | |||||
| this._canvas.width = this._lastSize.width | |||||
| this._canvas.height = this._lastSize.height | |||||
| this.resize() | |||||
| this._scene.setDirty({refreshScene: true, frameFade: false}) | |||||
| } | |||||
| private _onContextLost = (_: Event) => { | |||||
| this._lastSize.set(this._canvas.width, this._canvas.height) | |||||
| this._canvas.width = 2 | |||||
| this._canvas.height = 2 | |||||
| this.resize() | |||||
| this.enabled = false | |||||
| } | |||||
| /** | |||||
| * Mark that the canvas is resized. If the size is changed, the renderer and all render targets are resized. This happens before the render of the next frame. | |||||
| */ | |||||
| resize = () => { | |||||
| this._needsResize = true | |||||
| this.setDirty() | |||||
| } | |||||
| private _needsReset = true // renderer reset | |||||
| /** | |||||
| * Set the viewer to dirty and trigger render of the next frame. | |||||
| * @param source - The source of the dirty event. like plugin or 3d object | |||||
| * @param event - The event that triggered the dirty event. | |||||
| */ | |||||
| setDirty(source?: any, event?: Event): void { | |||||
| this._needsReset = true | |||||
| source = source ?? this | |||||
| this.dispatchEvent({...event ?? {}, type: 'update', source}) | |||||
| } | |||||
| /** | |||||
| * The renderer for the viewer that's attached to the canvas. This is wrapper around WebGLRenderer and EffectComposer and manages post-processing passes and rendering logic | |||||
| * @deprecated - use {@link renderManager} instead | |||||
| */ | |||||
| get renderer(): ViewerRenderManager { | |||||
| this.console.error('renderer is deprecated, use renderManager instead') | |||||
| return this.renderManager | |||||
| } | |||||
| /** | /** | ||||
| * Add an object/model/material/viewer-config/plugin-preset/... to the viewer scene from url or an {@link IAsset} object. | * Add an object/model/material/viewer-config/plugin-preset/... to the viewer scene from url or an {@link IAsset} object. | ||||
| * Same as {@link AssetManager.addAssetSingle} | * Same as {@link AssetManager.addAssetSingle} | ||||
| return await this.assetManager.importer.importSingle<T>(obj, options) | return await this.assetManager.importer.importSingle<T>(obj, options) | ||||
| } | } | ||||
| /** | |||||
| * Exports an object/mesh/material/texture/render-target/plugin-preset/viewer to a blob. | |||||
| * If no object is given, a glb is exported with the current viewer state. | |||||
| * @param obj | |||||
| * @param options | |||||
| */ | |||||
| async export(obj?: IObject3D|IMaterial|ITexture|IRenderTarget|IViewerPlugin|(typeof this), options?: ExportFileOptions) { | |||||
| if (!obj) obj = this._scene // this will export the glb with the scene and viewer config | |||||
| if ((<typeof this>obj).type === this.type) return jsonToBlob((<typeof this>obj).exportConfig()) | |||||
| if ((<IViewerPlugin>obj).constructor?.PluginType) return jsonToBlob(this.exportPluginConfig(<IViewerPlugin>obj)) | |||||
| return await this.assetManager.exporter.exportObject(<IObject3D|IMaterial|ITexture|IRenderTarget>obj, options) | |||||
| } | |||||
| /** | /** | ||||
| * Set the environment map of the scene from url or an {@link IAsset} object. | * Set the environment map of the scene from url or an {@link IAsset} object. | ||||
| * @param map | * @param map | ||||
| return this._scene.background | return this._scene.background | ||||
| } | } | ||||
| /** | |||||
| * Exports an object/mesh/material/texture/render-target/plugin-preset/viewer to a blob. | |||||
| * If no object is given, a glb is exported with the current viewer state. | |||||
| * @param obj | |||||
| * @param options | |||||
| */ | |||||
| async export(obj?: IObject3D|IMaterial|ITexture|IRenderTarget|IViewerPlugin|(typeof this), options?: ExportFileOptions) { | |||||
| if (!obj) obj = this._scene // this will export the glb with the scene and viewer config | |||||
| if ((<typeof this>obj).type === this.type) return jsonToBlob((<typeof this>obj).exportConfig()) | |||||
| if ((<IViewerPlugin>obj).constructor?.PluginType) return jsonToBlob(this.exportPluginConfig(<IViewerPlugin>obj)) | |||||
| return await this.assetManager.exporter.exportObject(<IObject3D|IMaterial|ITexture|IRenderTarget>obj, options) | |||||
| } | |||||
| /** | |||||
| * Export the scene to a file (default: glb with viewer config) and return a blob | |||||
| * @param options | |||||
| */ | |||||
| async exportScene(options?: ExportFileOptions): Promise<BlobExt | undefined> { | |||||
| return this.assetManager.exporter.exportObject(this._scene.modelRoot, options) | |||||
| } | |||||
| async getScreenshotBlob({mimeType = 'image/jpeg', quality = 90} = {}): Promise<Blob | null> { | |||||
| const blobPromise = async()=> new Promise<Blob|null>((resolve) => { | |||||
| this._canvas.toBlob((blob) => { | |||||
| resolve(blob) | |||||
| }, mimeType, quality) | |||||
| }) | |||||
| if (!this.renderEnabled) return blobPromise() | |||||
| return await this.doOnce('postFrame', async() => { | |||||
| this.renderEnabled = false | |||||
| const blob = await blobPromise() | |||||
| this.renderEnabled = true | |||||
| return blob | |||||
| }) | |||||
| } | |||||
| async getScreenshotDataUrl({mimeType = 'image/jpeg', quality = 90} = {}): Promise<string | null> { | |||||
| if (!this.renderEnabled) return this._canvas.toDataURL(mimeType, quality) | |||||
| return await this.doOnce('postFrame', () => this._canvas.toDataURL(mimeType, quality)) | |||||
| } | |||||
| /** | /** | ||||
| * Disposes the viewer and frees up all resource and events. Do not use the viewer after calling dispose. | * Disposes the viewer and frees up all resource and events. Do not use the viewer after calling dispose. | ||||
| * @note - If you want to reuse the viewer, set viewer.enabled to false instead, then set it to true again when required. To dispose all the objects, materials in the scene use `viewer.scene.disposeSceneModels()` | * @note - If you want to reuse the viewer, set viewer.enabled to false instead, then set it to true again when required. To dispose all the objects, materials in the scene use `viewer.scene.disposeSceneModels()` | ||||
| this.dispatchEvent({type: 'dispose'}) | this.dispatchEvent({type: 'dispose'}) | ||||
| } | } | ||||
| private _animationLoop(event: IAnimationLoopEvent): void { | |||||
| /** | |||||
| * Mark that the canvas is resized. If the size is changed, the renderer and all render targets are resized. This happens before the render of the next frame. | |||||
| */ | |||||
| resize = () => { | |||||
| this._needsResize = true | |||||
| this.setDirty() | |||||
| } | |||||
| /** | |||||
| * Set the viewer to dirty and trigger render of the next frame. | |||||
| * @param source - The source of the dirty event. like plugin or 3d object | |||||
| * @param event - The event that triggered the dirty event. | |||||
| */ | |||||
| setDirty(source?: any, event?: Event): void { | |||||
| this._needsReset = true | |||||
| source = source ?? this | |||||
| this.dispatchEvent({...event ?? {}, type: 'update', source}) | |||||
| } | |||||
| protected _animationLoop(event: IAnimationLoopEvent): void { | |||||
| if (!this.enabled || !this.renderEnabled) return | if (!this.enabled || !this.renderEnabled) return | ||||
| if (this._isRenderingFrame) { | if (this._isRenderingFrame) { | ||||
| this.console.warn('animation loop: frame skip') // not possible actually, since this is not async | this.console.warn('animation loop: frame skip') // not possible actually, since this is not async | ||||
| } | } | ||||
| /** | |||||
| * Get the HTML Element containing the canvas | |||||
| * @returns {HTMLElement} | |||||
| */ | |||||
| get container(): HTMLElement { | |||||
| return this._container | |||||
| } | |||||
| /** | |||||
| * Get the HTML Canvas Element where the viewer is rendering | |||||
| * @returns {HTMLCanvasElement} | |||||
| */ | |||||
| get canvas(): HTMLCanvasElement { | |||||
| return this._canvas | |||||
| } | |||||
| /** | /** | ||||
| * Get the Plugin by a constructor type or by the string type. | * Get the Plugin by a constructor type or by the string type. | ||||
| * Use string type if the plugin is not a dependency and you don't want to bundle the plugin. | * Use string type if the plugin is not a dependency and you don't want to bundle the plugin. | ||||
| } | } | ||||
| /** | /** | ||||
| * Get the Plugin by the string type. | |||||
| * @deprecated - Use {@link getPlugin} instead. | |||||
| * Get the Plugin by a constructor type or add a new plugin of the specified type if it doesn't exist. | |||||
| * @param type | * @param type | ||||
| * @returns {T | undefined} | |||||
| * @param args - arguments for the constructor of the plugin, used when a new plugin is created. | |||||
| */ | */ | ||||
| getPluginByType<T extends IViewerPlugin>(type: string): T | undefined { | |||||
| return this.plugins[type] as T | undefined | |||||
| } | |||||
| async getOrAddPlugin<T extends IViewerPlugin>(type: Class<T>, ...args: ConstructorParameters<Class<T>>): Promise<T> { | async getOrAddPlugin<T extends IViewerPlugin>(type: Class<T>, ...args: ConstructorParameters<Class<T>>): Promise<T> { | ||||
| const plugin = this.getPlugin(type) | const plugin = this.getPlugin(type) | ||||
| if (plugin) return plugin | if (plugin) return plugin | ||||
| return this.addPlugin(type, ...args) | return this.addPlugin(type, ...args) | ||||
| } | } | ||||
| /** | |||||
| * Get the Plugin by a constructor type or add a new plugin to the viewer of the specified type if it doesn't exist(sync). | |||||
| * @param type | |||||
| * @param args - arguments for the constructor of the plugin, used when a new plugin is created. | |||||
| */ | |||||
| getOrAddPluginSync<T extends IViewerPluginSync>(type: Class<T>, ...args: ConstructorParameters<Class<T>>): T { | getOrAddPluginSync<T extends IViewerPluginSync>(type: Class<T>, ...args: ConstructorParameters<Class<T>>): T { | ||||
| const plugin = this.getPlugin(type) | const plugin = this.getPlugin(type) | ||||
| if (plugin) return plugin | if (plugin) return plugin | ||||
| return p | return p | ||||
| } | } | ||||
| /** | |||||
| * Add multiple plugins to the viewer. | |||||
| * @param plugins - List of plugin instances or classes | |||||
| */ | |||||
| async addPlugins(plugins: (IViewerPlugin | Class<IViewerPlugin>)[]): Promise<void> { | async addPlugins(plugins: (IViewerPlugin | Class<IViewerPlugin>)[]): Promise<void> { | ||||
| for (const p of plugins) await this.addPlugin(p) | for (const p of plugins) await this.addPlugin(p) | ||||
| } | } | ||||
| /** | |||||
| * Add multiple plugins to the viewer(sync). | |||||
| * @param plugins - List of plugin instances or classes | |||||
| */ | |||||
| async addPluginsSync(plugins: (IViewerPluginSync | Class<IViewerPluginSync>)[]): Promise<void> { | async addPluginsSync(plugins: (IViewerPluginSync | Class<IViewerPluginSync>)[]): Promise<void> { | ||||
| for (const p of plugins) this.addPluginSync(p) | for (const p of plugins) this.addPluginSync(p) | ||||
| } | } | ||||
| this.setDirty(p) | this.setDirty(p) | ||||
| } | } | ||||
| /** | |||||
| * Remove a plugin instance or a plugin class(sync). Works similar to {@link ThreeViewer.addPluginSync} | |||||
| * @param p | |||||
| * @param dispose | |||||
| */ | |||||
| removePluginSync(p: IViewerPluginSync, dispose = true): void { | removePluginSync(p: IViewerPluginSync, dispose = true): void { | ||||
| const type = p.constructor.PluginType | const type = p.constructor.PluginType | ||||
| if (!this.plugins[type]) return | if (!this.plugins[type]) return | ||||
| this.resize() | this.resize() | ||||
| } | } | ||||
| // private _addSceneObject = (e: IEvent<any>) => { | |||||
| // if (!e || !e.object) return | |||||
| // const config = e.object.__importedViewerConfig // this is set in gltf.ts when gltf file is imported. This is done here so that scene settings are applied whenever the imported object is added to scene. | |||||
| // if (!config) return | |||||
| // this.fromJSON(config, config.resources) | |||||
| // } | |||||
| /** | |||||
| * @deprecated use {@link assetManager} instead. | |||||
| * Gets the Asset manager, contains useful functions for managing, loading and inserting assets. | |||||
| */ | |||||
| getManager(): AssetManager|undefined { | |||||
| return this.assetManager | |||||
| } | |||||
| // todo | |||||
| // public async fitToView(selected?: Object3D, distanceMultiplier = 1.5, duration?: number, ease?: Easing|EasingFunctionType) { | |||||
| // const camViews = this.getPluginByType<CameraViewPlugin>('CameraViews') | |||||
| // if (!camViews) { | |||||
| // this.console.error('CameraViews plugin is required for fitToView to work') | |||||
| // return | |||||
| // } | |||||
| // await camViews?.animateToFitObject(selected, distanceMultiplier, duration, ease, {min: (this.scene.activeCamera.getControls<OrbitControls3>()?.minDistance ?? 0.5) + 0.5, max: 1000.0}) | |||||
| // } | |||||
| /** | /** | ||||
| * Traverse all objects in scene model root. | * Traverse all objects in scene model root. | ||||
| * @param callback | * @param callback | ||||
| this._scene.modelRoot.traverse(callback) | this._scene.modelRoot.traverse(callback) | ||||
| } | } | ||||
| // todo: create/load texture utils | |||||
| /** | |||||
| * Add an object to the scene model root. | |||||
| * If an imported scene model root is passed, it will be loaded with viewer configuration, unless importConfig is false | |||||
| * @param imported | |||||
| * @param options | |||||
| */ | |||||
| async addSceneObject<T extends IObject3D|Object3D|RootSceneImportResult = RootSceneImportResult>(imported: T, options?: AddObjectOptions): Promise<T> { | |||||
| if (imported.userData?.rootSceneModelRoot) { | |||||
| const obj = <RootSceneImportResult>imported | |||||
| if (obj.importedViewerConfig && options?.importConfig !== false) await this.importConfig(obj.importedViewerConfig) | |||||
| this._scene.loadModelRoot(obj, options) | |||||
| return this._scene.modelRoot as T | |||||
| } | |||||
| this._scene.addObject(imported, options) | |||||
| return imported | |||||
| } | |||||
| /** | /** | ||||
| * Serialize all the plugins and their settings to save or create presets. Used in {@link toJSON}. | * Serialize all the plugins and their settings to save or create presets. Used in {@link toJSON}. | ||||
| return data | return data | ||||
| } | } | ||||
| /** | /** | ||||
| * Deserialize all the viewer and plugin settings. | * Deserialize all the viewer and plugin settings. | ||||
| * @note use async {@link ThreeViewer.importConfig} to import a json/config exported with {@link ThreeViewer.exportConfig} or {@link ThreeViewer.toJSON}. | * @note use async {@link ThreeViewer.importConfig} to import a json/config exported with {@link ThreeViewer.exportConfig} or {@link ThreeViewer.toJSON}. | ||||
| return await MetaImporter.ImportMeta(meta, extraResources) | return await MetaImporter.ImportMeta(meta, extraResources) | ||||
| } | } | ||||
| async addSceneObject<T extends IObject3D|Object3D|RootSceneImportResult = RootSceneImportResult>(imported: T, options?: AddObjectOptions): Promise<T> { | |||||
| if (imported.userData?.rootSceneModelRoot) { | |||||
| const obj = <RootSceneImportResult>imported | |||||
| if (obj.importedViewerConfig && options?.importConfig !== false) await this.importConfig(obj.importedViewerConfig) | |||||
| this._scene.loadModelRoot(obj, options) | |||||
| return this._scene.modelRoot as T | |||||
| } | |||||
| this._scene.addObject(imported, options) | |||||
| return imported | |||||
| async doOnce<TRet>(event: IViewerEventTypes, func: (...args: any[]) => TRet): Promise<TRet> { | |||||
| return new Promise((resolve) => { | |||||
| const listener = async(...args: any[]) => { | |||||
| this.removeEventListener(event, listener) | |||||
| resolve(await func(...args)) | |||||
| } | |||||
| this.addEventListener(event, listener) | |||||
| }) | |||||
| } | } | ||||
| private _setActiveCameraView(event: any = {}): void { | private _setActiveCameraView(event: any = {}): void { | ||||
| return p | return p | ||||
| } | } | ||||
| async doOnce<TRet>(event: IViewerEventTypes, func: (...args: any[]) => TRet): Promise<TRet> { | |||||
| return new Promise((resolve) => { | |||||
| const listener = async(...args: any[]) => { | |||||
| this.removeEventListener(event, listener) | |||||
| resolve(await func(...args)) | |||||
| } | |||||
| this.addEventListener(event, listener) | |||||
| }) | |||||
| } | |||||
| /** | |||||
| * Export the scene to a file (default: glb with viewer config) and return a blob | |||||
| * @param options | |||||
| */ | |||||
| async exportScene(options?: ExportFileOptions): Promise<BlobExt | undefined> { | |||||
| return this.assetManager.exporter.exportObject(this._scene.modelRoot, options) | |||||
| } | |||||
| async getScreenshotBlob({mimeType = 'image/jpeg', quality = 90} = {}): Promise<Blob | null> { | |||||
| const blobPromise = async()=> new Promise<Blob|null>((resolve) => { | |||||
| this._canvas.toBlob((blob) => { | |||||
| resolve(blob) | |||||
| }, mimeType, quality) | |||||
| }) | |||||
| if (!this.renderEnabled) return blobPromise() | |||||
| return await this.doOnce('postFrame', async() => { | |||||
| this.renderEnabled = false | |||||
| const blob = await blobPromise() | |||||
| this.renderEnabled = true | |||||
| return blob | |||||
| }) | |||||
| } | |||||
| async getScreenshotDataUrl({mimeType = 'image/jpeg', quality = 90} = {}): Promise<string | null> { | |||||
| if (!this.renderEnabled) return this._canvas.toDataURL(mimeType, quality) | |||||
| return await this.doOnce('postFrame', () => this._canvas.toDataURL(mimeType, quality)) | |||||
| } | |||||
| private _renderEnabledChanged(): void { | private _renderEnabledChanged(): void { | ||||
| this.dispatchEvent({type: this.renderEnabled ? 'renderEnabled' : 'renderDisabled'}) | this.dispatchEvent({type: this.renderEnabled ? 'renderEnabled' : 'renderDisabled'}) | ||||
| } | } | ||||
| plugins: [], | plugins: [], | ||||
| } | } | ||||
| // todo: find a better fix for context loss and restore? | |||||
| private _lastSize = new Vector2() | |||||
| private _onContextRestore = (_: Event) => { | |||||
| this.enabled = true | |||||
| this._canvas.width = this._lastSize.width | |||||
| this._canvas.height = this._lastSize.height | |||||
| this.resize() | |||||
| this._scene.setDirty({refreshScene: true, frameFade: false}) | |||||
| } | |||||
| private _onContextLost = (_: Event) => { | |||||
| this._lastSize.set(this._canvas.width, this._canvas.height) | |||||
| this._canvas.width = 2 | |||||
| this._canvas.height = 2 | |||||
| this.resize() | |||||
| this.enabled = false | |||||
| } | |||||
| // private _addSceneObject = (e: IEvent<any>) => { | |||||
| // if (!e || !e.object) return | |||||
| // const config = e.object.__importedViewerConfig // this is set in gltf.ts when gltf file is imported. This is done here so that scene settings are applied whenever the imported object is added to scene. | |||||
| // if (!config) return | |||||
| // this.fromJSON(config, config.resources) | |||||
| // } | |||||
| // todo | |||||
| // public async fitToView(selected?: Object3D, distanceMultiplier = 1.5, duration?: number, ease?: Easing|EasingFunctionType) { | |||||
| // const camViews = this.getPluginByType<CameraViewPlugin>('CameraViews') | |||||
| // if (!camViews) { | |||||
| // this.console.error('CameraViews plugin is required for fitToView to work') | |||||
| // return | |||||
| // } | |||||
| // await camViews?.animateToFitObject(selected, distanceMultiplier, duration, ease, {min: (this.scene.activeCamera.getControls<OrbitControls3>()?.minDistance ?? 0.5) + 0.5, max: 1000.0}) | |||||
| // } | |||||
| // todo: create/load texture utils | |||||
| // region legacy creation functions | // region legacy creation functions | ||||
| // /** | // /** | ||||
| // endregion | // endregion | ||||
| /** | |||||
| * The renderer for the viewer that's attached to the canvas. This is wrapper around WebGLRenderer and EffectComposer and manages post-processing passes and rendering logic | |||||
| * @deprecated - use {@link renderManager} instead | |||||
| */ | |||||
| get renderer(): ViewerRenderManager { | |||||
| this.console.error('renderer is deprecated, use renderManager instead') | |||||
| return this.renderManager | |||||
| } | |||||
| /** | |||||
| * @deprecated use {@link assetManager} instead. | |||||
| * Gets the Asset manager, contains useful functions for managing, loading and inserting assets. | |||||
| */ | |||||
| getManager(): AssetManager|undefined { | |||||
| return this.assetManager | |||||
| } | |||||
| /** | |||||
| * Get the Plugin by the string type. | |||||
| * @deprecated - Use {@link getPlugin} instead. | |||||
| * @param type | |||||
| * @returns {T | undefined} | |||||
| */ | |||||
| getPluginByType<T extends IViewerPlugin>(type: string): T | undefined { | |||||
| return this.plugins[type] as T | undefined | |||||
| } | |||||
| } | } |
| export const VERSION = '0.0.12' | |||||
| export const VERSION = '0.0.14' |