| Try them: https://threepipe.org/examples/ | Try them: https://threepipe.org/examples/ | ||||
| View the source code by pressing the code button on the top left of the example page. | |||||
| To make changes and run the example, click on the CodePen button on the top right of the source code. | |||||
| ## Getting Started | ## Getting Started | ||||
| Check out the GLTF Load example to see it in action or to check the JS equivalent code: https://threepipe.org/examples/gltf-load/ | Check out the GLTF Load example to see it in action or to check the JS equivalent code: https://threepipe.org/examples/gltf-load/ | ||||
| Check out the [Plugins](#plugins) section below to learn how to add additional functionality to the viewer. | |||||
| ## License | ## License | ||||
| The core framework([src](https://github.com/repalash/threepipe/tree/master/src), [dist](https://github.com/repalash/threepipe/tree/master/dist), [examples](https://github.com/repalash/threepipe/tree/master/examples) folders) and any [plugins](https://github.com/repalash/threepipe/tree/master/plugins) without a separate license are under the [Apache 2.0 license](https://github.com/repalash/threepipe/tree/master/LICENSE). | The core framework([src](https://github.com/repalash/threepipe/tree/master/src), [dist](https://github.com/repalash/threepipe/tree/master/dist), [examples](https://github.com/repalash/threepipe/tree/master/examples) folders) and any [plugins](https://github.com/repalash/threepipe/tree/master/plugins) without a separate license are under the [Apache 2.0 license](https://github.com/repalash/threepipe/tree/master/LICENSE). | ||||
| ## Contributing | ## Contributing | ||||
| Contributions to ThreePipe are welcome and encouraged! Feel free to open issues and pull requests on the GitHub repository. | Contributions to ThreePipe are welcome and encouraged! Feel free to open issues and pull requests on the GitHub repository. | ||||
| ## File Formats | |||||
| ThreePipe Asset Manager supports the import of following file formats out of the box: | |||||
| * Models: | |||||
| * gltf, glb | |||||
| * obj, mtl | |||||
| * fbx | |||||
| * drc | |||||
| * Materials | |||||
| * mat, pmat, bmat (json based), registered material template slugs | |||||
| * Images | |||||
| * webp, png, jpeg, jpg, svg, ico | |||||
| * hdr, exr | |||||
| * ktx2, ktx, dds, pvr | |||||
| * Misc | |||||
| * json, vjson | |||||
| * zip | |||||
| * txt | |||||
| Additional formats can be added by plugins: | |||||
| * Models | |||||
| * 3dm - Using [Rhino3dmLoadPlugin](#Rhino3dmLoadPlugin) | |||||
| ## Plugins | |||||
| ThreePipe has a simple plugin system that allows you to easily add new features to the viewer. Plugins can be added to the viewer using the `addPlugin` and `addPluginSync` methods. The plugin system is designed to be modular and extensible. Plugins can be added to the viewer at any time and can be removed using the `removePlugin` and `removePluginSync` methods. | |||||
| ### DepthBufferPlugin | |||||
| todo: image | |||||
| Example: https://threepipe.org/examples/#depth-buffer-plugin/ | |||||
| Source Code: [src/plugins/pipeline/DepthBufferPlugin.ts](./src/plugins/pipeline/DepthBufferPlugin.ts) | |||||
| Depth Buffer Plugin adds a pre-render pass to the render manager and renders a depth buffer to a target. The render target can be accessed by other plugins throughout the rendering pipeline to create effects like depth of field, SSAO, SSR, etc. | |||||
| ```typescript | |||||
| import {ThreeViewer, DepthBufferPlugin} from 'threepipe' | |||||
| const viewer = new ThreeViewer({...}) | |||||
| const depthPlugin = viewer.addPluginSync(new DepthBufferPlugin(HalfFloatType)) | |||||
| const depthTarget = depthPlugin.target; | |||||
| // Use the depth target by accesing `depthTarget.texture`. | |||||
| ``` | |||||
| The depth values are based on camera near far values, which are controlled automatically by the viewer. To manually specify near, far values and limits, it can be set in the camera userData. Check the [example](https://threepipe.org/examples/#depth-buffer-plugin/) for more details. | |||||
| ### NormalBufferPlugin | |||||
| todo: image | |||||
| Example: https://threepipe.org/examples/#normal-buffer-plugin/ | |||||
| Source Code: [src/plugins/pipeline/NormalBufferPlugin.ts](./src/plugins/pipeline/NormalBufferPlugin.ts) | |||||
| Normal Buffer Plugin adds a pre-render pass to the render manager and renders a normal buffer to a target. The render target can be accessed by other plugins throughout the rendering pipeline to create effects like SSAO, SSR, etc. | |||||
| Note: Use [`DepthNormalBufferPlugin`](#DepthNormalBufferPlugin) if using both `DepthBufferPlugin` and `NormalBufferPlugin` to render both depth and normal buffers in a single pass. | |||||
| ```typescript | |||||
| import {ThreeViewer, NormalBufferPlugin} from 'threepipe' | |||||
| const viewer = new ThreeViewer({...}) | |||||
| const normalPlugin = viewer.addPluginSync(new NormalBufferPlugin()) | |||||
| const normalTarget = normalPlugin.target; | |||||
| // Use the normal target by accessing `normalTarget.texture`. | |||||
| ``` | |||||
| ### DepthNormalBufferPlugin | |||||
| todo | |||||
| ### RenderTargetPreviewPlugin | |||||
| todo: image | |||||
| Example: https://threepipe.org/examples/#render-target-preview/ | |||||
| Source Code: [src/plugins/ui/RenderTargetPreviewPlugin.ts](./src/plugins/ui/RenderTargetPreviewPlugin.ts) | |||||
| RenderTargetPreviewPlugin is a useful development and debugging plugin that renders any registered render-target to the screen in small collapsable panels. | |||||
| ```typescript | |||||
| import {ThreeViewer, RenderTargetPreviewPlugin, NormalBufferPlugin} from 'threepipe' | |||||
| const viewer = new ThreeViewer({...}) | |||||
| const normalPlugin = viewer.addPluginSync(new NormalBufferPlugin(HalfFloatType)) | |||||
| const previewPlugin = viewer.addPluginSync(new RenderTargetPreviewPlugin()) | |||||
| // Show the normal buffer in a panel | |||||
| previewPlugin.addTarget(()=>normalPlugin.target, 'normal', false, false) | |||||
| ``` | |||||
| ### Rhino3dmLoadPlugin | |||||
| Example: https://threepipe.org/examples/#rhino3dm-load/ | |||||
| Source Code: [src/plugins/import/Rhino3dmLoadPlugin.ts](./src/plugins/import/Rhino3dmLoadPlugin.ts) | |||||
| Adds support for loading .3dm files generated by [Rhino 3D](https://www.rhino3d.com/). This plugin includes some changes with how 3dm files are loaded in three.js. The changes are around loading layer and primitive properties when set as reference in the 3dm files. |
| this.dispatchEvent({type: 'exportFile', obj, state:'processing', exportOptions: options}) | this.dispatchEvent({type: 'exportFile', obj, state:'processing', exportOptions: options}) | ||||
| const processed = await this.processBeforeExport(obj, options) | const processed = await this.processBeforeExport(obj, options) | ||||
| const ext = options.exportExt ?? processed?.typeExt ?? processed?.ext | |||||
| if (!processed || !ext) throw new Error(`Unable to preprocess before export ${ext}`) | |||||
| 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 | if (processed.blob) res = processed.blob | ||||
| else { | else { | ||||
| const parser = this._getParser(ext) | const parser = this._getParser(ext) | ||||
| 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'} | ||||
| else { | else { | ||||
| const blob = obj.renderManager.exportRenderTarget(obj as WebGLRenderTarget, 'auto') | |||||
| const blob = obj.renderManager.exportRenderTarget(obj as WebGLRenderTarget, | |||||
| (options.exportExt || '' !== '') && options.exportExt !== 'auto' ? | |||||
| options.exportExt === 'exr' ? 'image/x-exr' : 'image/' + options.exportExt : 'auto') | |||||
| return { | return { | ||||
| obj, ext: blob.ext, blob, | obj, ext: blob.ext, blob, | ||||
| } | } |
| async loadImported<T extends ValOrArr<ImportResult|undefined> = ImportResult>(imported: T, {autoSetEnvironment = true, autoSetBackground = false, ...options}: AddAssetOptions = {}): Promise<T | never[]> { | async loadImported<T extends ValOrArr<ImportResult|undefined> = ImportResult>(imported: T, {autoSetEnvironment = true, autoSetBackground = false, ...options}: AddAssetOptions = {}): Promise<T | never[]> { | ||||
| const arr: (ImportResult|undefined)[] = Array.isArray(imported) ? imported : [imported] | const arr: (ImportResult|undefined)[] = Array.isArray(imported) ? imported : [imported] | ||||
| let ret: T = Array.isArray(imported) ? [] : undefined as any | |||||
| for (const obj of arr) { | for (const obj of arr) { | ||||
| if (!obj) continue | |||||
| if (!obj) { | |||||
| if (Array.isArray(ret)) ret.push(undefined) | |||||
| continue | |||||
| } | |||||
| let r = obj | |||||
| switch (obj.assetType) { | switch (obj.assetType) { | ||||
| case 'material': | case 'material': | ||||
| case 'model': | case 'model': | ||||
| case 'light': | case 'light': | ||||
| case 'camera': | case 'camera': | ||||
| await this.viewer.addSceneObject(<IObject3D|RootSceneImportResult>obj, options) // todo update references in scene update event | |||||
| r = await this.viewer.addSceneObject(<IObject3D|RootSceneImportResult>obj, options) // todo update references in scene update event | |||||
| break | break | ||||
| case 'config': | case 'config': | ||||
| if (options?.importConfig !== false) await this.viewer.importConfig(<ISerializedConfig>obj) | if (options?.importConfig !== false) await this.viewer.importConfig(<ISerializedConfig>obj) | ||||
| break | break | ||||
| } | } | ||||
| this.dispatchEvent({type: 'loadAsset', data: obj}) | this.dispatchEvent({type: 'loadAsset', data: obj}) | ||||
| if (Array.isArray(ret)) ret.push(r) | |||||
| else ret = r as T | |||||
| } | } | ||||
| return imported || [] | |||||
| return ret || [] | |||||
| } | } | ||||
| /** | /** |
| removeControlsCtor(key: string): void; | removeControlsCtor(key: string): void; | ||||
| refreshCameraControls(setDirty?: boolean): void | refreshCameraControls(setDirty?: boolean): void | ||||
| updateProjectionMatrix(): void | |||||
| fov?: number | |||||
| // 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 | ||||
| import type {Event, IUniform, Material, MaterialParameters, Shader} from 'three' | |||||
| import type {Color, Event, IUniform, Material, MaterialParameters, Shader} from 'three' | |||||
| import type {IDisposable, IJSONSerializable} from 'ts-browser-helpers' | import type {IDisposable, IJSONSerializable} from 'ts-browser-helpers' | ||||
| import type {MaterialExtension} from '../materials' | import type {MaterialExtension} from '../materials' | ||||
| import type {ChangeEvent, IUiConfigContainer} from 'uiconfig.js' | import type {ChangeEvent, IUiConfigContainer} from 'uiconfig.js' | ||||
| transmissionMap?: ITexture | null | transmissionMap?: ITexture | null | ||||
| transmission?: number | transmission?: number | ||||
| color?: Color | |||||
| wireframe?: boolean | |||||
| isRawShaderMaterial?: boolean | isRawShaderMaterial?: boolean | ||||
| isPhysicalMaterial?: boolean | isPhysicalMaterial?: boolean |
| this.modelRoot.animations.push(animation) | this.modelRoot.animations.push(animation) | ||||
| } | } | ||||
| } | } | ||||
| obj.children.forEach(c=>this.addObject(c, options)) | |||||
| return obj.children.map(c=>this.addObject(c, options)) | |||||
| } | } | ||||
| private _addObject3D(model: IObject3D|null, {autoCenter = false, autoScale = false, autoScaleRadius = 2., addToRoot = false, license}: AddObjectOptions = {}): void { | private _addObject3D(model: IObject3D|null, {autoCenter = false, autoScale = false, autoScaleRadius = 2., addToRoot = false, license}: AddObjectOptions = {}): void { |
| IWebGLRenderer, | IWebGLRenderer, | ||||
| upgradeWebGLRenderer, | upgradeWebGLRenderer, | ||||
| } from '../core' | } from '../core' | ||||
| import {base64ToArrayBuffer, Class, onChange2, serializable, serialize, ValOrArr} from 'ts-browser-helpers' | |||||
| import {base64ToArrayBuffer, canvasFlipY, Class, onChange2, serializable, serialize, ValOrArr} from 'ts-browser-helpers' | |||||
| import {uiConfig, uiFolderContainer, uiMonitor, uiSlider, uiToggle} from 'uiconfig.js' | import {uiConfig, uiFolderContainer, uiMonitor, uiSlider, uiToggle} from 'uiconfig.js' | ||||
| import {generateUUID, textureDataToImageData} from '../three' | import {generateUUID, textureDataToImageData} from '../three' | ||||
| import {BlobExt, EXRExporter2} from '../assetmanager' | import {BlobExt, EXRExporter2} from '../assetmanager' | ||||
| /** | /** | ||||
| * Converts a render target to a png/jpeg data url string. | * Converts a render target to a png/jpeg data url string. | ||||
| * Note: this will clamp the values to [0, 1] and converts to srgb for float and half-float render targets. | |||||
| * @param target | * @param target | ||||
| * @param mimeType | * @param mimeType | ||||
| * @param quality | * @param quality | ||||
| } | } | ||||
| ctx.putImageData(imageData, 0, 0) | ctx.putImageData(imageData, 0, 0) | ||||
| const string = canvas.toDataURL(mimeType, quality) | |||||
| const string = (target.texture.flipY ? canvas : canvasFlipY(canvas)).toDataURL(mimeType, quality) // intentionally inverted ternary | |||||
| canvas.remove() | canvas.remove() | ||||
| return string | return string | ||||
| } | } |
| export {uniform, matDefine} from './decorators' | export {uniform, matDefine} from './decorators' | ||||
| export {getEncodingComponents, getTexelEncoding, getTexelDecoding, getTexelDecoding2, getTexelDecodingFunction, getTexelEncodingFunction, getTextureColorSpaceFromMap} from './encoding' | export {getEncodingComponents, getTexelEncoding, getTexelDecoding, getTexelDecoding2, getTexelDecodingFunction, getTexelEncodingFunction, getTextureColorSpaceFromMap} from './encoding' | ||||
| export {generateUUID, toIndexedGeometry} from './misc' | export {generateUUID, toIndexedGeometry} from './misc' | ||||
| export {getTextureDataType, textureToCanvas, textureDataToImageData, textureToDataUrl, imageToCanvas} from './texture' | |||||
| export {getTextureDataType, textureToCanvas, textureDataToImageData, textureToDataUrl, texImageToCanvas} from './texture' | |||||
| // export {} from './constants' | // export {} from './constants' |
| WebGLRenderer, | WebGLRenderer, | ||||
| } from 'three' | } from 'three' | ||||
| import {TextureImageData} from 'three/src/textures/types' | import {TextureImageData} from 'three/src/textures/types' | ||||
| import {LinearToSRGB} from 'ts-browser-helpers' | |||||
| import {canvasFlipY, LinearToSRGB} from 'ts-browser-helpers' | |||||
| export function getTextureDataType(renderer?: WebGLRenderer): TextureDataType { | export function getTextureDataType(renderer?: WebGLRenderer): TextureDataType { | ||||
| if (!renderer) return UnsignedByteType | if (!renderer) return UnsignedByteType | ||||
| * @param flipY | * @param flipY | ||||
| * @param canvas | * @param canvas | ||||
| */ | */ | ||||
| export function textureToCanvas(texture: Texture|DataTexture, maxWidth: number, flipY = false, canvas?: HTMLCanvasElement) { | |||||
| export function textureToCanvas(texture: Texture|DataTexture, maxWidth: number, flipY = false) { | |||||
| let img | let img | ||||
| if ((texture as DataTexture).isDataTexture) img = textureDataToImageData(texture.image, texture.colorSpace) | if ((texture as DataTexture).isDataTexture) img = textureDataToImageData(texture.image, texture.colorSpace) | ||||
| else img = texture.image | else img = texture.image | ||||
| return imageToCanvas(img, maxWidth, flipY, canvas) | |||||
| return texImageToCanvas(img, maxWidth, flipY) | |||||
| } | } | ||||
| export function imageToCanvas(image: TexImageSource, maxWidth: number, flipY = false, canvas?: HTMLCanvasElement) { | |||||
| canvas = canvas || document.createElement('canvas') | |||||
| export function texImageToCanvas(image: TexImageSource, maxWidth: number, flipY = false) { | |||||
| const canvas = document.createElement('canvas') | |||||
| // resize it to the size of our image | // resize it to the size of our image | ||||
| canvas.width = Math.min(maxWidth, image.width as number) | canvas.width = Math.min(maxWidth, image.width as number) | ||||
| canvas.height = Math.floor(1.0 + canvas.width * (image.height as number) / (image.width as number)) | canvas.height = Math.floor(1.0 + canvas.width * (image.height as number) / (image.width as number)) | ||||
| } | } | ||||
| let needsFlipY = false | |||||
| if ((image as ImageData).data !== undefined) { // THREE.DataTexture | if ((image as ImageData).data !== undefined) { // THREE.DataTexture | ||||
| const imageData = image as ImageData | const imageData = image as ImageData | ||||
| console.error('textureToDataUrl: could not get temp canvas context') | console.error('textureToDataUrl: could not get temp canvas context') | ||||
| ctx.putImageData(imageData, 0, 0) | ctx.putImageData(imageData, 0, 0) | ||||
| } else { | } else { | ||||
| tempCtx.putImageData(imageData, 0, 0) | |||||
| tempCtx.putImageData(imageData, 0, 0) // for resize | |||||
| ctx.drawImage(tempCanvas, 0, 0, canvas.width, canvas.height) | ctx.drawImage(tempCanvas, 0, 0, canvas.width, canvas.height) | ||||
| } | } | ||||
| } else { | } else { | ||||
| ctx.putImageData(imageData, 0, 0) | ctx.putImageData(imageData, 0, 0) | ||||
| if (flipY) needsFlipY = true // because of putImageData | |||||
| } | } | ||||
| } else { | } else { | ||||
| ctx.drawImage(image as any, 0, 0, canvas.width, canvas.height) | ctx.drawImage(image as any, 0, 0, canvas.width, canvas.height) | ||||
| } | } | ||||
| return canvas | |||||
| return !needsFlipY ? canvas : canvasFlipY(canvas) | |||||
| } | } | ||||
| export function textureToDataUrl(texture: Texture|DataTexture, maxWidth: number, flipY: boolean, mimeType?: string, quality?: number) { | export function textureToDataUrl(texture: Texture|DataTexture, maxWidth: number, flipY: boolean, mimeType?: string, quality?: number) { |
| export {downloadBlob, blobToDataURL} from 'ts-browser-helpers' | |||||
| export type {IEvent, IEventDispatcher} from 'ts-browser-helpers' | |||||
| export type {ImageCanvasOptions} from 'ts-browser-helpers' | |||||
| export type {AnyFunction, AnyOptions, Class, IDisposable, IJSONSerializable, PartialPick, PartialRecord, StringKeyOf, Fof, ValOrFunc, ValOrArr, ValOrArrOp} from 'ts-browser-helpers' | |||||
| export type {Serializer} from 'ts-browser-helpers' | |||||
| export {PointerDragHelper} from 'ts-browser-helpers' | |||||
| export {Damper} from 'ts-browser-helpers' | |||||
| export {SimpleEventDispatcher} from 'ts-browser-helpers' | |||||
| export {createCanvasElement, createDiv, createImage, createStyles, createScriptFromURL} from 'ts-browser-helpers' | |||||
| export {TYPED_ARRAYS, arrayBufferToBase64, base64ToArrayBuffer, getTypedArray} from 'ts-browser-helpers' | |||||
| export {escapeRegExp, getFilenameFromPath, parseFileExtension, replaceAll, toTitleCase, longestCommonPrefix} from 'ts-browser-helpers' | |||||
| export {prettyScrollbar} from 'ts-browser-helpers' | |||||
| export {blobToDataURL, downloadBlob, downloadFile, uploadFile, mobileAndTabletCheck} from 'ts-browser-helpers' | |||||
| export {LinearToSRGB, SRGBToLinear, colorToDataUrl} from 'ts-browser-helpers' | |||||
| export {onChange, onChange2, onChange3, serialize, serializable} from 'ts-browser-helpers' | |||||
| export {aesGcmDecrypt, aesGcmEncrypt} from 'ts-browser-helpers' | |||||
| export {verifyPermission, writeFile, getFileHandle, getNewFileHandle, readFile} from 'ts-browser-helpers' | |||||
| export {embedUrlRefs, htmlToCanvas, htmlToPng, htmlToSvg} from 'ts-browser-helpers' | |||||
| export {imageToCanvas, imageBitmapToBase64, imageUrlToImageData, imageDataToCanvas, isWebpExportSupported, canvasFlipY} from 'ts-browser-helpers' | |||||
| export {absMax, clearBit, updateBit} from 'ts-browser-helpers' | |||||
| export {includesAll} from 'ts-browser-helpers' | |||||
| export {copyProps, getOrCall, getPropertyDescriptor, isPropertyWritable, safeSetProperty} from 'ts-browser-helpers' | |||||
| export {deepAccessObject, getKeyByValue, objectHasOwn} from 'ts-browser-helpers' | |||||
| export {makeColorSvg, makeTextSvg, makeColorSvgCircle, svgToCanvas, svgToPng} from 'ts-browser-helpers' | |||||
| export {timeout, now} from 'ts-browser-helpers' | |||||
| export {pathJoin, getUrlQueryParam, setUrlQueryParam, remoteWorkerURL} from 'ts-browser-helpers' | |||||
| export {css, glsl, html, svgUrl} from 'ts-browser-helpers' | |||||
| export {Serialization} from 'ts-browser-helpers' | |||||
| export {shaderReplaceString} from './shader-helpers' | export {shaderReplaceString} from './shader-helpers' | ||||
| export {makeGLBFile} from './gltf' | export {makeGLBFile} from './gltf' | ||||
| export {serialize, serializable, Serialization} from 'ts-browser-helpers' |
| }) | }) | ||||
| } | } | ||||
| export function getEmptyMeta(): SerializationMetaType { | |||||
| export function getEmptyMeta(res?: Partial<SerializationResourcesType>): SerializationMetaType { | |||||
| return { // see Object3D.js toJSON for more details | return { // see Object3D.js toJSON for more details | ||||
| geometries: {}, | |||||
| materials: {}, | |||||
| textures: {}, | |||||
| images: {}, | |||||
| shapes: [], | |||||
| skeletons: {}, | |||||
| animations: [], | |||||
| extras: {}, | |||||
| geometries: {...res?.geometries}, | |||||
| materials: {...res?.materials}, | |||||
| textures: {...res?.textures}, | |||||
| images: {...res?.images}, | |||||
| shapes: {...res?.shapes}, | |||||
| skeletons: {...res?.skeletons}, | |||||
| animations: {...res?.animations}, | |||||
| extras: {...res?.extras}, | |||||
| _context: {}, | _context: {}, | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| export function metaFromResources(resources?: Partial<SerializationResourcesType>, viewer?: ThreeViewer): SerializationMetaType { | export function metaFromResources(resources?: Partial<SerializationResourcesType>, viewer?: ThreeViewer): SerializationMetaType { | ||||
| return { | return { | ||||
| ...getEmptyMeta(), | |||||
| ...resources, | ...resources, | ||||
| ...getEmptyMeta(resources), | |||||
| _context: { | _context: { | ||||
| assetManager: viewer?.assetManager, | assetManager: viewer?.assetManager, | ||||
| assetImporter: viewer?.assetManager.importer, | assetImporter: viewer?.assetManager.importer, |
| // } | // } | ||||
| get dirty(): boolean { | get dirty(): boolean { | ||||
| return this._dirty | |||||
| return this.enabled && this._dirty | |||||
| } | } | ||||
| set dirty(value: boolean) { | set dirty(value: boolean) { |
| const obj = <RootSceneImportResult>imported | const obj = <RootSceneImportResult>imported | ||||
| if (obj.importedViewerConfig && options?.importConfig !== false) await this.importConfig(obj.importedViewerConfig) | if (obj.importedViewerConfig && options?.importConfig !== false) await this.importConfig(obj.importedViewerConfig) | ||||
| this._scene.loadModelRoot(obj, options) | this._scene.loadModelRoot(obj, options) | ||||
| return imported | |||||
| return this._scene.modelRoot as T | |||||
| } | } | ||||
| this._scene.addObject(imported, options) | this._scene.addObject(imported, options) | ||||
| return imported | return imported |