| @@ -15,7 +15,7 @@ | |||
| "build-examples": "tsc --project examples/tsconfig.build.json", | |||
| "dev-examples": "tsc --project examples/tsconfig.build.json -w", | |||
| "serve-docs": "ws -d docs -p 8080", | |||
| "serve": "ws -d . -p 8000", | |||
| "serve": "ws -d . -p 9229", | |||
| "docs": "npx typedoc && markdown-to-html", | |||
| "prepare": "npm run build && npm run build-examples && npm run docs" | |||
| }, | |||
| @@ -89,6 +89,7 @@ export class AssetManager extends EventDispatcher<BaseEvent&{data: ImportResult} | |||
| this.viewer = viewer | |||
| this.viewer.scene.addEventListener('addSceneObject', this._sceneUpdated) | |||
| this.viewer.scene.addEventListener('materialChanged', this._sceneUpdated) | |||
| this.viewer.scene.addEventListener('beforeDeserialize', this._sceneUpdated) | |||
| this._initCacheStorage(simpleCache, storage ?? true) | |||
| this.importer.addEventListener('processRaw', (event)=>{ | |||
| @@ -278,6 +279,23 @@ export class AssetManager extends EventDispatcher<BaseEvent&{data: ImportResult} | |||
| for (const t of targets) { | |||
| this.materials.registerMaterial(t) | |||
| } | |||
| } else if (event.type === 'beforeDeserialize') { | |||
| // object/material/texture to be deserialized | |||
| const data = event.data | |||
| const meta = event.meta | |||
| if (!data.metadata) { | |||
| console.warn('Invalid data(no metadata)', data) | |||
| } | |||
| console.log(data, event) | |||
| if (event.material) { | |||
| if (data.metadata?.type !== 'Material') { | |||
| console.warn('Invalid material data', data) | |||
| } | |||
| JSONMaterialLoader.DeserializeMaterialJSON(data, this.viewer, meta, event.material).then(()=>{ | |||
| // | |||
| }) | |||
| } | |||
| } else { | |||
| console.error('Unexpected') | |||
| } | |||
| @@ -1,6 +1,7 @@ | |||
| import {SimpleJSONLoader} from './SimpleJSONLoader' | |||
| import {ThreeViewer} from '../../viewer' | |||
| import {getEmptyMeta, SerializationMetaType, ThreeSerialization} from '../../utils/serialization' | |||
| import {IMaterial} from '../../core' | |||
| export class JSONMaterialLoader extends SimpleJSONLoader { | |||
| @@ -10,7 +11,11 @@ export class JSONMaterialLoader extends SimpleJSONLoader { | |||
| if (!this.viewer) throw 'Viewer not set in JSONMaterialLoader.' | |||
| const json = await super.loadAsync(url, onProgress) as any | |||
| const meta: SerializationMetaType = getEmptyMeta() | |||
| return await JSONMaterialLoader.DeserializeMaterialJSON(json, this.viewer) | |||
| } | |||
| static async DeserializeMaterialJSON(json: any, viewer: ThreeViewer, meta?: SerializationMetaType, obj?: IMaterial|IMaterial[]) { | |||
| meta = meta || getEmptyMeta() | |||
| const json2 = {...json} | |||
| if (json.images) { | |||
| if (Array.isArray(json.images)) meta.images = Object.fromEntries(json.images.map((i: any) => [i.uuid, i])) | |||
| @@ -27,7 +32,7 @@ export class JSONMaterialLoader extends SimpleJSONLoader { | |||
| else meta.materials = json.materials | |||
| delete json2.materials | |||
| } | |||
| const resources = await this.viewer.loadConfigResources(meta) | |||
| return ThreeSerialization.Deserialize(json2, undefined, resources) | |||
| const resources = await viewer.loadConfigResources(meta) | |||
| return ThreeSerialization.Deserialize(json2, obj || undefined, resources) | |||
| } | |||
| } | |||
| @@ -90,9 +90,9 @@ export interface ICamera<E extends ICameraEvent = ICameraEvent, ET extends ICame | |||
| traverse(callback: (object: IObject3D) => void): void | |||
| traverseVisible(callback: (object: IObject3D) => void): void | |||
| traverseAncestors(callback: (object: IObject3D) => void): void | |||
| getObjectById(id: number): IObject3D | undefined | |||
| getObjectByName(name: string): IObject3D | undefined | |||
| getObjectByProperty(name: string, value: string): IObject3D | undefined | |||
| getObjectById<T extends IObject3D = IObject3D>(id: number): T | undefined | |||
| getObjectByName<T extends IObject3D = IObject3D>(name: string): T | undefined | |||
| getObjectByProperty<T extends IObject3D = IObject3D>(name: string, value: string): T | undefined | |||
| copy(source: this, recursive?: boolean, distanceFromTarget?: number, ...args: any[]): this | |||
| clone(recursive?: boolean): this | |||
| add(...object: IObject3D[]): this | |||
| @@ -1,23 +1,44 @@ | |||
| import type {Event, IUniform, Material, MaterialParameters, Shader} from 'three' | |||
| import type {AnyOptions, IDisposable, IJSONSerializable} from 'ts-browser-helpers' | |||
| import type {IDisposable, IJSONSerializable} from 'ts-browser-helpers' | |||
| import type {MaterialExtension} from '../materials' | |||
| import type {IUiConfigContainer} from 'uiconfig.js' | |||
| import type {SerializationMetaType} from '../utils/serialization' | |||
| import type {ChangeEvent, IUiConfigContainer} from 'uiconfig.js' | |||
| import type {SerializationMetaType} from '../utils' | |||
| import type {IObject3D} from './IObject' | |||
| import type {ITexture} from './ITexture' | |||
| import type {IImportResultUserData} from '../assetmanager' | |||
| export type IMaterialParameters = MaterialParameters & {customMaterialExtensions?: MaterialExtension[]} | |||
| export type IMaterialEventTypes = 'dispose' | 'materialUpdate' | 'beforeRender' | 'beforeCompile' | 'afterRender' | 'textureChanged' | |||
| export type IMaterialEventTypes = 'dispose' | 'materialUpdate' | 'beforeRender' | 'beforeCompile' | 'afterRender' | 'textureChanged' | 'beforeDeserialize' | |||
| export type IMaterialEvent<T extends string = IMaterialEventTypes> = Event & { | |||
| type: T | |||
| bubbleToObject?: boolean | |||
| bubbleToParent?: boolean | |||
| material?: IMaterial | |||
| texture?: ITexture | |||
| oldTexture?: ITexture | |||
| uiChangeEvent?: ChangeEvent | |||
| } | |||
| export interface IMaterialSetDirtyOptions { | |||
| /** | |||
| * @default true | |||
| */ | |||
| bubbleToObject?: boolean, | |||
| /** | |||
| * @default true | |||
| */ | |||
| refreshUi?: boolean, | |||
| /** | |||
| * @default true | |||
| */ | |||
| needsUpdate?: boolean, | |||
| /** | |||
| * Event from uiconfig.js | |||
| */ | |||
| uiChangeEvent?: ChangeEvent, | |||
| [key: string]: any | |||
| } | |||
| export type IMaterialSetDirtyOptions = AnyOptions & {bubbleToObject?: boolean} | |||
| export interface IMaterialUserData extends IImportResultUserData{ | |||
| uuid?: string // adding to userdata also, so that its saved in gltf | |||
| @@ -1,5 +1,5 @@ | |||
| import {IDisposable} from 'ts-browser-helpers' | |||
| import {IMaterial, IMaterialEvent} from './IMaterial' | |||
| import {IMaterial} from './IMaterial' | |||
| import {Event, Object3D} from 'three' | |||
| import {IUiConfigContainer, UiObjectConfig} from 'uiconfig.js' | |||
| import {IGeometry, IGeometryEvent} from './IGeometry' | |||
| @@ -7,7 +7,7 @@ import {IImportResultUserData} from '../assetmanager' | |||
| import {GLTF} from 'three/examples/jsm/loaders/GLTFLoader.js' | |||
| export type IObject3DEventTypes = 'dispose' | 'materialUpdate' | 'objectUpdate' | 'geometryChanged' | | |||
| 'materialChanged' | 'geometryUpdate' | 'added' | 'removed' | 'select' | | |||
| 'materialChanged' | 'geometryUpdate' | 'added' | 'removed' | 'select' | 'beforeDeserialize' | | |||
| 'setView' | 'activateMain' | 'cameraUpdate' // from camera | |||
| // | string | |||
| export interface IObject3DEvent<T extends string = IObject3DEventTypes> extends Event { | |||
| @@ -168,8 +168,6 @@ export interface IObject3D<E extends Event = IObject3DEvent, ET = IObject3DEvent | |||
| modelObject: this | |||
| // eslint-disable-next-line @typescript-eslint/naming-convention | |||
| _onMaterialUpdate?: (e: IMaterialEvent<'materialUpdate'>) => void | |||
| // eslint-disable-next-line @typescript-eslint/naming-convention | |||
| _onGeometryUpdate?: (e: IGeometryEvent<'geometryUpdate'>) => void | |||
| @@ -183,9 +181,9 @@ export interface IObject3D<E extends Event = IObject3DEvent, ET = IObject3DEvent | |||
| traverse(callback: (object: IObject3D) => void): void | |||
| traverseVisible(callback: (object: IObject3D) => void): void | |||
| traverseAncestors(callback: (object: IObject3D) => void): void | |||
| getObjectById(id: number): IObject3D | undefined | |||
| getObjectByName(name: string): IObject3D | undefined | |||
| getObjectByProperty(name: string, value: string): IObject3D | undefined | |||
| getObjectById<T extends IObject3D = IObject3D>(id: number): T | undefined | |||
| getObjectByName<T extends IObject3D = IObject3D>(name: string): T | undefined | |||
| getObjectByProperty<T extends IObject3D = IObject3D>(name: string, value: string): T | undefined | |||
| copy(source: this, recursive?: boolean, ...args: any[]): this | |||
| clone(recursive?: boolean): this | |||
| add(...object: IObject3D[]): this | |||
| @@ -127,9 +127,9 @@ export interface IScene<E extends ISceneEvent = ISceneEvent, ET extends ISceneEv | |||
| traverse(callback: (object: IObject3D) => void): void | |||
| traverseVisible(callback: (object: IObject3D) => void): void | |||
| traverseAncestors(callback: (object: IObject3D) => void): void | |||
| getObjectById(id: number): IObject3D | undefined | |||
| getObjectByName(name: string): IObject3D | undefined | |||
| getObjectByProperty(name: string, value: string): IObject3D | undefined | |||
| getObjectById<T extends IObject3D = IObject3D>(id: number): T | undefined | |||
| getObjectByName<T extends IObject3D = IObject3D>(name: string): T | undefined | |||
| getObjectByProperty<T extends IObject3D = IObject3D>(name: string, value: string): T | undefined | |||
| copy(source: this, recursive?: boolean): this | |||
| clone(recursive?: boolean): this | |||
| add(...object: IObject3D[]): this | |||
| @@ -453,9 +453,9 @@ export class PerspectiveCamera2 extends PerspectiveCamera implements ICamera { | |||
| traverse: (callback: (object: IObject3D) => void) => void | |||
| traverseVisible: (callback: (object: IObject3D) => void) => void | |||
| traverseAncestors: (callback: (object: IObject3D) => void) => void | |||
| getObjectById: (id: number) => IObject3D | undefined | |||
| getObjectByName: (name: string) => IObject3D | undefined | |||
| getObjectByProperty: (name: string, value: string) => IObject3D | undefined | |||
| getObjectById: <T extends IObject3D = IObject3D>(id: number) => T | undefined | |||
| getObjectByName: <T extends IObject3D = IObject3D>(name: string) => T | undefined | |||
| getObjectByProperty: <T extends IObject3D = IObject3D>(name: string, value: string) => T | undefined | |||
| copy: (source: ICamera|Camera, recursive?: boolean, distanceFromTarget?: number) => this | |||
| clone: (recursive?: boolean) => this | |||
| add: (...object: IObject3D[]) => this | |||
| @@ -25,8 +25,9 @@ import { | |||
| SubtractiveBlending, | |||
| TangentSpaceNormalMap, | |||
| } from 'three' | |||
| import {downloadBlob} from 'ts-browser-helpers' | |||
| import {downloadBlob, uploadFile} from 'ts-browser-helpers' | |||
| import {PhysicalMaterial} from './PhysicalMaterial' | |||
| import {getEmptyMeta} from '../../utils/serialization' | |||
| export const iMaterialUI = { | |||
| base: (material: IMaterial): UiObjectConfig[] => [ | |||
| @@ -73,7 +74,7 @@ export const iMaterialUI = { | |||
| { | |||
| type: 'checkbox', | |||
| property: [material, 'transparent'], | |||
| onChange: material.setDirty, | |||
| onChange: (ev)=>material.setDirty({uiChangeEvent: ev}), | |||
| }, | |||
| { | |||
| type: 'dropdown', | |||
| @@ -95,12 +96,12 @@ export const iMaterialUI = { | |||
| { | |||
| type: 'checkbox', | |||
| property: [material, 'depthTest'], | |||
| onChange: material.setDirty, | |||
| onChange: (ev)=>material.setDirty({uiChangeEvent: ev}), | |||
| }, | |||
| { | |||
| type: 'checkbox', | |||
| property: [material, 'depthWrite'], | |||
| onChange: material.setDirty, | |||
| onChange: (ev)=>material.setDirty({uiChangeEvent: ev}), | |||
| }, | |||
| { | |||
| type: 'slider', | |||
| @@ -229,10 +230,22 @@ export const iMaterialUI = { | |||
| }, | |||
| { | |||
| type: 'button', | |||
| label: `Download ${material.constructor.TypeSlug}}`, | |||
| label: `Download ${material.constructor.TypeSlug}`, | |||
| value: ()=>{ | |||
| const blob = new Blob([JSON.stringify(material.toJSON(), null, 2)], {type: 'application/json'}) | |||
| downloadBlob(blob, `unlit-material.${material.constructor.TypeSlug}`) | |||
| downloadBlob(blob, `material.${material.constructor.TypeSlug}`) | |||
| }, | |||
| }, | |||
| { | |||
| type: 'button', | |||
| label: `Select ${material.constructor.TypeSlug}`, | |||
| value: ()=>{ | |||
| uploadFile(false, false, material.constructor.TypeSlug).then(async(files)=>files?.[0]?.text()).then((text)=>{ | |||
| if (!text) return | |||
| const json = JSON.parse(text) | |||
| if (json.uuid) delete json.uuid // just copy the material properties | |||
| material.fromJSON(json, getEmptyMeta()) | |||
| }) | |||
| }, | |||
| }, | |||
| ()=>material.materialExtensions?.map(v=>v.getUiConfig?.(material, material.uiConfig?.uiRefresh)).filter(v=>v), | |||
| @@ -45,6 +45,7 @@ export class PhysicalMaterial extends MeshPhysicalMaterial<IMaterialEvent, Physi | |||
| readonly appliedMeshes: Set<IObject3D> = new Set() | |||
| readonly setDirty = iMaterialCommons.setDirty | |||
| clone(): this {return iMaterialCommons.clone(super.clone).call(this)} | |||
| dispatchEvent(event: IMaterialEvent): void {iMaterialCommons.dispatchEvent(super.dispatchEvent).call(this, event)} | |||
| generator?: IMaterialGenerator | |||
| @@ -123,6 +124,10 @@ export class PhysicalMaterial extends MeshPhysicalMaterial<IMaterialEvent, Physi | |||
| label: 'Physical Material', | |||
| uuid: 'MPM2_' + this.uuid, | |||
| expanded: true, | |||
| onChange: (ev)=>{ | |||
| if (!ev.config || ev.config.onChange) return | |||
| this.setDirty({uiChangeEvent: ev, needsUpdate: false, refreshUi: true}) | |||
| }, | |||
| children: [ | |||
| ...iMaterialUI.base(this), | |||
| iMaterialUI.blending(this), | |||
| @@ -188,8 +193,8 @@ export class PhysicalMaterial extends MeshPhysicalMaterial<IMaterialEvent, Physi | |||
| /** | |||
| * Deserializes the material from JSON. | |||
| * Textures should be loaded and in meta.textures before calling this method. | |||
| * todo - needs to be tested | |||
| * Note: some properties that are not serialized in Material.toJSON when they are default values (like side, alphaTest, blending, maps), they wont be reverted back if not present in JSON | |||
| * If _internal = true, Textures should be loaded and in meta.textures before calling this method. | |||
| * @param data | |||
| * @param meta | |||
| * @param _internal | |||
| @@ -199,7 +204,7 @@ export class PhysicalMaterial extends MeshPhysicalMaterial<IMaterialEvent, Physi | |||
| ThreeSerialization.Deserialize(data, this, meta, true) | |||
| return this.setValues(data) | |||
| } | |||
| ThreeSerialization.Deserialize(data, this, meta, false) | |||
| this.dispatchEvent({type: 'beforeDeserialize', data, meta, bubbleToObject: true, bubbleToParent: true}) | |||
| return this | |||
| } | |||
| @@ -45,6 +45,7 @@ export class UnlitMaterial extends MeshBasicMaterial<IMaterialEvent, UnlitMateri | |||
| readonly appliedMeshes: Set<IObject3D> = new Set() | |||
| readonly setDirty = iMaterialCommons.setDirty | |||
| clone(): this {return iMaterialCommons.clone(super.clone).call(this)} | |||
| dispatchEvent(event: IMaterialEvent): void {iMaterialCommons.dispatchEvent(super.dispatchEvent).call(this, event)} | |||
| generator?: IMaterialGenerator | |||
| @@ -159,7 +160,7 @@ export class UnlitMaterial extends MeshBasicMaterial<IMaterialEvent, UnlitMateri | |||
| ThreeSerialization.Deserialize(data, this, meta, true) | |||
| return this.setValues(data) | |||
| } | |||
| ThreeSerialization.Deserialize(data, this, meta, false) | |||
| this.dispatchEvent({type: 'beforeDeserialize', data, meta, bubbleToObject: true, bubbleToParent: true}) | |||
| return this | |||
| } | |||
| @@ -18,7 +18,7 @@ import {copyProps} from 'ts-browser-helpers' | |||
| import {copyMaterialUserData} from '../../utils/serialization' | |||
| import {MaterialExtender, MaterialExtension} from '../../materials' | |||
| import {IScene} from '../IScene' | |||
| import {IMaterial, IMaterialSetDirtyOptions} from '../IMaterial' | |||
| import {IMaterial, IMaterialEvent, IMaterialSetDirtyOptions} from '../IMaterial' | |||
| /** | |||
| * Map of all material properties and their default values in three.js - Material.js | |||
| @@ -75,7 +75,7 @@ export const iMaterialCommons = { | |||
| threeMaterialPropList, | |||
| setDirty: function(this: IMaterial, options?: IMaterialSetDirtyOptions): void { | |||
| this.needsUpdate = true | |||
| this.dispatchEvent({bubbleToObject: true, ...options, type: 'materialUpdate', material: this}) // this sets sceneUpdate in root scene | |||
| this.dispatchEvent({bubbleToObject: true, bubbleToParent: true, ...options, type: 'materialUpdate'}) // this sets sceneUpdate in root scene | |||
| this.uiConfig?.uiRefresh?.(true, 'postFrame', 1) | |||
| }, | |||
| setValues: (superSetValues: Material['setValues']): IMaterial['setValues'] => | |||
| @@ -123,6 +123,16 @@ export const iMaterialCommons = { | |||
| return material | |||
| }, | |||
| dispatchEvent: (superDispatchEvent: Material['dispatchEvent']): IMaterial['dispatchEvent'] => | |||
| function(this: IMaterial, event: IMaterialEvent): void { | |||
| superDispatchEvent.call(this, event) | |||
| const type = event.type | |||
| if (event.bubbleToObject && ( | |||
| type === 'beforeDeserialize' || type === 'materialUpdate' // todo - add more events | |||
| )) { | |||
| this.appliedMeshes.forEach(m => m.dispatchEvent({...event, material: this, type})) | |||
| } | |||
| }, | |||
| registerMaterialExtensions: function(this: IMaterial, customMaterialExtensions: MaterialExtension[]): void { | |||
| MaterialExtender.RegisterExtensions(this, customMaterialExtensions) | |||
| @@ -193,6 +203,7 @@ export function upgradeMaterial(this: IMaterial): IMaterial { | |||
| this.assetType = 'material' | |||
| this.setValues = iMaterialCommons.setValues(this.setValues) | |||
| this.clone = iMaterialCommons.clone(this.clone) | |||
| this.dispatchEvent = iMaterialCommons.dispatchEvent(this.dispatchEvent) | |||
| // todo: add uiconfig, serialization, other stuff from UnlitMaterial? | |||
| // dispose uiconfig etc. on dispose | |||
| @@ -160,7 +160,7 @@ export class RootScene extends Scene<ISceneEvent, ISceneEventTypes> implements I | |||
| } | |||
| /** | |||
| * Load model root scene exported to GLTF format. Used internally by {@link ThreeViewer.addSceneObject}. | |||
| Load model root scene exported to GLTF format. Used internally by {@link ThreeViewer.addSceneObject}. | |||
| * @param obj | |||
| * @param options | |||
| */ | |||
| @@ -512,10 +512,10 @@ export class RootScene extends Scene<ISceneEvent, ISceneEventTypes> implements I | |||
| traverse: (callback: (object: IObject3D) => void) => void | |||
| traverseVisible: (callback: (object: IObject3D) => void) => void | |||
| traverseAncestors: (callback: (object: IObject3D) => void) => void | |||
| getObjectById: (id: number) => IObject3D | undefined | |||
| getObjectByName: (name: string) => IObject3D | undefined | |||
| getObjectByProperty: (name: string, value: string) => IObject3D | undefined | |||
| copy: (source: IObject3D, recursive?: boolean) => this | |||
| getObjectById: <T extends IObject3D = IObject3D>(id: number) => T | undefined | |||
| getObjectByName: <T extends IObject3D = IObject3D>(name: string) => T | undefined | |||
| getObjectByProperty: <T extends IObject3D = IObject3D>(name: string, value: string) => T | undefined | |||
| copy: (source: this, recursive?: boolean, ...args: any[]) => this | |||
| clone: (recursive?: boolean) => this | |||
| remove: (...object: IObject3D[]) => this | |||
| dispatchEvent: (event: ISceneEvent) => void | |||
| @@ -1,5 +1,5 @@ | |||
| import {Event, Mesh, Vector3} from 'three' | |||
| import {IMaterial, IMaterialEvent} from '../IMaterial' | |||
| import {IMaterial} from '../IMaterial' | |||
| import {objectHasOwn} from 'ts-browser-helpers' | |||
| import {IObject3D, IObject3DEvent, IObjectProcessor, IObjectSetDirtyOptions} from '../IObject' | |||
| import {copyObject3DUserData} from '../../utils/serialization' | |||
| @@ -95,10 +95,6 @@ export const iObjectCommons = { | |||
| }) | |||
| } | |||
| }, | |||
| onMaterialUpdate: function(this: IObject3D, e: IMaterialEvent<'materialUpdate'>): void { | |||
| if (!e.bubbleToObject) return | |||
| this.dispatchEvent({bubbleToParent: true, ...e, object: this, material: e.target}) | |||
| }, | |||
| onGeometryUpdate: function(this: IObject3D, e: IGeometryEvent<'geometryUpdate'>): void { | |||
| if (!e.bubbleToObject) return | |||
| this.dispatchEvent({bubbleToParent: true, ...e, object: this, geometry: e.geometry}) | |||
| @@ -160,7 +156,6 @@ export const iObjectCommons = { | |||
| const mats = Array.isArray(this.material) ? [...(this.material as IMaterial[])] : [this.material!] | |||
| for (const mat of mats) { | |||
| if (!mat) continue | |||
| this._onMaterialUpdate && mat.removeEventListener('materialUpdate', this._onMaterialUpdate) | |||
| if (mat.appliedMeshes) { | |||
| mat.appliedMeshes.delete(this) | |||
| if (mat.userData && mat.appliedMeshes?.size === 0 && mat.userData.disposeOnIdle !== false) | |||
| @@ -178,7 +173,6 @@ export const iObjectCommons = { | |||
| } | |||
| materials.push(mat) | |||
| if (mat) { | |||
| this._onMaterialUpdate && mat.addEventListener('materialUpdate', this._onMaterialUpdate) | |||
| mat.appliedMeshes.add(this) | |||
| } | |||
| } | |||
| @@ -385,7 +379,6 @@ function upgradeObject3D(this: IObject3D, parent?: IObject3D|undefined, objectPr | |||
| if ((this.isMesh || this.isLine) && !this.userData.__meshSetup) { | |||
| this.userData.__meshSetup = true | |||
| this._onMaterialUpdate = (e: IMaterialEvent) => iObjectCommons.eventCallbacks.onMaterialUpdate.call(this, e) | |||
| this._onGeometryUpdate = (e: IGeometryEvent) => iObjectCommons.eventCallbacks.onGeometryUpdate.call(this, e) | |||
| // Material, Geometry prop init | |||
| @@ -415,7 +408,6 @@ function upgradeObject3D(this: IObject3D, parent?: IObject3D|undefined, objectPr | |||
| // if (oldGeom && oldGeom.userData && oldGeom.appliedMeshes?.size === 0 && oldGeom.userData.disposeOnIdle !== false) oldGeom.dispose() | |||
| } | |||
| delete this._onMaterialUpdate | |||
| delete this._onGeometryUpdate | |||
| }) | |||
| @@ -232,8 +232,8 @@ export class ThreeSerialization { | |||
| // data has deserialized textures and userData, assuming the rest can be deserialized by material.fromJSON | |||
| if (!obj || !obj.isMaterial || obj.type !== type) { | |||
| if (obj && Object.keys(obj).length) console.warn('Material type mismatch during deserialize, creating a new material', obj, data) | |||
| if (!obj || !obj.isMaterial || obj.type !== type && obj.constructor?.TYPE !== type) { | |||
| if (obj && Object.keys(obj).length) console.warn('Material type mismatch during deserialize, creating a new material', obj, data, type, obj.constructor?.type) | |||
| obj = null | |||
| } | |||
| // if obj is not null | |||