| viewer.addPluginSync(Rhino3dmLoadPlugin) | viewer.addPluginSync(Rhino3dmLoadPlugin) | ||||
| // load obj + mtl | |||||
| // load a 3dm file | |||||
| const result = await viewer.load<IObject3D>('https://threejs.org/examples/models/3dm/Rhino_Logo.3dm', { | const result = await viewer.load<IObject3D>('https://threejs.org/examples/models/3dm/Rhino_Logo.3dm', { | ||||
| autoCenter: true, | autoCenter: true, | ||||
| autoScale: true, | autoScale: true, | ||||
| }) | }) | ||||
| // export to glb | // export to glb | ||||
| const blob = await viewer.assetManager.exporter.exportObject(result) | |||||
| const blob = await viewer.export(result) | |||||
| // const blob = await viewer.exportScene(); // its possible to export the whole scene also | // const blob = await viewer.exportScene(); // its possible to export the whole scene also | ||||
| if (!blob || blob.ext !== 'glb') { | if (!blob || blob.ext !== 'glb') { |
| <html lang="en"> | <html lang="en"> | ||||
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>HDR Load</title> | |||||
| <title>EXR Load</title> | |||||
| <!-- 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> |
| } | } | ||||
| const mesh = helmet.getObjectByName('node_damagedHelmet_-6514')! | const mesh = helmet.getObjectByName('node_damagedHelmet_-6514')! | ||||
| // const blob = await viewer.assetManager.exporter.exportObject(helmetObject, {exportExt: 'glb'}) | |||||
| // const blob = await viewer.export(helmetObject, {exportExt: 'glb'}) | |||||
| // const blob = await viewer.exportScene({viewerConfig: false}) // export scene without viewer config | // const blob = await viewer.exportScene({viewerConfig: false}) // export scene without viewer config | ||||
| // const blob = await viewer.exportScene() // export scene with viewer config and default settings. | // const blob = await viewer.exportScene() // export scene with viewer config and default settings. | ||||
| createSimpleButtons({ | createSimpleButtons({ | ||||
| ['Download Helmet Object GLB']: async() => { | ['Download Helmet Object GLB']: async() => { | ||||
| const blob = await viewer.assetManager.exporter.exportObject(mesh, { | |||||
| const blob = await viewer.export(mesh, { | |||||
| exportExt: 'glb', | exportExt: 'glb', | ||||
| embedUrlImages: true, // embed images in glb even when url is available. | embedUrlImages: true, // embed images in glb even when url is available. | ||||
| }) | }) | ||||
| downloadBlob(blob, 'helmet.' + blob.ext) | downloadBlob(blob, 'helmet.' + blob.ext) | ||||
| }, | }, | ||||
| ['Download Helmet Material']: async() => { | ['Download Helmet Material']: async() => { | ||||
| const blob = await viewer.assetManager.exporter.exportObject(<IMaterial>mesh.material) | |||||
| const blob = await viewer.export(<IMaterial>mesh.material) | |||||
| if (!blob) { | if (!blob) { | ||||
| alert('Unable to export helmet material') | alert('Unable to export helmet material') | ||||
| return | return |
| <!DOCTYPE html> | |||||
| <html lang="en"> | |||||
| <head> | |||||
| <meta charset="UTF-8"> | |||||
| <title>HDR To EXR</title> | |||||
| <!-- 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, downloadBlob, IAsset, ITexture, ThreeViewer} from 'threepipe' | |||||
| const viewer = new ThreeViewer({canvas: document.getElementById('mcanvas') as HTMLCanvasElement}) | |||||
| async function init() { | |||||
| // import a hdr file | |||||
| const dataTexture = await viewer.import<ITexture>('https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr') | |||||
| if (!dataTexture) { | |||||
| console.error('Unable to import texture') | |||||
| return | |||||
| } | |||||
| // export as exr | |||||
| const blob = await viewer.export(dataTexture, {exportExt: 'exr'}) | |||||
| if (!blob || blob.ext !== 'exr') { | |||||
| console.error('Unable to export texture', blob) | |||||
| return | |||||
| } | |||||
| // load the exr as environment map | |||||
| const map = await viewer.setEnvironmentMap({ | |||||
| path: 'file.exr', | |||||
| file: blob, | |||||
| } as IAsset) | |||||
| if (!map) { | |||||
| console.error('Unable to load exr') | |||||
| return | |||||
| } | |||||
| viewer.scene.background = map | |||||
| // add download button | |||||
| const downloadButton = document.createElement('button') | |||||
| downloadButton.innerText = 'Download .exr' | |||||
| downloadButton.style.position = 'absolute' | |||||
| downloadButton.style.bottom = '3rem' | |||||
| downloadButton.style.right = '3rem' | |||||
| downloadButton.style.zIndex = '10000' | |||||
| downloadButton.onclick = () => downloadBlob(blob, 'file.exr') | |||||
| document.body.appendChild(downloadButton) | |||||
| } | |||||
| init().then(_testFinish) |
| <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> | ||||
| <li><a href="./hdr-to-exr/">Convert HDR to EXR </a></li> | |||||
| </ul> | </ul> | ||||
| <h2 class="category">Tests</h2> | <h2 class="category">Tests</h2> | ||||
| <ul> | <ul> |
| // todo wait for images to load | // todo wait for images to load | ||||
| // export to glb | // export to glb | ||||
| const blob = await viewer.assetManager.exporter.exportObject(result) | |||||
| const blob = await viewer.export(result) | |||||
| // const blob = await viewer.exportScene(); // its possible to export the whole scene also | // const blob = await viewer.exportScene(); // its possible to export the whole scene also | ||||
| if (!blob || blob.ext !== 'glb') { | if (!blob || blob.ext !== 'glb') { |
| sphere.position.setX(2) | sphere.position.setX(2) | ||||
| await viewer.addSceneObject(sphere) | await viewer.addSceneObject(sphere) | ||||
| const matBlob = await viewer.assetManager.exporter.exportObject(material) | |||||
| if (!matBlob) { | |||||
| return | |||||
| } | |||||
| const matBlob = await viewer.export(material) | |||||
| if (!matBlob) return | |||||
| const material2 = await viewer.assetManager.importer.importSingle<IMaterial>({file: matBlob, path: 'mat.' + matBlob.ext}) | const material2 = await viewer.assetManager.importer.importSingle<IMaterial>({file: matBlob, path: 'mat.' + matBlob.ext}) | ||||
| if (!material2) { | if (!material2) { | ||||
| return | return | ||||
| createSimpleButtons({ | createSimpleButtons({ | ||||
| ['Download PMAT']: async() => { | ['Download PMAT']: async() => { | ||||
| const blob = await viewer.assetManager.exporter.exportObject(material) | |||||
| const blob = await viewer.export(material) | |||||
| if (!blob) { | if (!blob) { | ||||
| alert('Unable to export material') | alert('Unable to export material') | ||||
| return | return |
| import {BaseEvent, EventDispatcher, WebGLRenderTarget} from 'three' | import {BaseEvent, EventDispatcher, WebGLRenderTarget} from 'three' | ||||
| import {IMaterial, IObject3D, ITexture} from '../core' | import {IMaterial, IObject3D, ITexture} from '../core' | ||||
| import {AnyOptions} from 'ts-browser-helpers' | |||||
| import {BlobExt, ExportFileOptions, IAssetExporter, IExporter, IExportParser} from './IExporter' | import {BlobExt, ExportFileOptions, IAssetExporter, IExporter, IExportParser} from './IExporter' | ||||
| import {EXRExporter2, SimpleJSONExporter, SimpleTextExporter} from './export' | import {EXRExporter2, SimpleJSONExporter, SimpleTextExporter} from './export' | ||||
| import {IRenderTarget} from '../rendering' | import {IRenderTarget} from '../rendering' | ||||
| return this._cachedParsers.find(e => e.ext.includes(ext))?.parser ?? this._createParser(ext) | return this._cachedParsers.find(e => e.ext.includes(ext))?.parser ?? this._createParser(ext) | ||||
| } | } | ||||
| public async processBeforeExport(obj: IObject3D|IMaterial|ITexture|IRenderTarget, _: AnyOptions = {}): Promise<{obj:any, ext:string, typeExt?:string, blob?: BlobExt}|undefined> { | |||||
| public async processBeforeExport(obj: IObject3D|IMaterial|ITexture|IRenderTarget, options: ExportFileOptions = {}): Promise<{obj:any, ext:string, typeExt?:string, blob?: BlobExt}|undefined> { | |||||
| // if (obj.assetExporterProcessed && !options.forceExporterReprocess) return obj //todo;;; | // if (obj.assetExporterProcessed && !options.forceExporterReprocess) return obj //todo;;; | ||||
| switch (obj.assetType) { | switch (obj.assetType) { | ||||
| case 'material': | case 'material': | ||||
| return {obj: (obj as IMaterial).toJSON(), ext: (obj as IMaterial).constructor?.TypeSlug || 'json', typeExt: 'json'} | return {obj: (obj as IMaterial).toJSON(), ext: (obj as IMaterial).constructor?.TypeSlug || 'json', typeExt: 'json'} | ||||
| case 'texture': | case 'texture': | ||||
| return {obj: (obj as ITexture).toJSON(), ext: 'json'} | |||||
| return options.exportExt ? {obj, ext: options.exportExt} : {obj: (obj as ITexture).toJSON(), ext: 'json'} | |||||
| case 'renderTarget': | case 'renderTarget': | ||||
| if (obj.isWebGLMultipleRenderTargets) console.error('AssetExporter: WebGLMultipleRenderTargets export not supported') | if (obj.isWebGLMultipleRenderTargets) console.error('AssetExporter: WebGLMultipleRenderTargets export not supported') | ||||
| else if (!obj.renderManager) return {obj, ext: 'exr'} | else if (!obj.renderManager) return {obj, ext: 'exr'} |
| import {WebGLRenderTarget} from 'three' | |||||
| import {DataTexture, WebGLRenderTarget} from 'three' | |||||
| import {EXRExporter, EXRExporterParseOptions} from 'three/examples/jsm/exporters/EXRExporter.js' | import {EXRExporter, EXRExporterParseOptions} from 'three/examples/jsm/exporters/EXRExporter.js' | ||||
| import {IExportParser} from '../IExporter' | import {IExportParser} from '../IExporter' | ||||
| import {IRenderTarget} from '../../rendering' | import {IRenderTarget} from '../../rendering' | ||||
| export class EXRExporter2 extends EXRExporter implements IExportParser { | export class EXRExporter2 extends EXRExporter implements IExportParser { | ||||
| async parseAsync(obj: IRenderTarget, options: EXRExporterParseOptions): Promise<Blob> { | |||||
| if (!obj.renderManager) throw new Error('No renderManager on renderTarget') | |||||
| if (obj.isWebGLMultipleRenderTargets) throw new Error('WebGLMultipleRenderTargets not supported') | |||||
| const res = this.parse(obj.renderManager.webglRenderer, obj as any as WebGLRenderTarget, options) | |||||
| async parseAsync(obj: IRenderTarget|DataTexture, options: EXRExporterParseOptions): Promise<Blob> { | |||||
| const target = <IRenderTarget>obj | |||||
| if (target.isWebGLRenderTarget && !target.renderManager) throw new Error('No renderManager on renderTarget') | |||||
| if (!target.isWebGLRenderTarget && !(<DataTexture>obj).isDataTexture) throw new Error('Invalid object type') | |||||
| if (target.isWebGLMultipleRenderTargets) throw new Error('WebGLMultipleRenderTargets not supported') | |||||
| const res = target.isWebGLRenderTarget ? | |||||
| this.parse(target.renderManager!.webglRenderer, <WebGLRenderTarget>target, options) : | |||||
| this.parse(undefined, <DataTexture>obj, options) | |||||
| return new Blob([res], {type: 'image/x-exr'}) | return new Blob([res], {type: 'image/x-exr'}) | ||||
| } | } | ||||
| } | } |
| Vector4, | Vector4, | ||||
| } from 'three' | } from 'three' | ||||
| import type {AssetImporter, AssetManager, MaterialManager} from '../assetmanager' | import type {AssetImporter, AssetManager, MaterialManager} from '../assetmanager' | ||||
| import {IAssetImporter} from '../assetmanager' | |||||
| import {BlobExt, IAssetImporter} from '../assetmanager' | |||||
| import {ThreeViewer} from '../viewer' | import {ThreeViewer} from '../viewer' | ||||
| import {ITexture} from '../core' | import {ITexture} from '../core' | ||||
| import {IRenderTarget, RenderManager} from '../rendering' | import {IRenderTarget, RenderManager} from '../rendering' | ||||
| }, // clear context even if its present in resources | }, // clear context even if its present in resources | ||||
| } | } | ||||
| } | } | ||||
| export function jsonToBlob(json: any): BlobExt { | |||||
| const b = new Blob([JSON.stringify(json)], {type: 'application/json'}) as BlobExt | |||||
| b.ext = 'json' | |||||
| return b | |||||
| } |
| import { | import { | ||||
| AddObjectOptions, | AddObjectOptions, | ||||
| IAnimationLoopEvent, | IAnimationLoopEvent, | ||||
| IMaterial, | |||||
| IObject3D, | IObject3D, | ||||
| IObjectProcessor, | IObjectProcessor, | ||||
| ITexture, | ITexture, | ||||
| import { | import { | ||||
| convertArrayBufferToStringsInMeta, | convertArrayBufferToStringsInMeta, | ||||
| getEmptyMeta, | getEmptyMeta, | ||||
| jsonToBlob, | |||||
| metaFromResources, | metaFromResources, | ||||
| MetaImporter, | MetaImporter, | ||||
| metaToResources, | metaToResources, | ||||
| import {IViewerPlugin, IViewerPluginSync} from './IViewerPlugin' | import {IViewerPlugin, IViewerPluginSync} from './IViewerPlugin' | ||||
| import {DropzonePlugin, DropzonePluginOptions} from '../plugins/interaction/DropzonePlugin' | import {DropzonePlugin, DropzonePluginOptions} from '../plugins/interaction/DropzonePlugin' | ||||
| import {uiConfig, uiFolderContainer, UiObjectConfig} from 'uiconfig.js' | import {uiConfig, uiFolderContainer, UiObjectConfig} from 'uiconfig.js' | ||||
| import {IRenderTarget} from '../rendering' | |||||
| export type IViewerEvent = BaseEvent & { | export type IViewerEvent = BaseEvent & { | ||||
| type: 'update'|'preRender'|'postRender'|'preFrame'|'postFrame'|'dispose'|'addPlugin'|'renderEnabled'|'renderDisabled' | type: 'update'|'preRender'|'postRender'|'preFrame'|'postFrame'|'dispose'|'addPlugin'|'renderEnabled'|'renderDisabled' | ||||
| return await this.assetManager.addAssetSingle<T>(obj, options) | return await this.assetManager.addAssetSingle<T>(obj, options) | ||||
| } | } | ||||
| /** | |||||
| * Imports an object/model/material/texture/viewer-config/plugin-preset/... to the viewer scene from url or an {@link IAsset} object. | |||||
| * Same as {@link AssetImporter.importSingle} | |||||
| * @param obj | |||||
| * @param options | |||||
| */ | |||||
| async import<T extends ImportResult = ImportResult>(obj: string | IAsset | null, options?: ImportAddOptions) { | |||||
| if (!obj) return | |||||
| 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 |