threepipe
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

iMaterialCommons.ts 7.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. import {
  2. AddEquation,
  3. AlwaysStencilFunc,
  4. ColorManagement,
  5. FrontSide,
  6. KeepStencilOp,
  7. LessEqualDepth,
  8. Material,
  9. MaterialParameters,
  10. NormalBlending,
  11. OneMinusSrcAlphaFactor,
  12. Scene,
  13. Shader,
  14. SrcAlphaFactor,
  15. WebGLRenderer,
  16. } from 'three'
  17. import {copyProps} from 'ts-browser-helpers'
  18. import {copyMaterialUserData} from '../../utils/serialization'
  19. import {MaterialExtender, MaterialExtension} from '../../materials'
  20. import {IScene} from '../IScene'
  21. import {IMaterial, IMaterialSetDirtyOptions} from '../IMaterial'
  22. /**
  23. * Map of all material properties and their default values in three.js - Material.js
  24. * This is used to copy properties and serialize/deserialize them.
  25. * @note: Upgrade note: keep updated from three.js/src/Material.js:22
  26. */
  27. export const threeMaterialPropList = {
  28. // uuid: '', // DONT COPY, should remain commented
  29. name: '',
  30. blending: NormalBlending,
  31. side: FrontSide,
  32. vertexColors: false,
  33. opacity: 1,
  34. transparent: false,
  35. blendSrc: SrcAlphaFactor,
  36. blendDst: OneMinusSrcAlphaFactor,
  37. blendEquation: AddEquation,
  38. blendSrcAlpha: null,
  39. blendDstAlpha: null,
  40. blendEquationAlpha: null,
  41. depthFunc: LessEqualDepth,
  42. depthTest: true,
  43. depthWrite: true,
  44. stencilWriteMask: 0xff,
  45. stencilFunc: AlwaysStencilFunc,
  46. stencilRef: 0,
  47. stencilFuncMask: 0xff,
  48. stencilFail: KeepStencilOp,
  49. stencilZFail: KeepStencilOp,
  50. stencilZPass: KeepStencilOp,
  51. stencilWrite: false,
  52. clippingPlanes: null,
  53. clipIntersection: false,
  54. clipShadows: false,
  55. shadowSide: null,
  56. colorWrite: true,
  57. precision: null,
  58. polygonOffset: false,
  59. polygonOffsetFactor: 0,
  60. polygonOffsetUnits: 0,
  61. dithering: false,
  62. alphaToCoverage: false,
  63. premultipliedAlpha: false,
  64. forceSinglePass: false,
  65. visible: true,
  66. toneMapped: true,
  67. userData: {},
  68. // wireframeLinecap: 'round',
  69. // wireframeLinejoin: 'round',
  70. alphaTest: 0,
  71. // fog: true,
  72. }
  73. export const iMaterialCommons = {
  74. threeMaterialPropList,
  75. setDirty: function(this: IMaterial, options?: IMaterialSetDirtyOptions): void {
  76. this.needsUpdate = true
  77. this.dispatchEvent({bubbleToObject: true, ...options, type: 'materialUpdate', material: this}) // this sets sceneUpdate in root scene
  78. this.uiConfig?.uiRefresh?.(true, 'postFrame', 1)
  79. },
  80. setValues: (superSetValues: Material['setValues']): IMaterial['setValues'] =>
  81. function(this: IMaterial, parameters: Material | (MaterialParameters & {type?: string})): IMaterial {
  82. // legacy check for old color management(non-sRGB) in material.setValues todo: move this to Material.fromJSON
  83. const legacyColors = (parameters as any)?.metadata && (parameters as any)?.metadata.version <= 4.5
  84. const lastColorManagementEnabled = ColorManagement.enabled
  85. if (legacyColors) ColorManagement.enabled = false
  86. const propList = this.constructor.MaterialProperties
  87. const params: any = !propList ? {...parameters} : copyProps(parameters, {} as any, Array.from(Object.keys(propList)))
  88. // remove undefined values
  89. for (const key of Object.keys(params)) if (params[key] === undefined) delete params[key]
  90. const userData = params.userData
  91. delete params.userData
  92. // todo: can migrate to @serialize for properties which have UI etc and use super.setValues for the rest like threeMaterialPropList
  93. superSetValues.call(this, params)
  94. if (userData) copyMaterialUserData(this.userData, userData)
  95. if (legacyColors) ColorManagement.enabled = lastColorManagementEnabled
  96. this.setDirty?.()
  97. return this
  98. },
  99. clone: (superClone: Material<any, any>['clone']): IMaterial['clone'] =>
  100. function(this: IMaterial): IMaterial {
  101. if (!this.userData.cloneId) {
  102. this.userData.cloneId = '0'
  103. }
  104. if (!this.userData.cloneCount) {
  105. this.userData.cloneCount = 0
  106. }
  107. this.userData.cloneCount += 1
  108. const material: IMaterial = this.generator?.({})?.setValues(this, false) ?? superClone.call(this)
  109. material.userData.cloneId = material.userData.cloneId + '_' + this.userData.cloneCount
  110. material.userData.cloneCount = 0
  111. material.name = material.name + '_' + material.userData.cloneId
  112. return material
  113. },
  114. registerMaterialExtensions: function(this: IMaterial, customMaterialExtensions: MaterialExtension[]): void {
  115. MaterialExtender.RegisterExtensions(this, customMaterialExtensions)
  116. },
  117. unregisterMaterialExtensions: function(this: IMaterial, customMaterialExtensions: MaterialExtension[]): void {
  118. MaterialExtender.UnregisterExtensions(this, customMaterialExtensions)
  119. },
  120. onBeforeCompile: function(this: IMaterial, shader: Shader, renderer: WebGLRenderer): void {
  121. if (this.materialExtensions) MaterialExtender.ApplyMaterialExtensions(this, shader, this.materialExtensions, renderer)
  122. this.dispatchEvent({type: 'beforeCompile', shader, renderer})
  123. shader.fragmentShader = shader.fragmentShader.replaceAll('#glMarker', '// ')
  124. shader.vertexShader = shader.vertexShader.replaceAll('#glMarker', '// ')
  125. },
  126. onBeforeRender: function(this: IMaterial, renderer, scene: Scene & Partial<IScene>, camera, geometry, object) {
  127. if (this.envMapIntensity !== undefined && !this.userData.separateEnvMapIntensity && scene.envMapIntensity !== undefined) {
  128. this.userData.__envIntensity = this.envMapIntensity
  129. this.envMapIntensity = scene.envMapIntensity
  130. }
  131. if (this.defines && this.envMap !== undefined && scene.fixedEnvMapDirection !== undefined) {
  132. if (scene.fixedEnvMapDirection) {
  133. if (!this.defines.FIX_ENV_DIRECTION) {
  134. this.defines.FIX_ENV_DIRECTION = '1'
  135. this.needsUpdate = true
  136. }
  137. } else if (this.defines.FIX_ENV_DIRECTION !== undefined) {
  138. delete this.defines.FIX_ENV_DIRECTION
  139. this.needsUpdate = true
  140. }
  141. }
  142. this.dispatchEvent({type: 'beforeRender', renderer, scene, camera, geometry, object})
  143. } as IMaterial['onBeforeRender'],
  144. onAfterRender: function(this: IMaterial, renderer, scene: Scene & Partial<IScene>, camera, geometry, object) {
  145. if (this.userData.__envIntensity !== undefined) {
  146. this.envMapIntensity = this.userData.__envIntensity
  147. delete this.userData.__envIntensity
  148. }
  149. this.dispatchEvent({type: 'afterRender', renderer, scene, camera, geometry, object})
  150. } as IMaterial['onAfterRender'],
  151. upgradeMaterial: upgradeMaterial,
  152. // todo;
  153. } as const
  154. /**
  155. * Convert a standard three.js {@link Material} to {@link IMaterial}
  156. */
  157. export function upgradeMaterial(this: IMaterial): IMaterial {
  158. if (!this.isMaterial) {
  159. console.error('Material is not a material', this)
  160. return this
  161. }
  162. if (!this.setDirty) this.setDirty = iMaterialCommons.setDirty
  163. if (!this.appliedMeshes) this.appliedMeshes = new Set()
  164. if (!this.userData) this.userData = {}
  165. this.userData.uuid = this.uuid
  166. // legacy
  167. if (!this.userData.setDirty) this.userData.setDirty = (e: any) => {
  168. console.warn('userData.setDirty is deprecated. Use setDirty instead.')
  169. this.setDirty(e)
  170. }
  171. if (this.assetType === 'material') return this // already upgraded
  172. this.assetType = 'material'
  173. this.setValues = iMaterialCommons.setValues(this.setValues)
  174. this.clone = iMaterialCommons.clone(this.clone)
  175. // todo: add uiconfig, serialization, other stuff from UnlitMaterial?
  176. // dispose uiconfig etc. on dispose
  177. return this
  178. }