Преглед изворни кода

Add Dropzone and DropzonePlugin, minor fix.

master
Palash Bansal пре 3 година
родитељ
комит
e3603ba142
No account linked to committer's email address

+ 1
- 1
.gitignore Прегледај датотеку

@@ -1,6 +1,6 @@
dist
docs
./index.html
/index.html
examples/**/*.js
examples/**/*.js.map


+ 44
- 0
examples/dropzone-plugin/index.html Прегледај датотеку

@@ -0,0 +1,44 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Dropzone Plugin</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;
}
#prompt-div{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: #333;
font-size: 2em;
font-family: sans-serif;
}
</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 id="prompt-div">Drop any <span style="font-family: monospace">glb/hdr/png/jpg</span> files here</div>
</div>

</body>

+ 34
- 0
examples/dropzone-plugin/script.ts Прегледај датотеку

@@ -0,0 +1,34 @@
import {_testFinish, DropzonePlugin, ThreeViewer} from 'threepipe'

async function init() {

const viewer = new ThreeViewer({
canvas: document.getElementById('mcanvas') as HTMLCanvasElement,
dropzone: { // this can also be set to true and configured by getting a reference to the DropzonePlugin
allowedExtensions: ['gltf', 'glb', 'hdr', 'png', 'jpg', 'json', 'fbx', 'obj'], // only allow these file types. If undefined, all files are allowed.
addOptions: {
disposeSceneObjects: true, // auto dispose of old scene objects
autoSetEnvironment: true, // when hdr is dropped
autoSetBackground: true, // when any image is dropped
autoCenter: true, // auto center the object
autoScale: true, // auto scale according to radius
autoScaleRadius: 2,
license: 'Imported from dropzone', // Any license to set on imported objects
importConfig: true, // import config from file
},
},
})

await viewer.setEnvironmentMap('https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr')

const dropzone = viewer.getPlugin(DropzonePlugin)
dropzone?.addEventListener('drop', (e: any) => {
if (!e.assets?.length) return // no assets imported
console.log('Dropped Event:', e)
const promptDiv = document.getElementById('prompt-div')!
promptDiv.style.display = 'none'
})

}

init().then(_testFinish)

+ 16
- 3
examples/gltf-load/script.ts Прегледај датотеку

@@ -1,10 +1,23 @@
import {_testFinish, ThreeViewer} from 'threepipe'

const viewer = new ThreeViewer({canvas: document.getElementById('mcanvas') as HTMLCanvasElement, msaa: true})

async function init() {

await viewer.setEnvironmentMap('https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr')
const viewer = new ThreeViewer({
canvas: document.getElementById('mcanvas') as HTMLCanvasElement,
msaa: true,
dropzone: {
allowedExtensions: ['gltf', 'glb', 'hdr'],
addOptions: {
disposeSceneObjects: true,
autoSetEnvironment: true, // when hdr is dropped
autoSetBackground: true,
},
},
})

await viewer.setEnvironmentMap('https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr', {
setBackground: true,
})
const result = await viewer.load('https://threejs.org/examples/models/gltf/DamagedHelmet/glTF/DamagedHelmet.gltf', {
autoCenter: true,
autoScale: true,

+ 1
- 0
examples/index.html Прегледај датотеку

@@ -203,6 +203,7 @@
<ul>
<li><a href="./depth-buffer-plugin">Depth Buffer Plugin </a></li>
<li><a href="./render-target-preview">Render Target Preview </a></li>
<li><a href="./dropzone-plugin">Dropzone (Drag & Drop) </a></li>
</ul>
<h2 class="category">Import/Export</h2>
<ul>

+ 1
- 1
src/assetmanager/import/MTLLoader2.ts Прегледај датотеку

@@ -583,4 +583,4 @@ class MaterialCreator {

}

export {MTLLoader2};
export {MTLLoader2, type MaterialCreator};

+ 1
- 1
src/assetmanager/import/index.ts Прегледај датотеку

@@ -1,6 +1,6 @@
export {JSONMaterialLoader} from './JSONMaterialLoader'
export {SimpleJSONLoader} from './SimpleJSONLoader'
export {MTLLoader2} from './MTLLoader2'
export {MTLLoader2, type MaterialCreator} from './MTLLoader2'
export {OBJLoader2} from './OBJLoader2'
export {ZipLoader} from './ZipLoader'
export {GLTFLoader2} from './GLTFLoader2'

+ 38
- 4
src/core/IScene.ts Прегледај датотеку

@@ -6,14 +6,47 @@ import {Box3B} from '../three/math/Box3B'
import {ITexture} from './ITexture'

export interface AddObjectOptions {
addToRoot?: boolean // default = false
// TODO; add more options
/**
* Add directly to the {@link RootScene} object instead of {@link RootScene.modelRoot}
* @default false
*/
addToRoot?: boolean
/**
* Automatically center the object in the scene.
* @default false
*/
autoCenter?: boolean,
/**
* Add a license to the object
*/
license?: string,
/**
* Automatically scale the object according to its bounding box and the {@link autoScaleRadius} setting
* @default false
*/
autoScale?: boolean
autoScaleRadius?: number // default = 2
/**
* Radius to use for {@link autoScale}
* @default 2
*/
autoScaleRadius?: number
/**
* any attached viewer config will be ignored if this is set to true
* @default true
*/
importConfig?: boolean

/**
* Clear the viewer scene objects before the new object is added. Same as {@link disposeSceneObjects} but does not dispose the objects.
*/
clearSceneObjects?: boolean
/**
* Dispose all the scene objects before the new object is added. Same as {@link clearSceneObjects} but also disposes the objects.
*/
disposeSceneObjects?: boolean

importConfig?: boolean // any attached viewer config will be ignored if this is set to true

// TODO; add more options
}

// | string
@@ -30,6 +63,7 @@ export interface ISceneEvent<T extends string = ISceneEventTypes> extends IObjec
// change?: string
}
export type ISceneSetDirtyOptions = IObjectSetDirtyOptions & {
[key: string]: any
}



+ 10
- 4
src/core/object/RootScene.ts Прегледај датотеку

@@ -146,6 +146,9 @@ export class RootScene extends Scene<ISceneEvent, ISceneEventTypes> implements I
* @param options
*/
addObject<T extends IObject3D|Object3D = IObject3D>(imported: T, options?: AddObjectOptions): T {
if (options?.clearSceneObjects || options?.disposeSceneObjects) {
this.clearSceneModels(options.disposeSceneObjects)
}
if (!imported) return imported
if (!imported.isObject3D) {
console.error('Invalid object, cannot add to scene.', imported)
@@ -162,6 +165,9 @@ export class RootScene extends Scene<ISceneEvent, ISceneEventTypes> implements I
* @param options
*/
loadModelRoot(obj: RootSceneImportResult, options?: AddObjectOptions) {
if (options?.clearSceneObjects || options?.disposeSceneObjects) {
this.clearSceneModels(options.disposeSceneObjects)
}
if (!obj.userData?.rootSceneModelRoot) {
console.error('Invalid model root scene object. Trying to add anyway.', obj)
}
@@ -221,11 +227,11 @@ export class RootScene extends Scene<ISceneEvent, ISceneEventTypes> implements I
this.setDirty({refreshScene: true})
}

clearSceneModels(dispose = false): void {
if (dispose) this.disposeSceneModels()
clearSceneModels(dispose = false, setDirty = true): void {
if (dispose) return this.disposeSceneModels(setDirty)
this.modelRoot.clear()
this.modelRoot.children = []
this.setDirty({refreshScene: true})
setDirty && this.setDirty({refreshScene: true})
}

disposeSceneModels(setDirty = true) {
@@ -261,7 +267,7 @@ export class RootScene extends Scene<ISceneEvent, ISceneEventTypes> implements I
public backgroundColor: Color | null = null // read in three.js WebGLBackground

/**
* @deprecated Use addSceneObject
* @deprecated Use {@link addObject}
*/
add(...object: Object3D[]): this {
super.add(...object)

+ 1
- 0
src/plugins/index.ts Прегледај датотеку

@@ -2,3 +2,4 @@ export {DepthBufferPlugin} from './pipeline/DepthBufferPlugin'
export type {DepthBufferPluginEventTypes, DepthBufferPluginPass, DepthBufferPluginTarget} from './pipeline/DepthBufferPlugin'
export {PipelinePassPlugin} from './base/PipelinePassPlugin'
export {RenderTargetPreviewPlugin} from './ui/RenderTargetPreviewPlugin'
export {DropzonePlugin, type DropzonePluginOptions} from './interaction/DropzonePlugin'

+ 135
- 0
src/plugins/interaction/DropzonePlugin.ts Прегледај датотеку

@@ -0,0 +1,135 @@
import {AViewerPluginSync} from '../../viewer/AViewerPlugin'
import {type ThreeViewer} from '../../viewer/'
import {Dropzone} from '../../utils'
import {uiButton, uiConfig, uiFolderContainer, uiToggle} from 'uiconfig.js'
import type {AddAssetOptions, ImportFilesOptions, ImportResult} from '../../assetmanager'

export interface DropzonePluginOptions {
domElement?: HTMLElement
allowedExtensions?: string[]
autoImport?: boolean
autoAdd?: boolean
importOptions?: ImportFilesOptions
addOptions?: AddAssetOptions
}
@uiFolderContainer('Dropzone')
export class DropzonePlugin extends AViewerPluginSync<'drop'> {
static readonly PluginType = 'Dropzone'
@uiToggle() enabled = true
private _inputEl?: HTMLInputElement
private _dropzone?: Dropzone
private _allowedExtensions: string[]|undefined = undefined // undefined and empty array is different.

/**
* Automatically import assets when dropped.
*/
autoImport = true
/**
* Automatically add dropped and imported assets to the scene.
* Works only if {@link autoImport} is true.
*/
@uiToggle() autoAdd = true

/**
* Import options for the {@link AssetImporter.importFiles}
*/
@uiConfig() importOptions: ImportFilesOptions = {
autoImportZipContents: true,
forceImporterReprocess: false,
}

/**
* Add options for the {@link RootScene.addObject}
*/
@uiConfig() addOptions: AddAssetOptions = {
autoCenter: true,
importConfig: true,
autoScale: true,
autoScaleRadius: 2,
license: '',
clearSceneObjects: false,
disposeSceneObjects: false,
autoSetBackground: false,
autoSetEnvironment: true,
}

/**
* Allowed file extensions. If undefined, all files are allowed.
*/
get allowedExtensions(): string[] | undefined {
return this._allowedExtensions
}

set allowedExtensions(value: string[] | undefined) {
this._allowedExtensions = value
if (this._inputEl) this._inputEl.accept = value ? value.map(v=>'.' + v).join(', ') : ''
}

/**
* Prompt for file selection using the browser file dialog.
*/
@uiButton('Select files')
public promptForFile(): void {
if (!this.enabled) return
this.allowedExtensions = this._allowedExtensions
this._inputEl?.click()
}

private _domElement?: HTMLElement
constructor(options?: DropzonePluginOptions) {
super()
if (!options) return
this._domElement = options.domElement
this.allowedExtensions = options.allowedExtensions
this.autoImport = options.autoImport ?? this.autoImport
this.autoAdd = options.autoAdd ?? this.autoAdd
this.importOptions = {...this.importOptions, ...options.importOptions}
this.addOptions = {...this.addOptions, ...options.addOptions}
}

onAdded(viewer: ThreeViewer) {
super.onAdded(viewer)
this._inputEl = document.createElement('input')!
this._inputEl.type = 'file'
this._dropzone = new Dropzone(this._domElement || viewer.canvas, this._inputEl, {
drop: this._onFileDrop.bind(this),
})
this.allowedExtensions = this._allowedExtensions
}

onRemove(viewer: ThreeViewer) {
super.onRemove(viewer)
this._dropzone?.destroy()
this._dropzone = undefined
this._inputEl = undefined
}

private async _onFileDrop({files}: {files: Map<string, File>}&any) {
if (!files) return
if (!this.enabled) return
const viewer = this._viewer
if (!viewer) return
if (this._allowedExtensions !== undefined) {
for (const file of files.keys()) {
if (!this._allowedExtensions.includes(file.split('.').pop()?.toLowerCase() ?? '')) {
files.delete(file)
}
}
}
if (files.size < 1) return
const manager = viewer.assetManager
let imported: Map<string, (ImportResult | undefined)[]>|undefined
let assets: (ImportResult | undefined)[]|undefined
if (this.autoImport) {
imported = await manager.importer.importFiles(files, {
allowedExtensions: this.allowedExtensions, ...this.importOptions,
})
if (this.autoAdd) {
const toAdd = [...imported?.values() ?? []].flat(2).filter(v=>!!v) ?? []
assets = await manager.loadImported(toAdd, {...this.addOptions})
}
}
this.dispatchEvent({type: 'drop', files, imported, assets})
}

}

+ 242
- 0
src/utils/Dropzone.ts Прегледај датотеку

@@ -0,0 +1,242 @@
/**
* Fork of: https://github.com/donmccurdy/simple-dropzone updated: Mar 2021
* The MIT License (MIT)
* Copyright (c) 2018 Don McCurdy
*
* Changes:
* Convert to typescript.
* webkitRelativePath for file input select.
* Removed unzip and dependency(done in importer).
*
* Watches an element for file drops, parses to create a filemap hierarchy,
* and emits the result.
*/
export class Dropzone {
get inputEl(): HTMLInputElement|undefined {
return this._inputEl
}
get el(): HTMLElement|undefined {
return this._el
}
private _el?: HTMLElement
private _inputEl?: HTMLInputElement
private _listeners: Record<DropEventType, ListenerCallback[]>

constructor(el?: HTMLElement, inputEl?: HTMLInputElement, listeners?: Partial<Record<DropEventType, ListenerCallback>>) {
this._el = el
this._inputEl = inputEl

this._listeners = {
drop: [],
dropstart: [],
droperror: [],
}

this._onDragover = this._onDragover.bind(this)
this._onDrop = this._onDrop.bind(this)
this._onSelect = this._onSelect.bind(this)

el?.addEventListener('dragover', this._onDragover, false)
el?.addEventListener('drop', this._onDrop, false)
inputEl?.addEventListener('change', this._onSelect)

listeners && Object.entries(listeners).forEach(([e, c])=> c && this.on(e as DropEventType, c))
}

on(type: DropEventType, callback: ListenerCallback): Dropzone {
this._listeners[type].push(callback)
return this
}

private _emit(type: DropEventType, data?: {[id:string]: any}) {
this._listeners[type]
.forEach((callback) => callback(data))
return this
}

/**
* Destroys the instance.
*/
destroy(): void {
const el = this._el
const inputEl = this._inputEl

el?.removeEventListener('dragover', this._onDragover)
el?.removeEventListener('drop', this._onDrop)
inputEl?.removeEventListener('change', this._onSelect)

}

/**
* References (and horror):
* - https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/items
* - https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/files
* - https://code.flickr.net/2012/12/10/drag-n-drop/
* - https://stackoverflow.com/q/44842247/1314762
*
*/
private _onDrop(e: DragEvent) {
e.stopPropagation()
e.preventDefault()

this._emit('dropstart')

const files = Array.from(e.dataTransfer?.files || []) as DropFile[]
const items = Array.from(e.dataTransfer?.items || [])

if (files.length === 0 && items.length === 0) {
this._fail('Required drag-and-drop APIs are not supported in this browser.')
return
}

// Prefer .items, which allow folder traversal if necessary.
if (items.length > 0) {
const entries = items.map((item) => item.webkitGetAsEntry())

// if (entries[0].name.match(/\.zip$/)) {
// this._loadZip(items[0].getAsFile())
// } else {
this._loadNextEntry(new Map(), entries)
// }

return
}

// Fall back to .files, since folders can't be traversed.
// if (files.length === 1 && files[0].name.match(/\.zip$/)) {
// this._loadZip(files[0])
// }
this._emit('drop', {files: new Map(files.map((file) => {
file.filePath = file.name
return [file.filePath, file]
}))})
}

/**
* @param {Event} e
*/
private _onDragover(e: DragEvent) {
e.stopPropagation()
e.preventDefault()
e.dataTransfer && (e.dataTransfer.dropEffect = 'copy') // Explicitly show this is a copy.
}

private _onSelect(e: Event) {
if (!this._inputEl) {
console.warn('Invalid Dropzone event ', e)
return
}
this._emit('dropstart')

// HTML file inputs do not seem to support folders, so assume this is a flat file list.
const files: DropFile[] = [].slice.call(this._inputEl.files ?? new FileList())

// Automatically decompress a zip archive if it is the only file given.
// if (files.length === 1 && this._isZip(files[0])) {
// this._loadZip(files[0])
// return
// }

const fileMap = new Map()
files.forEach((file) => {
file.filePath = (file as any).webkitRelativePath || file.name
fileMap.set(file.filePath, file)
})
this._emit('drop', {files: fileMap})
}

/**
* Iterates through a list of FileSystemEntry objects, creates the fileMap
* tree, and emits the result.
* @param {Array<FileSystemEntry>} entries
*/
private _loadNextEntry(fileMap: Map<string, DropFile>, entries: any[]) {
const entry = entries.pop()

if (!entry) {
this._emit('drop', {files: fileMap})
return
}

if (entry.isFile) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
entry.file((file: DropFile) => {
file.filePath = entry.fullPath
fileMap.set(entry.fullPath, file)
this._loadNextEntry(fileMap, entries)
}, () => console.error('Could not load file: %s', entry.fullPath))
} else if (entry.isDirectory) {
// readEntries() must be called repeatedly until it stops returning results.
// https://www.w3.org/TR/2012/WD-file-system-api-20120417/#the-directoryreader-interface
// https://bugs.chromium.org/p/chromium/issues/detail?id=378883
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
const reader = entry.createReader()
const readerCallback = (newEntries: any[]) => {
if (newEntries.length) {
entries = entries.concat(newEntries)
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
reader.readEntries(readerCallback)
} else {
this._loadNextEntry(fileMap, entries)
}
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
reader.readEntries(readerCallback)
} else {
console.warn('Unknown asset type: ' + entry.fullPath)
this._loadNextEntry(fileMap, entries)
}
}

// /**
// * Inflates a File in .ZIP format, creates the fileMap tree, and emits the
// * result.
// * @param {File} file
// */
// _loadZip(file) {
// const pending = []
// const fileMap = new Map()
// const archive = new fs.FS()
//
// const traverse = (node) => {
// if (node.directory) {
// node.children.forEach(traverse)
// } else if (node.name[0] !== '.') {
// pending.push(new Promise((resolve) => {
// node.getData(new zip.BlobWriter(), (blob) => {
// blob.name = node.name
// fileMap.set(node.getFullname(), blob)
// resolve()
// })
// }))
// }
// }
//
// archive.importBlob(file, () => {
// traverse(archive.root)
// Promise.all(pending).then(() => {
// this._emit('drop', {files: fileMap, archive: file})
// })
// })
// }

// /**
// * @param {File} file
// * @return {Boolean}
// */
// _isZip(file) {
// return file.type === 'application/zip' || file.name.match(/\.zip$/)
// }

/**
* @throws
*/
private _fail(message: string) {
this._emit('droperror', {message: message})
}
}
export type DropEventType = 'drop'|'dropstart'|'droperror'
export type ListenerCallback = ((data?:{files?:Map<string, DropFile>, message?:string})=>void)
export interface DropFile extends File{
filePath: string
}

+ 1
- 0
src/utils/index.ts Прегледај датотеку

@@ -1,5 +1,6 @@
export * from './browser-helpers'
export {windowDialogWrapper, type IDialogWrapper} from './DialogWrapper'
export {GLStatsJS} from './GLStatsJS'
export {Dropzone, type DropFile, type ListenerCallback, type DropEventType} from './Dropzone'
export {ThreeSerialization, type SerializationMetaType, type SerializationResourcesType, MetaImporter} from './serialization'
export {shaderReplaceString} from './shader-helpers'

+ 29
- 9
src/viewer/ThreeViewer.ts Прегледај датотеку

@@ -34,6 +34,7 @@ import {
} from '../assetmanager'
import {GLStatsJS, IDialogWrapper, windowDialogWrapper} from '../utils'
import {IViewerPlugin, IViewerPluginSync} from './IViewerPlugin'
import {DropzonePlugin, DropzonePluginOptions} from '../plugins/interaction/DropzonePlugin'

export type IViewerEvent = BaseEvent & {
type: 'update'|'preRender'|'postRender'|'preFrame'|'postFrame'|'dispose'|'addPlugin'
@@ -66,7 +67,7 @@ export type IConsoleWrapper = Partial<Console> & Pick<Console, 'log'|'warn'|'err
* Options for the ThreeViewer creation.
* @category Viewer
*/
export interface ThreeViewerOptions extends AssetManagerOptions{
export interface ThreeViewerOptions {
/**
* The canvas element to use for rendering. Only one of container and canvas must be specified.
*/
@@ -95,6 +96,15 @@ export interface ThreeViewerOptions extends AssetManagerOptions{

debug?: boolean

assetManager?: AssetManagerOptions

/**
* Add the dropzone plugin to the viewer, allowing to drag and drop files into the viewer over the canvas/container.
* Set to true/false to enable/disable the plugin, or pass options to configure the plugin. Assuming true if options are passed.
* @default - false
*/
dropzone?: boolean|DropzonePluginOptions

/**
* @deprecated use {@link msaa} instead
*/
@@ -266,7 +276,7 @@ export class ThreeViewer extends EventDispatcher<IViewerEvent, IViewerEventTypes
this.setDirty(this.renderManager, e)
})

this.assetManager = new AssetManager(this, options)
this.assetManager = new AssetManager(this, options.assetManager)

if (this.resizeObserver) this.resizeObserver.observe(this._canvas)
// sometimes resize observer is late, so extra check
@@ -275,7 +285,13 @@ export class ThreeViewer extends EventDispatcher<IViewerEvent, IViewerEventTypes
this._canvas.addEventListener('webglcontextrestored', this._onContextRestore, false)
this._canvas.addEventListener('webglcontextlost', this._onContextLost, false)

if (options.dropzone) {
this.addPluginSync(new DropzonePlugin(typeof options.dropzone === 'object' ? options.dropzone : undefined))
}

this.console.log('ThreePipe Viewer instance initialized, version: ', ThreeViewer.VERSION)


}

private _objectProcessor: IObjectProcessor = {
@@ -347,19 +363,23 @@ export class ThreeViewer extends EventDispatcher<IViewerEvent, IViewerEventTypes
/**
* Set the environment map of the scene from url or an {@link IAsset} object.
* @param map
* @param options
* @param setBackground - Set the background image of the scene from the same map.
* @param options - Options for importing the asset. See {@link ImportAssetOptions}
*/
async setEnvironmentMap(map: string | IAsset | null, options?: ImportAssetOptions): Promise<void> {
this._scene.environment = map ? await this.assetManager.importer.importSingle<ITexture>(map, options) || null : null
async setEnvironmentMap(map: string | IAsset | null | ITexture, {setBackground = false, ...options}: ImportAssetOptions&{setBackground?: boolean} = {}): Promise<void> {
this._scene.environment = map && !(<ITexture>map).isTexture ? await this.assetManager.importer.importSingle<ITexture>(map as string|IAsset, options) || null : <ITexture>map || null
if (setBackground) return this.setBackgroundMap(this._scene.environment)
}

/**
* Set the background image of the scene from url or an {@link IAsset} object.
* @param map
* @param options
* @param setEnvironment - Set the environment map of the scene from the same map.
* @param options - Options for importing the asset. See {@link ImportAssetOptions}
*/
async setBackgroundMap(map: string | IAsset | null, options?: ImportAssetOptions): Promise<void> {
this._scene.background = map ? await this.assetManager.importer.importSingle<ITexture>(map, options) || null : null
async setBackgroundMap(map: string | IAsset | null | ITexture, {setEnvironment = false, ...options}: ImportAssetOptions&{setBackground?: boolean} = {}): Promise<void> {
this._scene.background = map && !(<ITexture>map).isTexture ? await this.assetManager.importer.importSingle<ITexture>(map as string|IAsset, options) || null : <ITexture>map || null
if (setEnvironment) return this.setEnvironmentMap(this._scene.background)
}

/**
@@ -757,7 +777,7 @@ export class ThreeViewer extends EventDispatcher<IViewerEvent, IViewerEventTypes
* Deserialize and import all the viewer and plugin settings, exported with {@link exportConfig}.
*/
async importConfig(json: ISerializedConfig|ISerializedViewerConfig) {
if (json.type !== this.type || <string>json.type !== 'ViewerApp') {
if (json.type !== this.type && <string>json.type !== 'ViewerApp') {
if (this.getPlugin(json.type)) {
return this.importPluginConfig(json)
} else {

Loading…
Откажи
Сачувај