threepipe
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. import {
  2. Color,
  3. IUniform,
  4. Material,
  5. MeshBasicMaterial,
  6. MeshBasicMaterialParameters,
  7. MultiplyOperation,
  8. Shader,
  9. WebGLRenderer,
  10. } from 'three'
  11. import {UiObjectConfig} from 'uiconfig.js'
  12. import {
  13. IMaterial,
  14. IMaterialEvent,
  15. IMaterialEventTypes,
  16. IMaterialGenerator,
  17. IMaterialParameters,
  18. IMaterialTemplate,
  19. } from '../IMaterial'
  20. import {MaterialExtension} from '../../materials'
  21. import {shaderReplaceString} from '../../utils/shader-helpers'
  22. import {SerializationMetaType, ThreeSerialization} from '../../utils/serialization'
  23. import {ITexture} from '../ITexture'
  24. import {iMaterialCommons, threeMaterialPropList} from './iMaterialCommons'
  25. import {IObject3D} from '../IObject'
  26. import {iMaterialUI} from './IMaterialUi'
  27. export type UnlitMaterialEventTypes = IMaterialEventTypes | ''
  28. export class UnlitMaterial extends MeshBasicMaterial<IMaterialEvent, UnlitMaterialEventTypes> implements IMaterial<IMaterialEvent, UnlitMaterialEventTypes> {
  29. declare ['constructor']: typeof UnlitMaterial
  30. public static readonly TypeSlug = 'bmat'
  31. public static readonly TYPE = 'UnlitMaterial' // not using .type because it is used by three.js
  32. assetType = 'material' as const
  33. public readonly isUnlitMaterial = true
  34. readonly appliedMeshes: Set<IObject3D> = new Set()
  35. readonly setDirty = iMaterialCommons.setDirty
  36. dispose(): this {return iMaterialCommons.dispose(super.dispose).call(this)}
  37. clone(): this {return iMaterialCommons.clone(super.clone).call(this)}
  38. dispatchEvent(event: IMaterialEvent): void {iMaterialCommons.dispatchEvent(super.dispatchEvent).call(this, event)}
  39. generator?: IMaterialGenerator
  40. envMap: ITexture | null = null
  41. constructor({customMaterialExtensions, ...parameters}: MeshBasicMaterialParameters & IMaterialParameters = {}) {
  42. super(parameters)
  43. this.fog = false
  44. this.setDirty = this.setDirty.bind(this)
  45. if (customMaterialExtensions) this.registerMaterialExtensions(customMaterialExtensions)
  46. iMaterialCommons.upgradeMaterial.call(this)
  47. }
  48. // region Material Extension
  49. materialExtensions: MaterialExtension[] = []
  50. extraUniformsToUpload: Record<string, IUniform> = {}
  51. registerMaterialExtensions = iMaterialCommons.registerMaterialExtensions
  52. unregisterMaterialExtensions = iMaterialCommons.unregisterMaterialExtensions
  53. customProgramCacheKey(): string {
  54. return super.customProgramCacheKey() + iMaterialCommons.customProgramCacheKey.call(this)
  55. }
  56. onBeforeCompile(shader: Shader, renderer: WebGLRenderer): void { // shader is not Shader but WebglUniforms.getParameters return value type so includes defines
  57. const f = [
  58. ['vec3 outgoingLight = ', 'afterModulation'], // added markers before found substring
  59. ['#include <aomap_fragment>', 'beforeModulation'],
  60. ['ReflectedLight reflectedLight = ', 'beforeAccumulation'],
  61. ['#include <clipping_planes_fragment>', 'mainStart'],
  62. ]
  63. const v = [
  64. ['#include <uv_vertex>', 'mainStart'],
  65. ]
  66. for (const vElement of v) shader.vertexShader = shaderReplaceString(shader.vertexShader, vElement[0], '#glMarker ' + vElement[1] + '\n' + vElement[0])
  67. for (const vElement of f) shader.fragmentShader = shaderReplaceString(shader.fragmentShader, vElement[0], '#glMarker ' + vElement[1] + '\n' + vElement[0])
  68. iMaterialCommons.onBeforeCompile.call(this, shader, renderer)
  69. // ;(shader as any).defines.INVERSE_ALPHAMAP = this.userData.inverseAlphaMap ? 1 : 0 // todo
  70. super.onBeforeCompile(shader, renderer)
  71. }
  72. // onBeforeRender(...args: Parameters<IMaterial['onBeforeRender']>): void {
  73. // super.onBeforeRender(...args)
  74. // iMaterialCommons.onBeforeRender.call(this, ...args)
  75. //
  76. // // const t = this.userData.inverseAlphaMap ? 1 : 0 // todo
  77. // // if (t !== this.defines.INVERSE_ALPHAMAP) {
  78. // // this.defines.INVERSE_ALPHAMAP = t
  79. // // this.needsUpdate = true
  80. // // }
  81. // }
  82. onBeforeRender = iMaterialCommons.onBeforeRenderOverride(super.onBeforeRender)
  83. onAfterRender = iMaterialCommons.onAfterRenderOverride(super.onAfterRender)
  84. // endregion
  85. // region Serialization
  86. /**
  87. * Sets the values of this material based on the values of the passed material or an object with material properties
  88. * The input is expected to be a valid material or a deserialized material parameters object(including the deserialized userdata)
  89. * @param parameters - material or material parameters object
  90. * @param allowInvalidType - if true, the type of the oldMaterial is not checked. Objects without type are always allowed.
  91. * @param clearCurrentUserData - if undefined, then depends on material.isMaterial. if true, the current userdata is cleared before setting the new values, because it can have data which wont be overwritten if not present in the new material.
  92. */
  93. setValues(parameters: Material|(MeshBasicMaterialParameters&{type?:string}), allowInvalidType = true, clearCurrentUserData: boolean|undefined = undefined): this {
  94. if (!parameters) return this
  95. if (parameters.type && !allowInvalidType && !['MeshBasicMaterial', 'MeshBasicMaterial2', this.constructor.TYPE].includes(parameters.type)) {
  96. console.error('Material type is not supported:', parameters.type)
  97. return this
  98. }
  99. if (clearCurrentUserData === undefined) clearCurrentUserData = (<Material>parameters).isMaterial
  100. if (clearCurrentUserData) this.userData = {}
  101. iMaterialCommons.setValues(super.setValues).call(this, parameters)
  102. this.userData.uuid = this.uuid
  103. return this
  104. }
  105. copy(source: Material|any): this {
  106. return this.setValues(source, false)
  107. }
  108. /**
  109. * Serializes this material to JSON.
  110. * @param meta - metadata for serialization
  111. * @param _internal - Calls only super.toJSON, does internal three.js serialization and @serialize tags. Set it to true only if you know what you are doing. This is used in Serialization->serializer->material
  112. */
  113. toJSON(meta?: SerializationMetaType, _internal = false): any {
  114. if (_internal) return {
  115. ...super.toJSON(meta),
  116. ...ThreeSerialization.Serialize(this, meta, true), // this will serialize the properties of this class(like defined with @serialize and @serialize attribute)
  117. }
  118. return ThreeSerialization.Serialize(this, meta, false) // this will call toJSON again, but with baseOnly=true, that's why we set isThis to false.
  119. }
  120. /**
  121. * Deserializes the material from JSON.
  122. * Textures should be loaded and in meta.textures before calling this method.
  123. * todo - needs to be tested
  124. * @param data
  125. * @param meta
  126. * @param _internal
  127. */
  128. fromJSON(data: any, meta?: SerializationMetaType, _internal = false): this | null {
  129. if (_internal) {
  130. ThreeSerialization.Deserialize(data, this, meta, true)
  131. return this.setValues(data)
  132. }
  133. this.dispatchEvent({type: 'beforeDeserialize', data, meta, bubbleToObject: true, bubbleToParent: true})
  134. return this
  135. }
  136. // endregion
  137. // region UI Config
  138. // todo dispose ui config
  139. uiConfig: UiObjectConfig = {
  140. type: 'folder',
  141. label: 'Unlit Material',
  142. uuid: 'MBM2_' + this.uuid,
  143. expanded: true,
  144. children: [
  145. ...iMaterialUI.base(this),
  146. iMaterialUI.blending(this),
  147. iMaterialUI.polygonOffset(this),
  148. iMaterialUI.aoLightMap(this),
  149. ...iMaterialUI.misc(this),
  150. ],
  151. }
  152. // endregion UI Config
  153. // Class properties can also be listed with annotations like @serialize or @property
  154. static readonly MaterialProperties = {
  155. ...threeMaterialPropList,
  156. color: new Color(0xffffff),
  157. map: null,
  158. lightMap: null,
  159. lightMapIntensity: 1,
  160. aoMap: null,
  161. aoMapIntensity: 1,
  162. specularMap: null,
  163. alphaMap: null,
  164. envMap: null,
  165. combine: MultiplyOperation,
  166. envMapIntensity: 1,
  167. reflectivity: 1,
  168. refractionRatio: 0.98,
  169. wireframe: false,
  170. wireframeLinewidth: 1,
  171. wireframeLinecap: 'round',
  172. wireframeLinejoin: 'round',
  173. skinning: false,
  174. fog: true,
  175. }
  176. static MaterialTemplate: IMaterialTemplate<UnlitMaterial, Partial<typeof UnlitMaterial.MaterialProperties>> = {
  177. materialType: UnlitMaterial.TYPE,
  178. name: 'unlit',
  179. typeSlug: UnlitMaterial.TypeSlug,
  180. alias: ['basic', 'unlit', UnlitMaterial.TYPE, UnlitMaterial.TypeSlug, 'MeshBasicMaterial', 'MeshBasicMaterial2'],
  181. params: {
  182. color: new Color(1, 1, 1),
  183. },
  184. generator: (params) => {
  185. return new UnlitMaterial(params)
  186. },
  187. }
  188. }
  189. export class MeshBasicMaterial2 extends UnlitMaterial {
  190. constructor(parameters?: MeshBasicMaterialParameters) {
  191. super(parameters)
  192. console.error('MeshBasicMaterial2 is deprecated, use UnlitMaterial instead')
  193. }
  194. }