| viewer.scene.addObject(new DirectionalLight2(0x0000ff, 1)) | viewer.scene.addObject(new DirectionalLight2(0x0000ff, 1)) | ||||
| const l = new DirectionalLight2(0xff0000, 1) | const l = new DirectionalLight2(0xff0000, 1) | ||||
| l.position.set(1, 1, 1) | |||||
| l.target.position.set(-1, -1, -1) | |||||
| viewer.scene.addObject(l) | viewer.scene.addObject(l) | ||||
| await viewer.load('https://threejs.org/examples/models/gltf/ShadowmappableMesh.glb', { | await viewer.load('https://threejs.org/examples/models/gltf/ShadowmappableMesh.glb', { |
| "version": "0.0.29", | "version": "0.0.29", | ||||
| "license": "Apache-2.0", | "license": "Apache-2.0", | ||||
| "dependencies": { | "dependencies": { | ||||
| "@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1020/package.tgz", | |||||
| "@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.153.1002/package.tgz", | |||||
| "@types/webxr": "^0.5.1", | "@types/webxr": "^0.5.1", | ||||
| "@types/wicg-file-system-access": "^2020.9.5", | "@types/wicg-file-system-access": "^2020.9.5", | ||||
| "stats.js": "^0.17.0", | "stats.js": "^0.17.0", | ||||
| "rollup-plugin-glsl": "^1.3.0", | "rollup-plugin-glsl": "^1.3.0", | ||||
| "rollup-plugin-license": "^3.0.1", | "rollup-plugin-license": "^3.0.1", | ||||
| "rollup-plugin-postcss": "^4.0.2", | "rollup-plugin-postcss": "^4.0.2", | ||||
| "three": "https://github.com/repalash/three.js-modded/releases/download/v0.152.2021/package.tgz", | |||||
| "three": "https://github.com/repalash/three.js-modded/releases/download/v0.153.1003/package.tgz", | |||||
| "tslib": "^2.5.0", | "tslib": "^2.5.0", | ||||
| "typedoc": "^0.25.7", | "typedoc": "^0.25.7", | ||||
| "typescript": "^5.3.3", | "typescript": "^5.3.3", | ||||
| "dev": true | "dev": true | ||||
| }, | }, | ||||
| "node_modules/@types/three": { | "node_modules/@types/three": { | ||||
| "version": "0.152.1020", | |||||
| "resolved": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1020/package.tgz", | |||||
| "integrity": "sha512-Xnfma6acJylMQEBYiEOBAUifspGy2ao1UQ2ecYDKAFMwC04fDhTnO2LELluk3j/o/8qaYadOW4OcjvMKLOxTdg==", | |||||
| "version": "0.153.1002", | |||||
| "resolved": "https://github.com/repalash/three-ts-types/releases/download/v0.153.1002/package.tgz", | |||||
| "integrity": "sha512-C0gfzxmzvVR0dwzBtHlgA7HoTUoLeDalMksQCgq+suzqhAfbgLVBjE641NtNiEyp1TQmEOCVfgBBzpq3AboRpg==", | |||||
| "dependencies": { | "dependencies": { | ||||
| "@tweenjs/tween.js": "~18.6.4", | "@tweenjs/tween.js": "~18.6.4", | ||||
| "fflate": "~0.6.9", | "fflate": "~0.6.9", | ||||
| } | } | ||||
| }, | }, | ||||
| "node_modules/three": { | "node_modules/three": { | ||||
| "version": "0.152.2021", | |||||
| "resolved": "https://github.com/repalash/three.js-modded/releases/download/v0.152.2021/package.tgz", | |||||
| "integrity": "sha512-va2FQU/ES07GLdflqysT82rh8x+cwx0sCYB8w+JGjDCAcwYDYqvjWafWzWP0UrDR8JM+8HoCLwh+rHtGU5Eoug==", | |||||
| "version": "0.153.1003", | |||||
| "resolved": "https://github.com/repalash/three.js-modded/releases/download/v0.153.1003/package.tgz", | |||||
| "integrity": "sha512-AkqexatP6oS6RH3cryt1L535XFaQrb+np9pjGJZxU4dv63dZN2Hvp6vj+TBRd9hDTGmn1vC2zG64x46xWD8oSg==", | |||||
| "dev": true, | "dev": true, | ||||
| "license": "MIT" | "license": "MIT" | ||||
| }, | }, |
| "rollup-plugin-glsl": "^1.3.0", | "rollup-plugin-glsl": "^1.3.0", | ||||
| "rollup-plugin-license": "^3.0.1", | "rollup-plugin-license": "^3.0.1", | ||||
| "rollup-plugin-postcss": "^4.0.2", | "rollup-plugin-postcss": "^4.0.2", | ||||
| "three": "https://github.com/repalash/three.js-modded/releases/download/v0.152.2021/package.tgz", | |||||
| "three": "https://github.com/repalash/three.js-modded/releases/download/v0.153.1003/package.tgz", | |||||
| "tslib": "^2.5.0", | "tslib": "^2.5.0", | ||||
| "typedoc": "^0.25.7", | "typedoc": "^0.25.7", | ||||
| "typescript": "^5.3.3", | "typescript": "^5.3.3", | ||||
| "vite-plugin-dts": "^3.7.0" | "vite-plugin-dts": "^3.7.0" | ||||
| }, | }, | ||||
| "dependencies": { | "dependencies": { | ||||
| "@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1020/package.tgz", | |||||
| "@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.153.1002/package.tgz", | |||||
| "@types/webxr": "^0.5.1", | "@types/webxr": "^0.5.1", | ||||
| "@types/wicg-file-system-access": "^2020.9.5", | "@types/wicg-file-system-access": "^2020.9.5", | ||||
| "stats.js": "^0.17.0", | "stats.js": "^0.17.0", | ||||
| "dependencies": { | "dependencies": { | ||||
| "uiconfig.js": "^0.0.12", | "uiconfig.js": "^0.0.12", | ||||
| "ts-browser-helpers": "^0.12.0", | "ts-browser-helpers": "^0.12.0", | ||||
| "three": "https://github.com/repalash/three.js-modded/releases/download/v0.152.2021/package.tgz", | |||||
| "three-f": "https://github.com/repalash/three.js-modded/archive/refs/tags/v0.152.2021.tar.gz", | |||||
| "@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1020/package.tgz", | |||||
| "@types/three-f": "https://github.com/repalash/three-ts-types/archive/refs/tags/v0.152.1020.tar.gz", | |||||
| "three": "https://github.com/repalash/three.js-modded/releases/download/v0.153.1003/package.tgz", | |||||
| "three-f": "https://github.com/repalash/three.js-modded/archive/refs/tags/v0.153.1003.tar.gz", | |||||
| "@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.153.1002/package.tgz", | |||||
| "@types/three-f": "https://github.com/repalash/three-ts-types/archive/refs/tags/v0.153.1002.tar.gz", | |||||
| "@types/three-pkg": "https://gitpkg.now.sh/repalash/three-ts-types/types/three?modded_three" | "@types/three-pkg": "https://gitpkg.now.sh/repalash/three-ts-types/types/three?modded_three" | ||||
| }, | }, | ||||
| "local_dependencies": { | "local_dependencies": { |
| import {GLTFExporter, GLTFExporterOptions, GLTFExporterPlugin} from 'three/examples/jsm/exporters/GLTFExporter.js' | |||||
| import {GLTFExporter, GLTFExporterPlugin} from 'three/examples/jsm/exporters/GLTFExporter.js' | |||||
| import {IExportParser} from '../IExporter' | import {IExportParser} from '../IExporter' | ||||
| import {GLTFWriter2} from './GLTFWriter2' | import {GLTFWriter2} from './GLTFWriter2' | ||||
| import {Object3D} from 'three' | |||||
| import {AnimationClip, Object3D} from 'three' | |||||
| import {ThreeViewer} from '../../viewer' | import {ThreeViewer} from '../../viewer' | ||||
| import { | import { | ||||
| glbEncryptionProcessor, | glbEncryptionProcessor, | ||||
| GLTFViewerConfigExtension, | GLTFViewerConfigExtension, | ||||
| } from '../gltf' | } from '../gltf' | ||||
| export type GLTFExporter2Options = { | |||||
| export interface GLTFExporter2Options { | |||||
| /** | /** | ||||
| * embed images in glb even when remote url is available | * embed images in glb even when remote url is available | ||||
| * @default false | * @default false | ||||
| */ | */ | ||||
| encryptKey?: string|Uint8Array, | encryptKey?: string|Uint8Array, | ||||
| // From GLTFExporter | |||||
| /** | |||||
| * Export position, rotation and scale instead of matrix per node. | |||||
| * Default is false | |||||
| */ | |||||
| trs?: boolean; | |||||
| /** | |||||
| * Export only visible objects. | |||||
| * Default is false. | |||||
| */ | |||||
| onlyVisible?: boolean; | |||||
| /** | |||||
| * Export just the attributes within the drawRange, if defined, instead of exporting the whole array. | |||||
| * Default is true. | |||||
| */ | |||||
| truncateDrawRange?: boolean; | |||||
| /** | |||||
| * Restricts the image maximum size (both width and height) to the given value. This option works only if embedImages is true. | |||||
| * Default is Infinity. | |||||
| */ | |||||
| maxTextureSize?: number; | |||||
| /** | |||||
| * List of animations to be included in the export. | |||||
| */ | |||||
| animations?: AnimationClip[]; | |||||
| /** | |||||
| * Generate indices for non-index geometry and export with them. | |||||
| * Default is false. | |||||
| */ | |||||
| forceIndices?: boolean; | |||||
| /** | |||||
| * Export custom glTF extensions defined on an object's userData.gltfExtensions property. | |||||
| * Default is true. | |||||
| */ | |||||
| includeCustomExtensions?: boolean; | |||||
| [key: string]: any | [key: string]: any | ||||
| } & GLTFExporterOptions | |||||
| } | |||||
| export class GLTFExporter2 extends GLTFExporter implements IExportParser { | export class GLTFExporter2 extends GLTFExporter implements IExportParser { | ||||
| const gltfOptions: GLTFWriter2['options'] = { | const gltfOptions: GLTFWriter2['options'] = { | ||||
| // default options | // default options | ||||
| binary: false, | binary: false, | ||||
| trs: false, | |||||
| onlyVisible: true, | |||||
| truncateDrawRange: true, | |||||
| trs: options.trs ?? false, | |||||
| onlyVisible: options.onlyVisible ?? false, | |||||
| truncateDrawRange: options.truncateDrawRange ?? true, | |||||
| externalImagesInExtras: !options.embedUrlImages && options.externalImagesInExtras || false, // this is handled in gltfMaterialExtrasWriter, also see GLTFDracoExporter | externalImagesInExtras: !options.embedUrlImages && options.externalImagesInExtras || false, // this is handled in gltfMaterialExtrasWriter, also see GLTFDracoExporter | ||||
| maxTextureSize: Infinity, | |||||
| animations: [], | |||||
| includeCustomExtensions: true, | |||||
| maxTextureSize: options.maxTextureSize ?? Infinity, | |||||
| animations: options.animations ?? [], | |||||
| includeCustomExtensions: options.includeCustomExtensions ?? true, | |||||
| forceIndices: options.forceIndices ?? false, | |||||
| exporterOptions: options, | exporterOptions: options, | ||||
| } | } | ||||
| if (options.exportExt === 'glb') { | if (options.exportExt === 'glb') { |
| if (addToRoot) this.add(obj) | if (addToRoot) this.add(obj) | ||||
| else this.modelRoot.add(obj) | else this.modelRoot.add(obj) | ||||
| if (autoCenter && !obj.userData.isCentered) { | |||||
| if (autoCenter && !obj.userData.isCentered && !obj.userData.pseudoCentered) { // pseudoCentered is legacy | |||||
| obj.autoCenter?.() | obj.autoCenter?.() | ||||
| } else { | } else { | ||||
| obj.userData.isCentered = true // mark as centered, so that autoCenter is not called again when file is reloaded. | obj.userData.isCentered = true // mark as centered, so that autoCenter is not called again when file is reloaded. |
| return this._picker | return this._picker | ||||
| } | } | ||||
| static readonly PluginType = 'Picking' | static readonly PluginType = 'Picking' | ||||
| static readonly OldPluginType = 'PickingPlugin' // todo: swap | |||||
| private _picker?: ObjectPicker | private _picker?: ObjectPicker | ||||
| private _widget?: SelectionWidget | private _widget?: SelectionWidget | ||||
| private _hoverWidget?: SelectionWidget | private _hoverWidget?: SelectionWidget |
| this.isDisabled = ((sup)=>()=>!this._pointerEnabled || sup())(this.isDisabled) | this.isDisabled = ((sup)=>()=>!this._pointerEnabled || sup())(this.isDisabled) | ||||
| } | } | ||||
| saveFrameTimeThreshold = 500 // ms | |||||
| /** | |||||
| * Start a frame fade transition. | |||||
| * Note that the current frame data will only be used if the last running transition is ended or near the end. To do it anyway, call {@link stopTransition} first | |||||
| * @param duration | |||||
| */ | |||||
| public async startTransition(duration: number) { // duration in ms | public async startTransition(duration: number) { // duration in ms | ||||
| if (!this._viewer || !this._pass || this.isDisabled()) return | if (!this._viewer || !this._pass || this.isDisabled()) return | ||||
| if (!this._target) | if (!this._target) | ||||
| magFilter: LinearFilter, | magFilter: LinearFilter, | ||||
| colorSpace: (this._viewer.renderManager.composerTarget.texture as ITexture).colorSpace, | colorSpace: (this._viewer.renderManager.composerTarget.texture as ITexture).colorSpace, | ||||
| }) | }) | ||||
| if (this._pass.fadeTimeState < this.saveFrameTimeThreshold) // only save if very near the end | |||||
| this._pass.toSaveFrame = true | |||||
| this._pass.fadeTimeState = Math.max(duration, this._pass.fadeTimeState) | this._pass.fadeTimeState = Math.max(duration, this._pass.fadeTimeState) | ||||
| this._pass.fadeTime = this._pass.fadeTimeState | this._pass.fadeTime = this._pass.fadeTimeState | ||||
| if (this._pass.fadeTimeState < 500) // only save if very near the end | |||||
| this._pass.toSaveFrame = true | |||||
| // this._pass.passObject.enabled = true | |||||
| // this._pass.enabled = true | |||||
| this.setDirty() | this.setDirty() | ||||
| await timeout(duration) | await timeout(duration) | ||||
| } | } | ||||
| /** | |||||
| * Stop a frame fade transition if running. Note that it will be stopped next frame. | |||||
| */ | |||||
| public stopTransition() { | public stopTransition() { | ||||
| if (!this._pass) return | if (!this._pass) return | ||||
| this._pass.fadeTimeState = 0. // will be stopped in update on next frame | this._pass.fadeTimeState = 0. // will be stopped in update on next frame | ||||
| super.onRemove(viewer) | super.onRemove(viewer) | ||||
| } | } | ||||
| private _fadeCam = async(ev: any)=> | private _fadeCam = async(ev: any)=> | ||||
| ev.frameFade !== false && this.fadeOnActiveCameraChange && this.startTransition(ev.fadeDuration || 1000) | ev.frameFade !== false && this.fadeOnActiveCameraChange && this.startTransition(ev.fadeDuration || 1000) | ||||
| private _fadeMat = async(ev: any)=> | private _fadeMat = async(ev: any)=> |
| } | } | ||||
| fromJSON(data: ISerializedConfig&{pass?: any}, meta?: SerializationMetaType): this|null|Promise<this|null> { | fromJSON(data: ISerializedConfig&{pass?: any}, meta?: SerializationMetaType): this|null|Promise<this|null> { | ||||
| console.log(data) | |||||
| if (data.jitter !== undefined) { | if (data.jitter !== undefined) { | ||||
| const ssaa = this._viewer?.getPlugin(SSAAPlugin) | const ssaa = this._viewer?.getPlugin(SSAAPlugin) | ||||
| if (!ssaa) { | if (!ssaa) { |
| async addSceneObject<T extends IObject3D|Object3D|RootSceneImportResult = RootSceneImportResult>(imported: T, options?: AddObjectOptions): Promise<T> { | async addSceneObject<T extends IObject3D|Object3D|RootSceneImportResult = RootSceneImportResult>(imported: T, options?: AddObjectOptions): Promise<T> { | ||||
| if (imported.userData?.rootSceneModelRoot) { | if (imported.userData?.rootSceneModelRoot) { | ||||
| const obj = <RootSceneImportResult>imported | const obj = <RootSceneImportResult>imported | ||||
| if (obj.importedViewerConfig && options?.importConfig !== false) await this.importConfig(obj.importedViewerConfig) | |||||
| this._scene.loadModelRoot(obj, options) | this._scene.loadModelRoot(obj, options) | ||||
| if (obj.importedViewerConfig && options?.importConfig !== false) await this.importConfig(obj.importedViewerConfig) | |||||
| return this._scene.modelRoot as T | return this._scene.modelRoot as T | ||||
| } | } | ||||
| this._scene.addObject(imported, options) | this._scene.addObject(imported, options) |