UNPKG

threepipe

Version:

A 3D viewer framework built on top of three.js in TypeScript with a focus on quality rendering, modularity and extensibility.

145 lines 6.01 kB
import { EventDispatcher } from 'three'; import { EXRExporter2, SimpleJSONExporter, SimpleTextExporter } from './export'; /** * Asset Exporter * * Utility class to export objects, materials, textures, render targets, etc. * Used in {@link AssetManager} to export assets. * @category Asset Manager */ export class AssetExporter extends EventDispatcher { addExporter(...exporters) { for (const exporter of exporters) { if (this.exporters.includes(exporter)) { console.warn('Exporter already added', exporter); return; } this.exporters.push(exporter); } } removeExporter(...exporters) { for (const exporter of exporters) { const i = this.exporters.indexOf(exporter); if (i >= 0) this.exporters.splice(i, 1); } } getExporter(...ext) { return this.exporters.find(e => e.ext.some(e1 => ext.includes(e1))); } constructor() { super(); this.exporters = [ { ctor: () => new SimpleJSONExporter(), ext: ['json'] }, { ctor: () => new SimpleTextExporter(), ext: ['txt', 'text'] }, { ctor: () => new EXRExporter2(), ext: ['exr'] }, // {ctor: ()=>new EXRExporter2(), ext: ['png', 'jpeg', 'webp']}, // todo // {ctor: ()=>new GLTFDracoExporter(), ext: ['gltf', 'glb']}, ]; this._cachedParsers = []; } async exportObject(obj, options = {}) { if (!obj?.assetType) { console.error('Object has no asset type'); return undefined; } const excluded = []; if (obj.assetType === 'model') { obj.traverse((o) => { if (o.userData.excludeFromExport && o.visible) { o.visible = false; excluded.push(o); } }); } const blob = await this._exportFile(obj, options); if (obj.assetType === 'model') { excluded.forEach((o) => o.visible = true); } if (obj?.userData?.rootSceneModelRoot && options.viewerConfig === false) { delete obj.userData.__exportViewerConfig; } return blob; } // export to blob async _exportFile(obj, options = {}) { // if ((file as any)?.__imported) return (file as any).__imported // todo: cache exports? let res; try { this.dispatchEvent({ type: 'exportFile', obj, state: 'processing', exportOptions: options }); const processed = await this.processBeforeExport(obj, options); const ext = options.exportExt || processed?.typeExt || processed?.ext; if (!processed || !ext) { console.error(processed, options, obj); throw new Error(`Unable to preprocess before export ${ext}`); } if (processed.blob) res = processed.blob; else { const parser = this._getParser(ext); this.dispatchEvent({ type: 'exportFile', obj, state: 'exporting' }); res = await parser.parseAsync(processed.obj, { exportExt: processed.ext ?? ext, ...options }); res.ext = processed.ext; } this.dispatchEvent({ type: 'exportFile', obj, state: 'done' }); } catch (e) { console.error('AssetExporter: Unable to Export file', obj); // console.error(e) this.dispatchEvent({ type: 'exportFile', obj, state: 'error', error: e }); throw e; return undefined; } // if (file) (file as any).__imported = res return res; } _createParser(ext) { const exporter = this.exporters.find(e => e.ext.includes(ext)); if (!exporter) throw new Error(`No exporter found for extension ${ext}`); const parser = exporter?.ctor(this, exporter); if (!parser) throw new Error(`Unable to create parser for extension ${ext}`); this._cachedParsers.push({ ext: exporter.ext, parser }); this.dispatchEvent({ type: 'exporterCreate', exporter, parser }); return parser; } _getParser(ext) { return this._cachedParsers.find(e => e.ext.includes(ext))?.parser ?? this._createParser(ext); } async processBeforeExport(obj, options = {}) { // if (obj.assetExporterProcessed && !options.forceExporterReprocess) return obj //todo;;; switch (obj.assetType) { case 'light': console.error('AssetExporter: light export not implemented'); return undefined; case 'model': return { obj, ext: 'glb' }; // return {obj, ext: 'gltf'} case 'material': return { obj: obj.toJSON(), ext: obj.constructor?.TypeSlug || 'json', typeExt: 'json' }; case 'texture': return options.exportExt ? { obj, ext: options.exportExt } : { obj: obj.toJSON(), ext: 'json' }; case 'renderTarget': if (obj.isWebGLMultipleRenderTargets) console.error('AssetExporter: WebGLMultipleRenderTargets export not supported'); else if (!obj.renderManager) return { obj, ext: 'exr' }; else { const blob = obj.renderManager.exportRenderTarget(obj, (options.exportExt || '' !== '') && options.exportExt !== 'auto' ? options.exportExt === 'exr' ? 'image/x-exr' : 'image/' + options.exportExt : 'auto'); return { obj, ext: blob.ext, blob, }; } break; default: console.error('AssetExporter: unknown asset type', obj.assetType); } return undefined; } dispose() { // todo } } //# sourceMappingURL=AssetExporter.js.map