| - Add example and any other tests to `tests/` | - Add example and any other tests to `tests/` | ||||
| - Add info to `README.md` | - Add info to `README.md` | ||||
| - Add info to `./website/guide/threepipe-packages.md` | - Add info to `./website/guide/threepipe-packages.md` | ||||
| - Add info to `./website/packages/PluginName.md` | |||||
| - Add info to `./website/package/plugin-name.md` and add to `./website/.vitepress/config.ts` | |||||
| - `npm run build` and test with example | - `npm run build` and test with example | ||||
| - Publish package with `npm run new:publish`. Add tag to git like `plugin-name-v0.0.1` | |||||
| - Publish package with `npm run new:publish`. Check that tag is added to git like `plugin-name-v0.0.1` |
| - [SimplifyModifierPlugin](https://threepipe.org/plugin/SimplifyModifierPlugin.html) - Boilerplate for plugin to simplify geometries | - [SimplifyModifierPlugin](https://threepipe.org/plugin/SimplifyModifierPlugin.html) - Boilerplate for plugin to simplify geometries | ||||
| - [MeshOptSimplifyModifierPlugin](https://threepipe.org/plugin/MeshOptSimplifyModifierPlugin.html) - Simplify geometries using [meshoptimizer](https://github.com/zeux/meshoptimizer) library | - [MeshOptSimplifyModifierPlugin](https://threepipe.org/plugin/MeshOptSimplifyModifierPlugin.html) - Simplify geometries using [meshoptimizer](https://github.com/zeux/meshoptimizer) library | ||||
| - [Packages](https://threepipe.org/guide/threepipe-packages.html) | - [Packages](https://threepipe.org/guide/threepipe-packages.html) | ||||
| - [@threepipe/webgi-plugins](https://webgi.dev) - Web [Global Illumination](https://en.wikipedia.org/wiki/Global_illumination) - Realistic rendering plugin pack (SSR, SSRTAO, HDR Bloom, TAA, Depth of Field, SSGI, etc.) | |||||
| - [@threepipe/plugin-tweakpane](https://threepipe.org/package/plugin-tweakpane.html) [Tweakpane](https://tweakpane.github.io/docs/) UI Plugin | - [@threepipe/plugin-tweakpane](https://threepipe.org/package/plugin-tweakpane.html) [Tweakpane](https://tweakpane.github.io/docs/) UI Plugin | ||||
| - [@threepipe/plugin-blueprintjs](https://threepipe.org/package/plugin-blueprintjs.html) [BlueprintJs](https://blueprintjs.com/) UI Plugin | - [@threepipe/plugin-blueprintjs](https://threepipe.org/package/plugin-blueprintjs.html) [BlueprintJs](https://blueprintjs.com/) UI Plugin | ||||
| - [@threepipe/plugin-tweakpane-editor](https://threepipe.org/package/plugin-tweakpane-editor.html) - Editor Plugin using Tweakpane for plugin UI | - [@threepipe/plugin-tweakpane-editor](https://threepipe.org/package/plugin-tweakpane-editor.html) - Editor Plugin using Tweakpane for plugin UI | ||||
| - [@threepipe/plugin-network](https://threepipe.org/package/plugin-network.html) - Network/Cloud related plugin implementations for Threepipe | - [@threepipe/plugin-network](https://threepipe.org/package/plugin-network.html) - Network/Cloud related plugin implementations for Threepipe | ||||
| - [@threepipe/plugin-svg-renderer](https://threepipe.org/package/plugin-svg-renderer.html) - Add support for exporting a 3d scene as SVG using [three-svg-renderer](https://www.npmjs.com/package/three-svg-renderer) | - [@threepipe/plugin-svg-renderer](https://threepipe.org/package/plugin-svg-renderer.html) - Add support for exporting a 3d scene as SVG using [three-svg-renderer](https://www.npmjs.com/package/three-svg-renderer) | ||||
| - [@threepipe/plugin-3d-tiles-renderer](https://threepipe.org/package/plugin-3d-tiles-renderer.html) - Plugins for [3d-tiles-renderer](https://github.com/NASA-AMMOS/3DTilesRendererJS), b3dm, i3dm, cmpt, pnts, dzi, slippy maps importers. | - [@threepipe/plugin-3d-tiles-renderer](https://threepipe.org/package/plugin-3d-tiles-renderer.html) - Plugins for [3d-tiles-renderer](https://github.com/NASA-AMMOS/3DTilesRendererJS), b3dm, i3dm, cmpt, pnts, dzi, slippy maps importers. | ||||
| - [@threepipe/webgi-plugins](https://webgi.dev) - Web [Global Illumination](https://en.wikipedia.org/wiki/Global_illumination) - Realistic rendering plugin pack (SSR, SSRTAO, HDR Bloom, TAA, Depth of Field, SSGI, etc.) | |||||
| - [@threepipe/plugin-assimpjs](https://threepipe.org/package/plugin-assimpjs.html) - Plugin and helpers to load and use [assimpjs](https://github.com/kovacsv/assimpjs) (with fbx, other exporters) in the browser. | |||||
| ## Documentation | ## Documentation | ||||
| <!DOCTYPE html> | |||||
| <html lang="en"> | |||||
| <head> | |||||
| <meta charset="UTF-8"> | |||||
| <title>AssimpJs Plugin</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", | |||||
| "@threepipe/plugin-assimpjs": "./../../plugins/assimpjs/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/global-loading.mjs"></script> | |||||
| <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, | |||||
| _testStart, | |||||
| downloadBlob, HemisphereLight, | |||||
| IObject3D, | |||||
| LoadingScreenPlugin, | |||||
| ThreeViewer, | |||||
| } from 'threepipe' | |||||
| import {AssimpJsPlugin} from '@threepipe/plugin-assimpjs' | |||||
| const viewer = new ThreeViewer({ | |||||
| canvas: document.getElementById('mcanvas') as HTMLCanvasElement, | |||||
| msaa: true, | |||||
| plugins: [LoadingScreenPlugin], | |||||
| }) | |||||
| async function init() { | |||||
| const assimp = viewer.addPluginSync(AssimpJsPlugin) | |||||
| await assimp.init() | |||||
| console.log('AssimpJsPlugin initialized:', assimp.ajs) | |||||
| // Direct way to convert without using the viewer | |||||
| const files = [ | |||||
| 'https://threejs.org/examples/models/obj/male02/male02.obj', | |||||
| 'https://threejs.org/examples/models/obj/male02/male02.mtl', // mtl doesnt work? | |||||
| ] | |||||
| const fe = files.map(async f=>fetch(`${f}`).then(async t=>t.arrayBuffer())) | |||||
| const responses = await Promise.all(fe) | |||||
| const fileList: Record<string, ArrayBuffer> = {} | |||||
| for (let i = 0; i < files.length; i++) { | |||||
| fileList[files[i]] = responses[i] | |||||
| } | |||||
| const fbx = assimp.convertFiles(fileList, 'fbx') | |||||
| if (!fbx) { | |||||
| console.error('Failed to convert files to fbx') | |||||
| return | |||||
| } | |||||
| // load the fbx file | |||||
| await viewer.load<IObject3D>({path: 'file.fbx', file: fbx}, { | |||||
| autoCenter: true, | |||||
| autoScale: true, | |||||
| }) | |||||
| viewer.scene.addObject(new HemisphereLight(0xffffff, 0x444444, 2)) | |||||
| // add download button | |||||
| const downloadButton = document.createElement('button') | |||||
| downloadButton.innerText = 'Download .fbx' | |||||
| downloadButton.style.position = 'absolute' | |||||
| downloadButton.style.bottom = '3rem' | |||||
| downloadButton.style.right = '3rem' | |||||
| downloadButton.style.zIndex = '10000' | |||||
| downloadButton.onclick = () => downloadBlob(fbx, 'file.fbx') | |||||
| document.body.appendChild(downloadButton) | |||||
| } | |||||
| _testStart() | |||||
| init().finally(_testFinish) |
| <!DOCTYPE html> | |||||
| <html lang="en"> | |||||
| <head> | |||||
| <meta charset="UTF-8"> | |||||
| <title>FBX Export (Assimp)</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", | |||||
| "@threepipe/plugin-assimpjs": "./../../plugins/assimpjs/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/global-loading.mjs"></script> | |||||
| <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, | |||||
| _testStart, | |||||
| downloadBlob, | |||||
| HemisphereLight, | |||||
| IObject3D, | |||||
| LoadingScreenPlugin, | |||||
| ThreeViewer, | |||||
| } from 'threepipe' | |||||
| import {AssimpJsPlugin} from '@threepipe/plugin-assimpjs' | |||||
| const viewer = new ThreeViewer({ | |||||
| canvas: document.getElementById('mcanvas') as HTMLCanvasElement, | |||||
| msaa: true, | |||||
| plugins: [LoadingScreenPlugin], | |||||
| }) | |||||
| // Export to fbx is done by first exporting to glb and converting that to fbx using AssimpJsPlugin | |||||
| async function init() { | |||||
| const assimp = viewer.addPluginSync(AssimpJsPlugin) | |||||
| await assimp.init() | |||||
| viewer.setEnvironmentMap('https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr') | |||||
| // load a file | |||||
| const result = await viewer.load<IObject3D>('https://threejs.org/examples/models/gltf/DamagedHelmet/glTF/DamagedHelmet.gltf', { | |||||
| autoCenter: true, | |||||
| autoScale: true, | |||||
| }) | |||||
| let fbxBlob: Blob | undefined = undefined | |||||
| let converting = false | |||||
| async function exportFbx() { | |||||
| if (fbxBlob) return fbxBlob | |||||
| if (converting) { | |||||
| console.warn('Already converting, please wait...') | |||||
| return | |||||
| } | |||||
| converting = true | |||||
| // export to glb | |||||
| const blob = await viewer.export(result, { | |||||
| embedUrlImages: true, | |||||
| }) | |||||
| // const blob = await viewer.exportScene(); // its possible to export the whole scene also | |||||
| if (!blob || blob.ext !== 'glb') { | |||||
| alert('Unable to export scene') | |||||
| converting = false | |||||
| return | |||||
| } | |||||
| fbxBlob = assimp.convertFiles({['file.glb']: await blob.arrayBuffer()}, 'fbx') | |||||
| if (!fbxBlob) { | |||||
| alert('Failed to convert glb to fbx') | |||||
| converting = false | |||||
| return | |||||
| } | |||||
| // clear scene | |||||
| viewer.scene.disposeSceneModels() | |||||
| // load a light and fbx file | |||||
| const hemiLight = viewer.scene.addObject(new HemisphereLight(0xffffff, 0x444444, 5), {addToRoot: true}) | |||||
| hemiLight.name = 'Hemisphere Light' | |||||
| await viewer.load({ | |||||
| path: 'file.fbx', | |||||
| file: fbxBlob, | |||||
| }, { | |||||
| autoCenter: true, | |||||
| autoScale: true, | |||||
| }) | |||||
| converting = false | |||||
| return fbxBlob | |||||
| } | |||||
| // add download button | |||||
| const convertButton = document.createElement('button') | |||||
| convertButton.innerText = 'Convert to fbx' | |||||
| convertButton.style.position = 'absolute' | |||||
| convertButton.style.bottom = '6rem' | |||||
| convertButton.style.right = '3rem' | |||||
| convertButton.style.zIndex = '10000' | |||||
| convertButton.onclick = async() => { | |||||
| await exportFbx() | |||||
| } | |||||
| document.body.appendChild(convertButton) | |||||
| const downloadButton = document.createElement('button') | |||||
| downloadButton.innerText = 'Download as .fbx' | |||||
| downloadButton.style.position = 'absolute' | |||||
| downloadButton.style.bottom = '3rem' | |||||
| downloadButton.style.right = '3rem' | |||||
| downloadButton.style.zIndex = '10000' | |||||
| downloadButton.onclick = async() => { | |||||
| await exportFbx() | |||||
| if (fbxBlob) downloadBlob(fbxBlob, 'file.fbx') | |||||
| } | |||||
| document.body.appendChild(downloadButton) | |||||
| } | |||||
| _testStart() | |||||
| init().finally(_testFinish) |
| <li><a href="./extra-importer-plugins/">Extra (3ds, 3mf, collada, amf, bvh, vox, gcode, mdd, pcd, tilt, wrl, ldraw, vtk, xyz) 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> | ||||
| <li><a href="./gltf-meshopt-compression/">glTF MeshOpt Decode (Compression Extension) </a></li> | <li><a href="./gltf-meshopt-compression/">glTF MeshOpt Decode (Compression Extension) </a></li> | ||||
| <li><a href="./gltf-mesh-lines/">glTF Mesh Lines <br/>(Fat Lines) </a></li> | <li><a href="./gltf-mesh-lines/">glTF Mesh Lines <br/>(Fat Lines) </a></li> | ||||
| <li><a href="./assimpjs-plugin/">AssimpJs Plugin </a></li> | |||||
| <li><a href="./b3dm-load/">B3DM Load (3D Tile) </a></li> | <li><a href="./b3dm-load/">B3DM Load (3D Tile) </a></li> | ||||
| <li><a href="./i3dm-load/">I3DM Load (3D Tile) </a></li> | <li><a href="./i3dm-load/">I3DM Load (3D Tile) </a></li> | ||||
| <li><a href="./pnts-load/">PNTS Load (3D Points) </a></li> | <li><a href="./pnts-load/">PNTS Load (3D Points) </a></li> | ||||
| <li><a href="./render-target-export/">EXR, PNG, JPEG, WEBP Export<br/>(Render Target Export) </a></li> | <li><a href="./render-target-export/">EXR, PNG, JPEG, WEBP Export<br/>(Render Target Export) </a></li> | ||||
| <li><a href="./glb-export/">GLB Export </a></li> | <li><a href="./glb-export/">GLB Export </a></li> | ||||
| <li><a href="./glb-draco-export/">GLB (+DRACO) Export </a></li> | <li><a href="./glb-draco-export/">GLB (+DRACO) Export </a></li> | ||||
| <li><a href="./flx-export/">FBX Export (AssimpJs)<br/>(glTF To FBX) </a></li> | |||||
| <li><a href="./pmat-material-export/">PMAT Material Export </a></li> | <li><a href="./pmat-material-export/">PMAT Material Export </a></li> | ||||
| <li><a href="./transfr-share-plugin/">Transfr.one Share Plugin<br/>(Upload, share link) </a></li> | <li><a href="./transfr-share-plugin/">Transfr.one Share Plugin<br/>(Upload, share link) </a></li> | ||||
| </ul> | </ul> |
| { | { | ||||
| "name": "threepipe", | "name": "threepipe", | ||||
| "version": "0.0.45", | |||||
| "version": "0.0.46", | |||||
| "lockfileVersion": 3, | "lockfileVersion": 3, | ||||
| "requires": true, | "requires": true, | ||||
| "packages": { | "packages": { | ||||
| "": { | "": { | ||||
| "name": "threepipe", | "name": "threepipe", | ||||
| "version": "0.0.45", | |||||
| "version": "0.0.46", | |||||
| "license": "Apache-2.0", | "license": "Apache-2.0", | ||||
| "dependencies": { | "dependencies": { | ||||
| "@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.158.1003/package.tgz", | "@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.158.1003/package.tgz", |
| { | { | ||||
| "name": "threepipe", | "name": "threepipe", | ||||
| "version": "0.0.45", | |||||
| "version": "0.0.46", | |||||
| "description": "A modern 3D viewer framework built on top of three.js, written in TypeScript, designed to make creating high-quality, modular, and extensible 3D experiences on the web simple and enjoyable.", | "description": "A modern 3D viewer framework built on top of three.js, written in TypeScript, designed to make creating high-quality, modular, and extensible 3D experiences on the web simple and enjoyable.", | ||||
| "main": "dist/index.js", | "main": "dist/index.js", | ||||
| "module": "dist/index.mjs", | "module": "dist/index.mjs", |
| { | |||||
| "name": "@threepipe/plugin-assimpjs", | |||||
| "version": "0.1.0", | |||||
| "lockfileVersion": 3, | |||||
| "requires": true, | |||||
| "packages": { | |||||
| "": { | |||||
| "name": "@threepipe/plugin-assimpjs", | |||||
| "version": "0.1.0", | |||||
| "license": "Apache-2.0", | |||||
| "dependencies": { | |||||
| "assimpjs": "^0.0.10", | |||||
| "threepipe": "file:./../../src/" | |||||
| }, | |||||
| "devDependencies": {} | |||||
| }, | |||||
| "../../src": {}, | |||||
| "node_modules/assimpjs": { | |||||
| "version": "0.0.10", | |||||
| "resolved": "https://registry.npmjs.org/assimpjs/-/assimpjs-0.0.10.tgz", | |||||
| "integrity": "sha512-iY8M+eQzdCvfSkdduj6sPmIbP2fIn40PK6JRrAMxBawL3tHG6Mm0qvitkxB3ZoFBug5o7IdbzQK+jujZTopGPQ==", | |||||
| "license": "MIT" | |||||
| }, | |||||
| "node_modules/threepipe": { | |||||
| "resolved": "../../src", | |||||
| "link": true | |||||
| } | |||||
| } | |||||
| } |
| { | |||||
| "name": "@threepipe/plugin-assimpjs", | |||||
| "description": "Assimp.js Plugin for ThreePipe", | |||||
| "version": "0.1.0", | |||||
| "devDependencies": { | |||||
| }, | |||||
| "dependencies": { | |||||
| "threepipe": "file:./../../src/", | |||||
| "assimpjs": "^0.0.10" | |||||
| }, | |||||
| "exports": { | |||||
| ".": { | |||||
| "types": "./dist/index.d.ts", | |||||
| "import": "./dist/index.mjs", | |||||
| "require": "./dist/index.js" | |||||
| }, | |||||
| "./dist/": { | |||||
| "import": "./dist/", | |||||
| "require": "./dist/" | |||||
| } | |||||
| }, | |||||
| "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": "git diff --exit-code --name-only HEAD * && npm run prepare && clean-package && npm publish --access public && clean-package restore && git tag $npm_package_name-$npm_package_version", | |||||
| "prepare": "npm run build && npm run docs", | |||||
| "build": "rimraf dist && vite build", | |||||
| "dev": "NODE_ENV=development vite build --watch", | |||||
| "docs": "rimraf docs && npx typedoc" | |||||
| }, | |||||
| "author": "repalash <palash@shaders.app>", | |||||
| "license": "Apache-2.0", | |||||
| "keywords": [ | |||||
| "three", | |||||
| "three.js", | |||||
| "threepipe", | |||||
| "vite", | |||||
| "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", | |||||
| "directory": "plugins/plugin-template-vite" | |||||
| }, | |||||
| "clean-package": { | |||||
| "remove": [ | |||||
| "clean-package", | |||||
| "scripts", | |||||
| "devDependencies", | |||||
| "//", | |||||
| "markdown-to-html" | |||||
| ], | |||||
| "replace": { | |||||
| "dependencies": {}, | |||||
| "peerDependencies": { | |||||
| "threepipe": "^0.0.46" | |||||
| } | |||||
| } | |||||
| } | |||||
| } |
| import {AViewerPluginSync, ThreeViewer, getUrlQueryParam, createScriptFromURL} from 'threepipe' | |||||
| interface AssimpJsInterface{ | |||||
| [key: string]: any | |||||
| } | |||||
| /** | |||||
| * AssimpJsPlugin | |||||
| * | |||||
| * Helper plugin to load the assimp.js library from a CDN and provide a method to convert files using Assimp.js. | |||||
| * | |||||
| * Assimpjs - https://github.com/kovacsv/assimpjs | |||||
| * Fork with a custom build to support fbx export - https://github.com/repalash/assimpjs | |||||
| */ | |||||
| export class AssimpJsPlugin extends AViewerPluginSync { | |||||
| public static readonly PluginType: string = 'SamplePlugin' | |||||
| enabled = true | |||||
| dependencies = [] | |||||
| // public static LIBRARY_PATH = `https://cdn.jsdelivr.net/npm/assimpjs@${getUrlQueryParam('assimpjs', '0.0.10')}/` | |||||
| // adds fbx export support | |||||
| public static LIBRARY_PATH = `https://cdn.jsdelivr.net/gh/repalash/assimpjs@${getUrlQueryParam('assimpjs', 'main')}/` | |||||
| constructor() { | |||||
| super() | |||||
| } | |||||
| protected _scriptElement?: HTMLScriptElement | |||||
| private _initing: Promise<void>|undefined | |||||
| async init() { | |||||
| if (!this._initing) this._initing = this._init() | |||||
| await this._initing | |||||
| return this.ajs | |||||
| } | |||||
| private async _init() { | |||||
| if (!(window as any).assimpjs) { | |||||
| this._scriptElement = await createScriptFromURL(AssimpJsPlugin.LIBRARY_PATH + 'dist/assimpjs.js') | |||||
| } | |||||
| const ctor = (window as any).assimpjs | |||||
| const ajs = ctor ? await ctor({ | |||||
| locateFile: (file: string) => AssimpJsPlugin.LIBRARY_PATH + 'dist/' + file, | |||||
| // print: (text: string) => console.log(text), | |||||
| // printErr: (text: string) => console.error(text), | |||||
| // onRuntimeInitialized: () => { | |||||
| // console.log('Assimp.js initialized') | |||||
| // this.viewer?.emit('assimpjs-initialized', ajs) | |||||
| // }, | |||||
| // noExitRuntime: true, | |||||
| }) : null | |||||
| if (!ajs) { | |||||
| this._initing = undefined | |||||
| this._scriptElement?.remove() | |||||
| throw new Error('Failed to load Assimp.js library') | |||||
| } | |||||
| this.ajs = ajs | |||||
| } | |||||
| ajs?: AssimpJsInterface | |||||
| initOnAdd = true | |||||
| onAdded(viewer: ThreeViewer) { | |||||
| super.onAdded(viewer) | |||||
| if (this.initOnAdd) this.init() | |||||
| } | |||||
| // todo add ui config to export the scene, selected object as fbx or glb2 etc. or interface with the AssetExporter. | |||||
| convertFiles(files: Record<string, ArrayBuffer>, format: 'fbx'|'gltf2'|'glb2'|'assjson' = 'glb2') { | |||||
| const ajs = this.ajs | |||||
| if (!ajs) { | |||||
| console.error('Assimp.js is not initialized, wait for the promise like - `await assimpPlugin.init()`') | |||||
| return | |||||
| } | |||||
| const fileList = new ajs.FileList() | |||||
| for (const [name, content] of Object.entries(files)) { | |||||
| fileList.AddFile(name, new Uint8Array(content)) | |||||
| } | |||||
| // convert file list to assimp json | |||||
| const result = ajs.ConvertFileList(fileList, format) | |||||
| // check if the conversion succeeded | |||||
| if (!result.IsSuccess() || result.FileCount() == 0) { | |||||
| // resultDiv.innerHTML = result.GetErrorCode() | |||||
| console.error(result.GetErrorCode()) | |||||
| console.error(result) | |||||
| return | |||||
| } | |||||
| // get the result file, and convert to blob | |||||
| const resultFile = result.GetFile(0) | |||||
| const blob = new Blob([resultFile.GetContent()], {type: 'application/octet-stream'}) | |||||
| return blob | |||||
| } | |||||
| } |
| 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 | |||||
| } | |||||
| declare module '*.css?inline' { // for vite | |||||
| const content: string | |||||
| export default content | |||||
| } | |||||
| // export {} | |||||
| // hack for typedoc | |||||
| // eslint-disable-next-line @typescript-eslint/naming-convention | |||||
| // declare type OffscreenCanvas = HTMLCanvasElement |
| export {AssimpJsPlugin} from './AssimpJsPlugin' |
| { | |||||
| "compilerOptions": { | |||||
| "baseUrl": "./src", | |||||
| "rootDir": "./src", | |||||
| "allowJs": true, | |||||
| "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": "ES2021", | |||||
| "strictNullChecks": true, | |||||
| "lib": [ | |||||
| "es2020", | |||||
| "esnext", | |||||
| "dom" | |||||
| ] | |||||
| }, | |||||
| "include": [ | |||||
| "src/**/*" | |||||
| ], | |||||
| "exclude": [ | |||||
| "node_modules", | |||||
| "**/*.spec.ts", | |||||
| "dist" | |||||
| ] | |||||
| } |
| { | |||||
| "extends": [ | |||||
| "../../typedoc.json" | |||||
| ], | |||||
| "entryPoints": [ | |||||
| "src/index.ts" | |||||
| ], | |||||
| "name": "Threepipe Assimpjs Plugin", | |||||
| "readme": "none" | |||||
| } |
| import {defineConfig} from 'vite' | |||||
| import json from '@rollup/plugin-json'; | |||||
| import dts from 'vite-plugin-dts' | |||||
| import packageJson from './package.json'; | |||||
| import license from 'rollup-plugin-license'; | |||||
| import replace from '@rollup/plugin-replace'; | |||||
| import glsl from 'rollup-plugin-glsl'; | |||||
| import path from 'node:path'; | |||||
| const isProd = process.env.NODE_ENV === 'production' | |||||
| const { name, version, author } = packageJson | |||||
| const {main, module, browser} = packageJson | |||||
| const globals = { | |||||
| 'three': 'threepipe', // just incase someone uses three | |||||
| 'threepipe': 'threepipe', | |||||
| } | |||||
| export default defineConfig({ | |||||
| optimizeDeps: { | |||||
| exclude: ['uiconfig.js', 'ts-browser-helpers'], | |||||
| }, | |||||
| base: '', | |||||
| // define: { | |||||
| // 'process.env': process.env | |||||
| // }, | |||||
| build: { | |||||
| sourcemap: true, | |||||
| minify: false, | |||||
| cssMinify: isProd, | |||||
| cssCodeSplit: false, | |||||
| watch: !isProd ? { | |||||
| buildDelay: 1000, | |||||
| } : null, | |||||
| lib: { | |||||
| entry: 'src/index.ts', | |||||
| formats: isProd ? ['es', 'umd'] : ['es'], | |||||
| name: name, | |||||
| fileName: (format) => (format === 'umd' ? main : module).replace('dist/', ''), | |||||
| }, | |||||
| outDir: 'dist', | |||||
| emptyOutDir: isProd, | |||||
| commonjsOptions: { | |||||
| exclude: [/uiconfig.js/, /ts-browser-helpers/], | |||||
| }, | |||||
| rollupOptions: { | |||||
| output: { | |||||
| // inlineDynamicImports: false, | |||||
| globals, | |||||
| }, | |||||
| external: Object.keys(globals), | |||||
| }, | |||||
| }, | |||||
| plugins: [ | |||||
| isProd ? dts({tsconfigPath: './tsconfig.json'}) : null, | |||||
| replace({ | |||||
| 'from \'three\'': 'from \'threepipe\'', | |||||
| delimiters: ['', ''], | |||||
| }), | |||||
| replace({ | |||||
| 'process.env.NODE_ENV': JSON.stringify(isProd ? 'production' : 'development'), | |||||
| preventAssignment: true, | |||||
| }), | |||||
| glsl({ // todo: minify glsl. | |||||
| include: 'src/**/*.glsl', | |||||
| }), | |||||
| json(), | |||||
| // 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` | |||||
| // }), | |||||
| license({ | |||||
| banner: ` | |||||
| @license | |||||
| ${name} v${version} | |||||
| Copyright 2022<%= moment().format('YYYY') > 2022 ? '-' + moment().format('YYYY') : null %> ${author} | |||||
| ${packageJson.license} License | |||||
| See ./dependencies.txt for any bundled third-party dependencies and licenses. | |||||
| `, | |||||
| thirdParty: { | |||||
| output: path.join(__dirname, 'dist', 'dependencies.txt'), | |||||
| includePrivate: true, // Default is false. | |||||
| }, | |||||
| }), | |||||
| ], | |||||
| }) |
| export const VERSION = '0.0.45' | |||||
| export const VERSION = '0.0.46' |
| {text: 'Blend Importer Plugin', link: 'package/plugin-blend-importer'}, | {text: 'Blend Importer Plugin', link: 'package/plugin-blend-importer'}, | ||||
| {text: 'Gaussian Splatting Plugin', link: 'package/plugin-gaussian-splatting'}, | {text: 'Gaussian Splatting Plugin', link: 'package/plugin-gaussian-splatting'}, | ||||
| {text: 'svg-renderer Plugin', link: 'package/plugin-svg-renderer'}, | {text: 'svg-renderer Plugin', link: 'package/plugin-svg-renderer'}, | ||||
| {text: 'Tiles (OGC) Renderer Plugin', link: 'package/plugin-3d-tiles-renderer'}, | |||||
| {text: '3D Tiles (OGC) Renderer Plugin', link: 'package/plugin-3d-tiles-renderer'}, | |||||
| {text: 'Assimpjs Plugin', link: 'package/plugin-assimpjs'}, | |||||
| ] | ] | ||||
| }, | }, | ||||
| ], | ], |
| ## List of all the packages | ## List of all the packages | ||||
| - [@threepipe/webgi-plugins](https://webgi.dev) - Web [Global Illumination](https://en.wikipedia.org/wiki/Global_illumination) - Realistic rendering plugin pack (SSR, SSRTAO, HDR Bloom, TAA, Depth of Field, SSGI, etc.) | |||||
| - [@threepipe/plugin-tweakpane](../package/plugin-tweakpane) Tweakpane UI Plugin. Renders a [tweakpane](https://tweakpane.github.io/docs/) UI attached to the viewer for any ui config object. | - [@threepipe/plugin-tweakpane](../package/plugin-tweakpane) Tweakpane UI Plugin. Renders a [tweakpane](https://tweakpane.github.io/docs/) UI attached to the viewer for any ui config object. | ||||
| - [@threepipe/plugin-blueprintjs](../package/plugin-blueprintjs) BlueprintJs UI Plugin. Renders a [blueprintjs](https://blueprintjs.com/) ([React](https://react.dev/)) UI attached to the viewer for any ui config object. | - [@threepipe/plugin-blueprintjs](../package/plugin-blueprintjs) BlueprintJs UI Plugin. Renders a [blueprintjs](https://blueprintjs.com/) ([React](https://react.dev/)) UI attached to the viewer for any ui config object. | ||||
| - [@threepipe/plugin-tweakpane-editor](../package/plugin-tweakpane-editor) - Tweakpane Editor Plugin. Uses the tweakpane ui plugin to create a [full editor](https://threepipe.org/examples/tweakpane-editor). | - [@threepipe/plugin-tweakpane-editor](../package/plugin-tweakpane-editor) - Tweakpane Editor Plugin. Uses the tweakpane ui plugin to create a [full editor](https://threepipe.org/examples/tweakpane-editor). | ||||
| - [@threepipe/plugin-gaussian-splatting](../package/plugin-gaussian-splatting) - [3D Gaussian Splatting](https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/) plugin for loading and rendering splat files | - [@threepipe/plugin-gaussian-splatting](../package/plugin-gaussian-splatting) - [3D Gaussian Splatting](https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/) plugin for loading and rendering splat files | ||||
| - [@threepipe/plugin-svg-renderer](../package/plugin-svg-renderer) - Add support for exporting 3d scene as SVG (WIP) using [three-svg-renderer](https://www.npmjs.com/package/three-svg-renderer). | - [@threepipe/plugin-svg-renderer](../package/plugin-svg-renderer) - Add support for exporting 3d scene as SVG (WIP) using [three-svg-renderer](https://www.npmjs.com/package/three-svg-renderer). | ||||
| - [@threepipe/plugin-3d-tiles-renderer](https://threepipe.org/package/plugin-3d-tiles-renderer.html) - Plugins for [3d-tiles-renderer](https://github.com/NASA-AMMOS/3DTilesRendererJS), b3dm, i3dm, cmpt, pnts importers. | - [@threepipe/plugin-3d-tiles-renderer](https://threepipe.org/package/plugin-3d-tiles-renderer.html) - Plugins for [3d-tiles-renderer](https://github.com/NASA-AMMOS/3DTilesRendererJS), b3dm, i3dm, cmpt, pnts importers. | ||||
| - [@threepipe/webgi-plugins](https://webgi.dev) - Web [Global Illumination](https://en.wikipedia.org/wiki/Global_illumination) - Realistic rendering plugin pack (SSR, SSRTAO, HDR Bloom, TAA, Depth of Field, SSGI, etc.) | |||||
| - [@threepipe/plugin-assimpjs](https://threepipe.org/package/plugin-assimpjs.html) - Plugin and helpers to load and use [assimpjs](https://github.com/kovacsv/assimpjs) (with fbx, other exporters) in the browser. |
| text: '@threepipe/plugin-svg-renderer' | text: '@threepipe/plugin-svg-renderer' | ||||
| link: './plugin-svg-renderer' | link: './plugin-svg-renderer' | ||||
| next: false | |||||
| next: | |||||
| text: '@threepipe/plugin-assimpjs' | |||||
| link: './plugin-assimpjs' | |||||
| --- | --- | ||||
| # @threepipe/plugin-3d-tiles-renderer | # @threepipe/plugin-3d-tiles-renderer |
| --- | |||||
| prev: | |||||
| text: '@threepipe/plugin-3d-tiles-renderer' | |||||
| link: './plugin-3d-tiles-renderer' | |||||
| next: false | |||||
| --- | |||||
| # @threepipe/plugin-assimpjs | |||||
| This package exports [AssimpJsPlugin](https://threepipe.org/plugins/assimpjs/docs/classes/AssimpJsPlugin.html) which loads the assimpjs library and provides `ajs` interface. | |||||
| [Example](https://threepipe.org/examples/#assimpjs-plugin/) — | |||||
| [Source Code](https://github.com/repalash/threepipe/blob/master/plugins/assimpjs/src/index.ts) — | |||||
| [API Reference](https://threepipe.org/plugins/assimpjs/docs) | |||||
| [](https://www.npmjs.com/package/@threepipe/plugin-assimpjs) | |||||
| ```bash | |||||
| npm install @threepipe/plugin-assimpjs | |||||
| ``` | |||||
| ## Sample Usage | |||||
| ### Load and render tileset | |||||
| To import a tileset, simply add the `TilesRendererPlugin` and load the root json with the plugin or the viewer. | |||||
| The near, far plane of the camera can be set based on the file. | |||||
| ```typescript | |||||
| import {ThreeViewer} from 'threepipe' | |||||
| import {TilesRendererPlugin, TilesRendererGroup} from '@threepipe/plugin-assimpjs' | |||||
| const viewer = new ThreeViewer({...}) | |||||
| const tiles = viewer.addPluginSync(TilesRendererPlugin) | |||||
| viewer.scene.mainCamera.position.set(300, 300, 300) | |||||
| // optional. (Required for GlobeControls) | |||||
| viewer.scene.mainCamera.autoNearFar = false | |||||
| viewer.scene.mainCamera.minNearPlane = 1 | |||||
| viewer.scene.mainCamera.maxFarPlane = 1000 | |||||
| // Now load any tileset json file. | |||||
| const group = await tiles.load('https://raw.githubusercontent.com/NASA-AMMOS/3DTilesRendererJS/c7a9a7f7607e8759d16c26fb83815ad1cd1fd865/example/data/tileset.json', { | |||||
| autoScale: true, | |||||
| autoCenter: true, | |||||
| autoScaleRadius: 100, | |||||
| }) | |||||
| // or load directly from the viewer. A custom fileExtension or fileHandler must be passed, to tell the viewer the type of the json file. | |||||
| const group1 = await viewer.load<TilesRendererGroup>('https://raw.githubusercontent.com/NASA-AMMOS/3DTilesRendererJS/c7a9a7f7607e8759d16c26fb83815ad1cd1fd865/example/data/tileset.json', { | |||||
| fileExtension: TilesRendererPlugin.DUMMY_EXT, | |||||
| autoScale: true, | |||||
| autoCenter: true, | |||||
| autoScaleRadius: 100, | |||||
| }) | |||||
| ``` | |||||
| Check the [assimpjs](https://threepipe.com/examples/#assimpjs/), [ogc-tiles-mars](https://threepipe.com/examples/#ogc-tiles-mars/) examples for a live demo. | |||||
| ### Use `EnvironmentControls` with `TilesRendererPlugin` | |||||
| ```typescript | |||||
| import {TilesRendererPlugin, TilesRendererGroup, EnvironmentControlsPlugin, EnvironmentControls2, GlobeControlsPlugin, GlobeControls2} from '@threepipe/plugin-assimpjs' | |||||
| const viewer = new ThreeViewer({...}) | |||||
| const tiles = viewer.addPluginSync(TilesRendererPlugin) | |||||
| const group = await tiles.load('...') | |||||
| viewer.addPluginSync(EnvironmentControlsPlugin) | |||||
| viewer.addPluginSync(GlobeControlsPlugin) | |||||
| viewer.scene.mainCamera.controlsMode = 'environment' | |||||
| viewer.scene.mainCamera.lookAt(0, 0, 0) | |||||
| let controls = viewer.scene.mainCamera.controls as EnvironmentControls2 | |||||
| controls.minDistance = 0.25; | |||||
| // For globe controls | |||||
| viewer.scene.mainCamera.controlsMode = 'globe' | |||||
| viewer.scene.mainCamera.lookAt(0, 0, 0) | |||||
| controls = viewer.scene.mainCamera.controls as GlobeControls2 | |||||
| // optional. (Required for GlobeControls) | |||||
| controls.setTilesRenderer(group.tilesRenderer) | |||||
| ``` | |||||
| ### Additional `TilesRenderer` Plugins | |||||
| Some plugins are used by default in the `TilesRendererPlugin` to load and render the tileset. These can be disabled/configured when loading a file and more can be added. | |||||
| Custom plugins can be added to the individual `TilesRenderer` when loading a tileset file. | |||||
| ```typescript | |||||
| import {UnloadTilesPlugin, TileCompressionPlugin} from '@threepipe/plugin-assimpjs' | |||||
| const result = await tiles.load('url', { | |||||
| autoCenter: true, | |||||
| autoScale: false, | |||||
| tiles: { | |||||
| TilesFadePlugin: { | |||||
| fadeDuration: 0.5, | |||||
| }, | |||||
| plugins: [ | |||||
| ()=>new UnloadTilesPlugin(), | |||||
| ()=>new TileCompressionPlugin(), | |||||
| ], | |||||
| }, | |||||
| }) | |||||
| ``` | |||||
| ### Loading Cesium Ion Assets | |||||
| Cesium Ion assets like Google Maps can be loaded with the `loadCesiumIon` function in the plugin, or by passing a custom plugin in the viewer. | |||||
| ```typescript | |||||
| const tiles = viewer.getPlugin(TilesRendererPlugin) | |||||
| const result = await tiles.loadCesiumIon({ | |||||
| assetId: '2275207', | |||||
| apiToken: CESIUM_ION_API_TOKEN, | |||||
| autoRefreshToken: true, | |||||
| }, { | |||||
| autoCenter: false, | |||||
| // more options | |||||
| tiles: { | |||||
| TilesFadePlugin: true, | |||||
| plugins: [ | |||||
| ()=>new TileCompressionPlugin(), | |||||
| ()=>new UnloadTilesPlugin(), | |||||
| ], | |||||
| }, | |||||
| }) | |||||
| // or | |||||
| const result2 = await viewer.load('file.tileset', { | |||||
| tiles: { | |||||
| CesiumIonAuthPlugin: { | |||||
| assetId: '2275207', | |||||
| apiToken: CESIUM_ION_API_TOKEN, | |||||
| autoRefreshToken: true, | |||||
| }, | |||||
| TilesFadePlugin: true, | |||||
| plugins: [ | |||||
| ()=>new TileCompressionPlugin(), | |||||
| ()=>new UnloadTilesPlugin(), | |||||
| ], | |||||
| }, | |||||
| }) | |||||
| ``` | |||||
| Note - `TilesRendererPlugin.DUMMY_EXT` = `tileset` | |||||
| :::info | |||||
| Get the `CESIUM_ION_API_TOKEN` for free from [cesium ion](https://ion.cesium.com/) | |||||
| ::: | |||||
| Check the Google Maps examples - [ogc-tiles-google-maps](https://threepipe.com/examples/#ogc-tiles-google-maps/), [ogc-tiles-google-maps-3d](https://threepipe.com/examples/#ogc-tiles-google-maps-3d/) examples for sample usage | |||||
| ### Loading 3d tiles files | |||||
| To load any individual tile file format, add the plugin to the viewer and load the file directly as you would with any other file. The plugin will automatically detect the type of the file and load it. | |||||
| ```typescript | |||||
| import {ThreeViewer} from 'threepipe' | |||||
| import {B3DMLoadPlugin, CMPTLoadPlugin, I3DMLoadPlugin, PNTSLoadPlugin} from '@threepipe/plugin-assimpjs' | |||||
| const viewer = new ThreeViewer({...}) | |||||
| viewer.addPluginsSync([B3DMLoadPlugin, CMPTLoadPlugin, I3DMLoadPlugin, PNTSLoadPlugin, LoadingScreenPlugin]) | |||||
| // Now load any file | |||||
| const b3dm = await viewer.load<IObject3D>('https://example.com/file.b3dm') | |||||
| const cmpt = await viewer.load<IObject3D>('https://example.com/file.cmpt') | |||||
| const i3dm = await viewer.load<IObject3D>('https://example.com/file.i3dm') | |||||
| const pnts = await viewer.load<IObject3D>('https://example.com/file.pnts') | |||||
| // Load file by data url | |||||
| const model = await viewer.load<IObject3D>('data:application/octet-stream;base64,...', { | |||||
| fileExtension: 'b3dm', | |||||
| }) | |||||
| // or by using `model/<extension>` mime type | |||||
| const model2 = await viewer.load<IObject3D>('data:model/b3dm;base64,...') | |||||
| ``` | |||||
| The asset importer will automatically detect the type of the file and load it. | |||||
| Checkout the examples [b3dm-load](https://threepipe.org/examples/#b3dm-load/), | |||||
| [cmpt-load](https://threepipe.org/examples/#cmpt-load/), | |||||
| [pnts-load](https://threepipe.org/examples/#pnts-load/), | |||||
| [i3dm-load](https://threepipe.org/examples/#i3dm-load/) for more details. | |||||
| ### Loading Image tiles | |||||
| The package exports plugins `DeepZoomImageLoadPlugin` and `SlippyMapTilesLoadPlugin` to load deep zoom images and slippy map tiles respectively. | |||||
| They add and use the `TilesRendererPlugin` automatically. | |||||
| The plugins can be added to the viewer and files can be loaded directly from the viewer or asset manager. | |||||
| ```typescript | |||||
| import {ThreeViewer} from 'threepipe' | |||||
| import {TilesRendererPlugin, DeepZoomImageLoadPlugin, SlippyMapTilesLoadPlugin} from '@threepipe/plugin-assimpjs' | |||||
| const viewer = new ThreeViewer({...}) | |||||
| viewer.addPluginsSync([TilesRendererPlugin, DeepZoomImageLoadPlugin, SlippyMapTilesLoadPlugin]) | |||||
| // Load deep zoom image | |||||
| const result = await viewer.load('https://openseadragon.github.io/example-images/duomo/duomo.dzi', { | |||||
| autoCenter: true, | |||||
| autoScale: true, | |||||
| autoScaleRadius: 30, | |||||
| tiles: { | |||||
| DeepZoomImagePlugin: { | |||||
| center: true | |||||
| }, | |||||
| errorTarget: 1, | |||||
| } | |||||
| }) | |||||
| const result2 = await viewer.load('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { | |||||
| autoCenter: true, | |||||
| autoScale: true, | |||||
| autoScaleRadius: 30, | |||||
| fileExtension: SlippyMapTilesLoadPlugin.DUMMY_EXT, | |||||
| tiles: { | |||||
| errorTarget: 1, | |||||
| XYZTilesPlugin: { | |||||
| projection: 'planar', | |||||
| center: true | |||||
| }, | |||||
| } | |||||
| }) | |||||
| ``` | |||||
| Checkout the examples [dzi-load](https://threepipe.org/examples/#dzi-load/), | |||||
| [slippy-map-tiles](https://threepipe.org/examples/#slippy-map-tiles/) for a demo. |