| @@ -16,7 +16,7 @@ async function init() { | |||
| viewer.scene.addObject(new DirectionalLight2(0x0000ff, 1)) | |||
| const l = new DirectionalLight2(0xff0000, 1) | |||
| l.position.set(1, 1, 1) | |||
| l.target.position.set(-1, -1, -1) | |||
| viewer.scene.addObject(l) | |||
| await viewer.load('https://threejs.org/examples/models/gltf/ShadowmappableMesh.glb', { | |||
| @@ -9,7 +9,7 @@ | |||
| "version": "0.0.29", | |||
| "license": "Apache-2.0", | |||
| "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/wicg-file-system-access": "^2020.9.5", | |||
| "stats.js": "^0.17.0", | |||
| @@ -41,7 +41,7 @@ | |||
| "rollup-plugin-glsl": "^1.3.0", | |||
| "rollup-plugin-license": "^3.0.1", | |||
| "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", | |||
| "typedoc": "^0.25.7", | |||
| "typescript": "^5.3.3", | |||
| @@ -1401,9 +1401,9 @@ | |||
| "dev": true | |||
| }, | |||
| "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": { | |||
| "@tweenjs/tween.js": "~18.6.4", | |||
| "fflate": "~0.6.9", | |||
| @@ -10464,9 +10464,9 @@ | |||
| } | |||
| }, | |||
| "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, | |||
| "license": "MIT" | |||
| }, | |||
| @@ -102,7 +102,7 @@ | |||
| "rollup-plugin-glsl": "^1.3.0", | |||
| "rollup-plugin-license": "^3.0.1", | |||
| "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", | |||
| "typedoc": "^0.25.7", | |||
| "typescript": "^5.3.3", | |||
| @@ -111,7 +111,7 @@ | |||
| "vite-plugin-dts": "^3.7.0" | |||
| }, | |||
| "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/wicg-file-system-access": "^2020.9.5", | |||
| "stats.js": "^0.17.0", | |||
| @@ -122,10 +122,10 @@ | |||
| "dependencies": { | |||
| "uiconfig.js": "^0.0.12", | |||
| "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" | |||
| }, | |||
| "local_dependencies": { | |||
| @@ -1,7 +1,7 @@ | |||
| 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 {GLTFWriter2} from './GLTFWriter2' | |||
| import {Object3D} from 'three' | |||
| import {AnimationClip, Object3D} from 'three' | |||
| import {ThreeViewer} from '../../viewer' | |||
| import { | |||
| glbEncryptionProcessor, | |||
| @@ -15,7 +15,7 @@ import { | |||
| GLTFViewerConfigExtension, | |||
| } from '../gltf' | |||
| export type GLTFExporter2Options = { | |||
| export interface GLTFExporter2Options { | |||
| /** | |||
| * embed images in glb even when remote url is available | |||
| * @default false | |||
| @@ -62,8 +62,52 @@ export type GLTFExporter2Options = { | |||
| */ | |||
| 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 | |||
| } & GLTFExporterOptions | |||
| } | |||
| export class GLTFExporter2 extends GLTFExporter implements IExportParser { | |||
| @@ -106,13 +150,14 @@ export class GLTFExporter2 extends GLTFExporter implements IExportParser { | |||
| const gltfOptions: GLTFWriter2['options'] = { | |||
| // default options | |||
| 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 | |||
| maxTextureSize: Infinity, | |||
| animations: [], | |||
| includeCustomExtensions: true, | |||
| maxTextureSize: options.maxTextureSize ?? Infinity, | |||
| animations: options.animations ?? [], | |||
| includeCustomExtensions: options.includeCustomExtensions ?? true, | |||
| forceIndices: options.forceIndices ?? false, | |||
| exporterOptions: options, | |||
| } | |||
| if (options.exportExt === 'glb') { | |||
| @@ -240,7 +240,7 @@ export class RootScene extends Scene<ISceneEvent, ISceneEventTypes> implements I | |||
| if (addToRoot) this.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?.() | |||
| } else { | |||
| obj.userData.isCentered = true // mark as centered, so that autoCenter is not called again when file is reloaded. | |||
| @@ -15,6 +15,7 @@ export class PickingPlugin extends AViewerPluginSync<'selectedObjectChanged'|'ho | |||
| return this._picker | |||
| } | |||
| static readonly PluginType = 'Picking' | |||
| static readonly OldPluginType = 'PickingPlugin' // todo: swap | |||
| private _picker?: ObjectPicker | |||
| private _widget?: SelectionWidget | |||
| private _hoverWidget?: SelectionWidget | |||
| @@ -46,6 +46,13 @@ export class FrameFadePlugin | |||
| 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 | |||
| if (!this._viewer || !this._pass || this.isDisabled()) return | |||
| if (!this._target) | |||
| @@ -55,14 +62,20 @@ export class FrameFadePlugin | |||
| magFilter: LinearFilter, | |||
| 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.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() | |||
| await timeout(duration) | |||
| } | |||
| /** | |||
| * Stop a frame fade transition if running. Note that it will be stopped next frame. | |||
| */ | |||
| public stopTransition() { | |||
| if (!this._pass) return | |||
| this._pass.fadeTimeState = 0. // will be stopped in update on next frame | |||
| @@ -88,7 +101,6 @@ export class FrameFadePlugin | |||
| super.onRemove(viewer) | |||
| } | |||
| private _fadeCam = async(ev: any)=> | |||
| ev.frameFade !== false && this.fadeOnActiveCameraChange && this.startTransition(ev.fadeDuration || 1000) | |||
| private _fadeMat = async(ev: any)=> | |||
| @@ -160,7 +160,6 @@ export class ProgressivePlugin | |||
| } | |||
| fromJSON(data: ISerializedConfig&{pass?: any}, meta?: SerializationMetaType): this|null|Promise<this|null> { | |||
| console.log(data) | |||
| if (data.jitter !== undefined) { | |||
| const ssaa = this._viewer?.getPlugin(SSAAPlugin) | |||
| if (!ssaa) { | |||
| @@ -950,8 +950,8 @@ export class ThreeViewer extends EventDispatcher<IViewerEvent, IViewerEventTypes | |||
| async addSceneObject<T extends IObject3D|Object3D|RootSceneImportResult = RootSceneImportResult>(imported: T, options?: AddObjectOptions): Promise<T> { | |||
| if (imported.userData?.rootSceneModelRoot) { | |||
| const obj = <RootSceneImportResult>imported | |||
| if (obj.importedViewerConfig && options?.importConfig !== false) await this.importConfig(obj.importedViewerConfig) | |||
| this._scene.loadModelRoot(obj, options) | |||
| if (obj.importedViewerConfig && options?.importConfig !== false) await this.importConfig(obj.importedViewerConfig) | |||
| return this._scene.modelRoot as T | |||
| } | |||
| this._scene.addObject(imported, options) | |||