Improve warning in AssetManager, Create MaterialManager.copyMaterialProps, fix camera aspect when canvas has height 0, add undo for some buttons, changes/fixes for ui, handle InteractionPromptPlugin in CameraViewPlugin, support async onStop and onComplete in PopmotionPlugin, allow resetting geometry in BaseGroundPlugin, add pluginListeners, forPlugin in ThreeViewer, add SwitchNodeBasePlugin.snapIcons, fixes in InteractionPromptPlugin, add isEditor, LS_DEFAULT_LOGO in LoadingScreenPlugin, add isEditor in FrameFadePlugin.
1 year ago |
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 |
- import {
- AddEquation,
- AlwaysStencilFunc,
- ColorManagement,
- FrontSide,
- KeepStencilOp,
- LessEqualDepth,
- Material,
- MaterialParameters,
- NormalBlending,
- OneMinusSrcAlphaFactor,
- Scene,
- Shader,
- SrcAlphaFactor,
- WebGLRenderer,
- } from 'three'
- import {copyProps} from 'ts-browser-helpers'
- import {copyMaterialUserData} from '../../utils/serialization'
- import {MaterialExtender, MaterialExtension} from '../../materials'
- import {IScene} from '../IScene'
- import {IMaterial, IMaterialEventMap, IMaterialSetDirtyOptions} from '../IMaterial'
- import {isInScene} from '../../three/utils'
-
- /**
- * Map of all material properties and their default values in three.js - Material.js
- * This is used to copy properties and serialize/deserialize them.
- * @note: Upgrade note: keep updated from three.js/src/Material.js:22
- */
- export const threeMaterialPropList = {
- // uuid: '', // DONT COPY, should remain commented
- name: '',
- blending: NormalBlending,
- side: FrontSide,
- vertexColors: false,
- opacity: 1,
- transparent: false,
- blendSrc: SrcAlphaFactor,
- blendDst: OneMinusSrcAlphaFactor,
- blendEquation: AddEquation,
- blendSrcAlpha: null,
- blendDstAlpha: null,
- blendEquationAlpha: null,
- blendColor: '#000000',
- blendAlpha: 0,
- depthFunc: LessEqualDepth,
- depthTest: true,
- depthWrite: true,
- stencilWriteMask: 0xff,
- stencilFunc: AlwaysStencilFunc,
- stencilRef: 0,
- stencilFuncMask: 0xff,
- stencilFail: KeepStencilOp,
- stencilZFail: KeepStencilOp,
- stencilZPass: KeepStencilOp,
- stencilWrite: false,
- clippingPlanes: null,
- clipIntersection: false,
- clipShadows: false,
- shadowSide: null,
- colorWrite: true,
- precision: null,
- polygonOffset: false,
- polygonOffsetFactor: 0,
- polygonOffsetUnits: 0,
- dithering: false,
- alphaToCoverage: false,
- premultipliedAlpha: false,
- forceSinglePass: false,
- visible: true,
- toneMapped: true,
- userData: {},
- // wireframeLinecap: 'round',
- // wireframeLinejoin: 'round',
- alphaTest: 0,
- alphaHash: false,
- // fog: true,
- }
- export const iMaterialCommons = {
- threeMaterialPropList,
- setDirty: function(this: IMaterial, options?: IMaterialSetDirtyOptions): void {
- if (options?.needsUpdate !== false) this.needsUpdate = true
- this.dispatchEvent({bubbleToObject: true, bubbleToParent: true, ...options, type: 'materialUpdate'}) // this sets sceneUpdate in root scene
- if (options?.last !== false) this.uiConfig?.uiRefresh?.(true, 'postFrame', 1)
- },
- setValues: (superSetValues: Material['setValues']): IMaterial['setValues'] =>
- function(this: IMaterial, parameters: Material | (MaterialParameters & {type?: string})): IMaterial {
-
- // legacy check for old color management(non-sRGB) in material.setValues todo: move this to Material.fromJSON
- const legacyColors = (parameters as any)?.metadata && (parameters as any)?.metadata.version <= 4.5
- const lastColorManagementEnabled = ColorManagement.enabled
- if (legacyColors) ColorManagement.enabled = false
-
- const propList = this.constructor.MaterialProperties
- const params: any = !propList ? {...parameters} : copyProps(parameters, {} as any, Array.from(Object.keys(propList)))
-
- // remove undefined values
- for (const key of Object.keys(params)) if (params[key] === undefined) delete params[key]
-
- const userData = params.userData
- delete params.userData
-
- // todo: can migrate to @serialize for properties which have UI etc and use super.setValues for the rest like threeMaterialPropList
- superSetValues.call(this, params)
-
- if (userData) copyMaterialUserData(this.userData, userData)
-
- if (legacyColors) ColorManagement.enabled = lastColorManagementEnabled
-
- this.setDirty?.()
- return this
- },
- dispose: (superDispose: Material['dispose']): IMaterial['dispose'] =>
- function(this: IMaterial, force = true): void {
- if (!force && (this.userData.disposeOnIdle === false || isInScene(this))) return
- superDispose.call(this)
- },
- clone: (superClone: Material['clone']): IMaterial['clone'] =>
- function(this: IMaterial, track = false): IMaterial {
- if (track) {
- if (!this.userData.cloneId) {
- this.userData.cloneId = '0'
- }
- if (!this.userData.cloneCount) {
- this.userData.cloneCount = 0
- }
- this.userData.cloneCount += 1
- }
-
- const material: IMaterial = this.generator?.({})?.setValues(this, false) ?? superClone.call(this)
-
- if (track) {
-
- material.userData.cloneId = material.userData.cloneId + '_' + this.userData.cloneCount
- material.userData.cloneCount = 0
- material.name = (material.name || 'mat') + '_' + material.userData.cloneId
- }
-
- return material
- },
- dispatchEvent: (superDispatchEvent: Material['dispatchEvent']): IMaterial['dispatchEvent'] =>
- function(this: IMaterial, event): void {
- superDispatchEvent.call(this, event)
- const type = event.type
- if ((event as IMaterialEventMap['materialUpdate']).bubbleToObject && (
- type === 'beforeDeserialize' || type === 'materialUpdate' || type === 'textureUpdate' // todo - add more events
- )) {
- this.appliedMeshes.forEach(m => m.dispatchEvent({...event, material: this, type}))
- }
- },
-
- customProgramCacheKey: function(this: IMaterial): string {
- return MaterialExtender.CacheKeyForExtensions(this, this.materialExtensions) + this.userData.inverseAlphaMap
- },
- registerMaterialExtensions: function(this: IMaterial, customMaterialExtensions: MaterialExtension[]): void {
- MaterialExtender.RegisterExtensions(this, customMaterialExtensions)
- },
- unregisterMaterialExtensions: function(this: IMaterial, customMaterialExtensions: MaterialExtension[]): void {
- MaterialExtender.UnregisterExtensions(this, customMaterialExtensions)
- },
-
- // shader is not Shader but WebglUniforms.getParameters return value type so includes defines
- onBeforeCompile: function(this: IMaterial, shader: Shader, renderer: WebGLRenderer): void {
- if (this.materialExtensions) MaterialExtender.ApplyMaterialExtensions(this, shader, this.materialExtensions, renderer)
-
- this.dispatchEvent({type: 'beforeCompile', shader, renderer})
-
- shader.fragmentShader = shader.fragmentShader.replaceAll('#glMarker', '// ')
- shader.vertexShader = shader.vertexShader.replaceAll('#glMarker', '// ')
- },
- onBeforeRender: function(this: IMaterial, renderer, scene: Scene & Partial<IScene>, camera, geometry, object) {
- if (this.envMapIntensity !== undefined && !this.userData.separateEnvMapIntensity && scene.envMapIntensity !== undefined) {
- this.userData.__envIntensity = this.envMapIntensity
- this.envMapIntensity = scene.envMapIntensity
- }
- if (this.defines && this.envMap !== undefined && scene.fixedEnvMapDirection !== undefined) {
- if (scene.fixedEnvMapDirection) {
- if (!this.defines.FIX_ENV_DIRECTION) {
- this.defines.FIX_ENV_DIRECTION = '1'
- this.needsUpdate = true
- }
- } else if (this.defines.FIX_ENV_DIRECTION !== undefined) {
- delete this.defines.FIX_ENV_DIRECTION
- this.needsUpdate = true
- }
- }
- this.dispatchEvent({type: 'beforeRender', renderer, scene, camera, geometry, object})
- } as IMaterial['onBeforeRender'],
- onAfterRender: function(this: IMaterial, renderer, scene: Scene & Partial<IScene>, camera, geometry, object) {
- if (this.userData.__envIntensity !== undefined) {
- this.envMapIntensity = this.userData.__envIntensity
- delete this.userData.__envIntensity
- }
- this.dispatchEvent({type: 'afterRender', renderer, scene, camera, geometry, object})
- } as IMaterial['onAfterRender'],
-
- onBeforeCompileOverride: (superOnBeforeCompile: Material['onBeforeCompile']): IMaterial['onBeforeCompile'] =>
- function(this: IMaterial, shader: Shader, renderer: WebGLRenderer): void {
- iMaterialCommons.onBeforeCompile.call(this, shader, renderer)
- superOnBeforeCompile.call(this, shader, renderer)
- },
- onBeforeRenderOverride: (superOnBeforeRender: Material['onBeforeRender']): IMaterial['onBeforeRender'] =>
- function(this: IMaterial, ...args: Parameters<Material['onBeforeRender']>): void {
- superOnBeforeRender.call(this, ...args)
- iMaterialCommons.onBeforeRender.call(this, ...args)
- },
- onAfterRenderOverride: (superOnAfterRender: Material['onAfterRender']): IMaterial['onAfterRender'] =>
- function(this: IMaterial, ...args: Parameters<Material['onAfterRender']>): void {
- superOnAfterRender.call(this, ...args)
- iMaterialCommons.onAfterRender.call(this, ...args)
- },
- customProgramCacheKeyOverride: (superCustomPropertyCacheKey: Material['customProgramCacheKey']): IMaterial['customProgramCacheKey'] =>
- function(this: IMaterial): string {
- return superCustomPropertyCacheKey.call(this) + iMaterialCommons.customProgramCacheKey.call(this)
- },
-
- upgradeMaterial: upgradeMaterial,
- // todo;
- } as const
-
- /**
- * Convert a standard three.js {@link Material} to {@link IMaterial}
- */
- export function upgradeMaterial(this: IMaterial): IMaterial {
- if (!this.isMaterial) {
- console.error('Material is not a material', this)
- return this
- }
- if (!this.setDirty) this.setDirty = iMaterialCommons.setDirty
- if (!this.appliedMeshes) this.appliedMeshes = new Set()
- if (!this.userData) this.userData = {}
- this.userData.uuid = this.uuid // for serialization
-
- // legacy
- if (!this.userData.setDirty) this.userData.setDirty = (e: any) => {
- console.warn('userData.setDirty is deprecated. Use setDirty instead.')
- this.setDirty(e)
- }
-
- if (this.assetType === 'material') return this // already upgraded
- this.assetType = 'material'
- this.setValues = iMaterialCommons.setValues(this.setValues)
- this.dispose = iMaterialCommons.dispose(this.dispose)
- this.clone = iMaterialCommons.clone(this.clone)
- this.dispatchEvent = iMaterialCommons.dispatchEvent(this.dispatchEvent)
-
- // material extensions
- if (!this.extraUniformsToUpload) this.extraUniformsToUpload = {}
- if (!this.materialExtensions) this.materialExtensions = []
- if (!this.registerMaterialExtensions) this.registerMaterialExtensions = iMaterialCommons.registerMaterialExtensions
- if (!this.unregisterMaterialExtensions) this.unregisterMaterialExtensions = iMaterialCommons.unregisterMaterialExtensions
- this.onBeforeCompile = iMaterialCommons.onBeforeCompileOverride(this.onBeforeCompile)
- this.onBeforeRender = iMaterialCommons.onBeforeRenderOverride(this.onBeforeRender)
- this.onAfterRender = iMaterialCommons.onAfterRenderOverride(this.onAfterRender)
- this.customProgramCacheKey = iMaterialCommons.customProgramCacheKeyOverride(this.customProgramCacheKey)
-
- // todo: add uiconfig, serialization, other stuff from UnlitMaterial?
- // dispose uiconfig etc. on dispose
-
- return this
- }
|