material.js 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554
  1. import { __decorate } from "../tslib.es6.js";
  2. import { serialize } from "../Misc/decorators.js";
  3. import { Tools } from "../Misc/tools.js";
  4. import { Observable } from "../Misc/observable.js";
  5. import { EngineStore } from "../Engines/engineStore.js";
  6. import { SubMesh } from "../Meshes/subMesh.js";
  7. import { UniformBuffer } from "./uniformBuffer.js";
  8. import { Logger } from "../Misc/logger.js";
  9. import { Plane } from "../Maths/math.plane.js";
  10. import { DrawWrapper } from "./drawWrapper.js";
  11. import { MaterialStencilState } from "./materialStencilState.js";
  12. import { ScenePerformancePriority } from "../scene.js";
  13. import { MaterialPluginEvent } from "./materialPluginEvent.js";
  14. import { BindSceneUniformBuffer } from "./materialHelper.functions.js";
  15. import { SerializationHelper } from "../Misc/decorators.serialization.js";
  16. /**
  17. * Base class for the main features of a material in Babylon.js
  18. */
  19. export class Material {
  20. /**
  21. * If the material can be rendered to several textures with MRT extension
  22. */
  23. get canRenderToMRT() {
  24. // By default, shaders are not compatible with MRTs
  25. // Base classes should override that if their shader supports MRT
  26. return false;
  27. }
  28. /**
  29. * Sets the alpha value of the material
  30. */
  31. set alpha(value) {
  32. if (this._alpha === value) {
  33. return;
  34. }
  35. const oldValue = this._alpha;
  36. this._alpha = value;
  37. // Only call dirty when there is a state change (no alpha / alpha)
  38. if (oldValue === 1 || value === 1) {
  39. this.markAsDirty(Material.MiscDirtyFlag + Material.PrePassDirtyFlag);
  40. }
  41. }
  42. /**
  43. * Gets the alpha value of the material
  44. */
  45. get alpha() {
  46. return this._alpha;
  47. }
  48. /**
  49. * Sets the culling state (true to enable culling, false to disable)
  50. */
  51. set backFaceCulling(value) {
  52. if (this._backFaceCulling === value) {
  53. return;
  54. }
  55. this._backFaceCulling = value;
  56. this.markAsDirty(Material.TextureDirtyFlag);
  57. }
  58. /**
  59. * Gets the culling state
  60. */
  61. get backFaceCulling() {
  62. return this._backFaceCulling;
  63. }
  64. /**
  65. * Sets the type of faces that should be culled (true for back faces, false for front faces)
  66. */
  67. set cullBackFaces(value) {
  68. if (this._cullBackFaces === value) {
  69. return;
  70. }
  71. this._cullBackFaces = value;
  72. this.markAsDirty(Material.TextureDirtyFlag);
  73. }
  74. /**
  75. * Gets the type of faces that should be culled
  76. */
  77. get cullBackFaces() {
  78. return this._cullBackFaces;
  79. }
  80. /**
  81. * Block the dirty-mechanism for this specific material
  82. * When set to false after being true the material will be marked as dirty.
  83. */
  84. get blockDirtyMechanism() {
  85. return this._blockDirtyMechanism;
  86. }
  87. set blockDirtyMechanism(value) {
  88. if (this._blockDirtyMechanism === value) {
  89. return;
  90. }
  91. this._blockDirtyMechanism = value;
  92. if (!value) {
  93. this.markDirty();
  94. }
  95. }
  96. /**
  97. * This allows you to modify the material without marking it as dirty after every change.
  98. * This function should be used if you need to make more than one dirty-enabling change to the material - adding a texture, setting a new fill mode and so on.
  99. * The callback will pass the material as an argument, so you can make your changes to it.
  100. * @param callback the callback to be executed that will update the material
  101. */
  102. atomicMaterialsUpdate(callback) {
  103. this.blockDirtyMechanism = true;
  104. try {
  105. callback(this);
  106. }
  107. finally {
  108. this.blockDirtyMechanism = false;
  109. }
  110. }
  111. /**
  112. * Gets a boolean indicating that current material needs to register RTT
  113. */
  114. get hasRenderTargetTextures() {
  115. this._eventInfo.hasRenderTargetTextures = false;
  116. this._callbackPluginEventHasRenderTargetTextures(this._eventInfo);
  117. return this._eventInfo.hasRenderTargetTextures;
  118. }
  119. /**
  120. * Called during a dispose event
  121. */
  122. set onDispose(callback) {
  123. if (this._onDisposeObserver) {
  124. this.onDisposeObservable.remove(this._onDisposeObserver);
  125. }
  126. this._onDisposeObserver = this.onDisposeObservable.add(callback);
  127. }
  128. /**
  129. * An event triggered when the material is bound
  130. */
  131. get onBindObservable() {
  132. if (!this._onBindObservable) {
  133. this._onBindObservable = new Observable();
  134. }
  135. return this._onBindObservable;
  136. }
  137. /**
  138. * Called during a bind event
  139. */
  140. set onBind(callback) {
  141. if (this._onBindObserver) {
  142. this.onBindObservable.remove(this._onBindObserver);
  143. }
  144. this._onBindObserver = this.onBindObservable.add(callback);
  145. }
  146. /**
  147. * An event triggered when the material is unbound
  148. */
  149. get onUnBindObservable() {
  150. if (!this._onUnBindObservable) {
  151. this._onUnBindObservable = new Observable();
  152. }
  153. return this._onUnBindObservable;
  154. }
  155. /**
  156. * An event triggered when the effect is (re)created
  157. */
  158. get onEffectCreatedObservable() {
  159. if (!this._onEffectCreatedObservable) {
  160. this._onEffectCreatedObservable = new Observable();
  161. }
  162. return this._onEffectCreatedObservable;
  163. }
  164. /**
  165. * Sets the value of the alpha mode.
  166. *
  167. * | Value | Type | Description |
  168. * | --- | --- | --- |
  169. * | 0 | ALPHA_DISABLE | |
  170. * | 1 | ALPHA_ADD | |
  171. * | 2 | ALPHA_COMBINE | |
  172. * | 3 | ALPHA_SUBTRACT | |
  173. * | 4 | ALPHA_MULTIPLY | |
  174. * | 5 | ALPHA_MAXIMIZED | |
  175. * | 6 | ALPHA_ONEONE | |
  176. * | 7 | ALPHA_PREMULTIPLIED | |
  177. * | 8 | ALPHA_PREMULTIPLIED_PORTERDUFF | |
  178. * | 9 | ALPHA_INTERPOLATE | |
  179. * | 10 | ALPHA_SCREENMODE | |
  180. *
  181. */
  182. set alphaMode(value) {
  183. if (this._alphaMode === value) {
  184. return;
  185. }
  186. this._alphaMode = value;
  187. this.markAsDirty(Material.TextureDirtyFlag);
  188. }
  189. /**
  190. * Gets the value of the alpha mode
  191. */
  192. get alphaMode() {
  193. return this._alphaMode;
  194. }
  195. /**
  196. * Sets the need depth pre-pass value
  197. */
  198. set needDepthPrePass(value) {
  199. if (this._needDepthPrePass === value) {
  200. return;
  201. }
  202. this._needDepthPrePass = value;
  203. if (this._needDepthPrePass) {
  204. this.checkReadyOnEveryCall = true;
  205. }
  206. }
  207. /**
  208. * Gets the depth pre-pass value
  209. */
  210. get needDepthPrePass() {
  211. return this._needDepthPrePass;
  212. }
  213. /**
  214. * Can this material render to prepass
  215. */
  216. get isPrePassCapable() {
  217. return false;
  218. }
  219. /**
  220. * Sets the state for enabling fog
  221. */
  222. set fogEnabled(value) {
  223. if (this._fogEnabled === value) {
  224. return;
  225. }
  226. this._fogEnabled = value;
  227. this.markAsDirty(Material.MiscDirtyFlag);
  228. }
  229. /**
  230. * Gets the value of the fog enabled state
  231. */
  232. get fogEnabled() {
  233. return this._fogEnabled;
  234. }
  235. get wireframe() {
  236. switch (this._fillMode) {
  237. case Material.WireFrameFillMode:
  238. case Material.LineListDrawMode:
  239. case Material.LineLoopDrawMode:
  240. case Material.LineStripDrawMode:
  241. return true;
  242. }
  243. return this._scene.forceWireframe;
  244. }
  245. /**
  246. * Sets the state of wireframe mode
  247. */
  248. set wireframe(value) {
  249. this.fillMode = value ? Material.WireFrameFillMode : Material.TriangleFillMode;
  250. }
  251. /**
  252. * Gets the value specifying if point clouds are enabled
  253. */
  254. get pointsCloud() {
  255. switch (this._fillMode) {
  256. case Material.PointFillMode:
  257. case Material.PointListDrawMode:
  258. return true;
  259. }
  260. return this._scene.forcePointsCloud;
  261. }
  262. /**
  263. * Sets the state of point cloud mode
  264. */
  265. set pointsCloud(value) {
  266. this.fillMode = value ? Material.PointFillMode : Material.TriangleFillMode;
  267. }
  268. /**
  269. * Gets the material fill mode
  270. */
  271. get fillMode() {
  272. return this._fillMode;
  273. }
  274. /**
  275. * Sets the material fill mode
  276. */
  277. set fillMode(value) {
  278. if (this._fillMode === value) {
  279. return;
  280. }
  281. this._fillMode = value;
  282. this.markAsDirty(Material.MiscDirtyFlag);
  283. }
  284. /**
  285. * In case the depth buffer does not allow enough depth precision for your scene (might be the case in large scenes)
  286. * You can try switching to logarithmic depth.
  287. * @see https://doc.babylonjs.com/features/featuresDeepDive/materials/advanced/logarithmicDepthBuffer
  288. */
  289. get useLogarithmicDepth() {
  290. return this._useLogarithmicDepth;
  291. }
  292. set useLogarithmicDepth(value) {
  293. const fragmentDepthSupported = this.getScene().getEngine().getCaps().fragmentDepthSupported;
  294. if (value && !fragmentDepthSupported) {
  295. Logger.Warn("Logarithmic depth has been requested for a material on a device that doesn't support it.");
  296. }
  297. this._useLogarithmicDepth = value && fragmentDepthSupported;
  298. this._markAllSubMeshesAsMiscDirty();
  299. }
  300. /** @internal */
  301. _getDrawWrapper() {
  302. return this._drawWrapper;
  303. }
  304. /**
  305. * @internal
  306. */
  307. _setDrawWrapper(drawWrapper) {
  308. this._drawWrapper = drawWrapper;
  309. }
  310. /**
  311. * Creates a material instance
  312. * @param name defines the name of the material
  313. * @param scene defines the scene to reference
  314. * @param doNotAdd specifies if the material should be added to the scene
  315. */
  316. constructor(name, scene, doNotAdd) {
  317. /**
  318. * Custom shadow depth material to use for shadow rendering instead of the in-built one
  319. */
  320. this.shadowDepthWrapper = null;
  321. /**
  322. * Gets or sets a boolean indicating that the material is allowed (if supported) to do shader hot swapping.
  323. * This means that the material can keep using a previous shader while a new one is being compiled.
  324. * This is mostly used when shader parallel compilation is supported (true by default)
  325. */
  326. this.allowShaderHotSwapping = true;
  327. /**
  328. * Gets or sets user defined metadata
  329. */
  330. this.metadata = null;
  331. /**
  332. * For internal use only. Please do not use.
  333. */
  334. this.reservedDataStore = null;
  335. /**
  336. * Specifies if the ready state should be checked on each call
  337. */
  338. this.checkReadyOnEveryCall = false;
  339. /**
  340. * Specifies if the ready state should be checked once
  341. */
  342. this.checkReadyOnlyOnce = false;
  343. /**
  344. * The state of the material
  345. */
  346. this.state = "";
  347. /**
  348. * The alpha value of the material
  349. */
  350. this._alpha = 1.0;
  351. /**
  352. * Specifies if back face culling is enabled
  353. */
  354. this._backFaceCulling = true;
  355. /**
  356. * Specifies if back or front faces should be culled (when culling is enabled)
  357. */
  358. this._cullBackFaces = true;
  359. this._blockDirtyMechanism = false;
  360. /**
  361. * Callback triggered when the material is compiled
  362. */
  363. this.onCompiled = null;
  364. /**
  365. * Callback triggered when an error occurs
  366. */
  367. this.onError = null;
  368. /**
  369. * Callback triggered to get the render target textures
  370. */
  371. this.getRenderTargetTextures = null;
  372. /**
  373. * Specifies if the material should be serialized
  374. */
  375. this.doNotSerialize = false;
  376. /**
  377. * @internal
  378. */
  379. this._storeEffectOnSubMeshes = false;
  380. /**
  381. * Stores the animations for the material
  382. */
  383. this.animations = null;
  384. /**
  385. * An event triggered when the material is disposed
  386. */
  387. this.onDisposeObservable = new Observable();
  388. /**
  389. * An observer which watches for dispose events
  390. */
  391. this._onDisposeObserver = null;
  392. this._onUnBindObservable = null;
  393. /**
  394. * An observer which watches for bind events
  395. */
  396. this._onBindObserver = null;
  397. /**
  398. * Stores the value of the alpha mode
  399. */
  400. this._alphaMode = 2;
  401. /**
  402. * Stores the state of the need depth pre-pass value
  403. */
  404. this._needDepthPrePass = false;
  405. /**
  406. * Specifies if depth writing should be disabled
  407. */
  408. this.disableDepthWrite = false;
  409. /**
  410. * Specifies if color writing should be disabled
  411. */
  412. this.disableColorWrite = false;
  413. /**
  414. * Specifies if depth writing should be forced
  415. */
  416. this.forceDepthWrite = false;
  417. /**
  418. * Specifies the depth function that should be used. 0 means the default engine function
  419. */
  420. this.depthFunction = 0;
  421. /**
  422. * Specifies if there should be a separate pass for culling
  423. */
  424. this.separateCullingPass = false;
  425. /**
  426. * Stores the state specifying if fog should be enabled
  427. */
  428. this._fogEnabled = true;
  429. /**
  430. * Stores the size of points
  431. */
  432. this.pointSize = 1.0;
  433. /**
  434. * Stores the z offset Factor value
  435. */
  436. this.zOffset = 0;
  437. /**
  438. * Stores the z offset Units value
  439. */
  440. this.zOffsetUnits = 0;
  441. /**
  442. * Gives access to the stencil properties of the material
  443. */
  444. this.stencil = new MaterialStencilState();
  445. /**
  446. * Specifies if uniform buffers should be used
  447. */
  448. this._useUBO = false;
  449. /**
  450. * Stores the fill mode state
  451. */
  452. this._fillMode = Material.TriangleFillMode;
  453. /**
  454. * Specifies if the depth write state should be cached
  455. */
  456. this._cachedDepthWriteState = false;
  457. /**
  458. * Specifies if the color write state should be cached
  459. */
  460. this._cachedColorWriteState = false;
  461. /**
  462. * Specifies if the depth function state should be cached
  463. */
  464. this._cachedDepthFunctionState = 0;
  465. /** @internal */
  466. this._indexInSceneMaterialArray = -1;
  467. /** @internal */
  468. this.meshMap = null;
  469. /** @internal */
  470. this._parentContainer = null;
  471. /** @internal */
  472. this._uniformBufferLayoutBuilt = false;
  473. this._eventInfo = {}; // will be initialized before each event notification
  474. /** @internal */
  475. this._callbackPluginEventGeneric = () => void 0;
  476. /** @internal */
  477. this._callbackPluginEventIsReadyForSubMesh = () => void 0;
  478. /** @internal */
  479. this._callbackPluginEventPrepareDefines = () => void 0;
  480. /** @internal */
  481. this._callbackPluginEventPrepareDefinesBeforeAttributes = () => void 0;
  482. /** @internal */
  483. this._callbackPluginEventHardBindForSubMesh = () => void 0;
  484. /** @internal */
  485. this._callbackPluginEventBindForSubMesh = () => void 0;
  486. /** @internal */
  487. this._callbackPluginEventHasRenderTargetTextures = () => void 0;
  488. /** @internal */
  489. this._callbackPluginEventFillRenderTargetTextures = () => void 0;
  490. /**
  491. * Enforces alpha test in opaque or blend mode in order to improve the performances of some situations.
  492. */
  493. this._forceAlphaTest = false;
  494. /**
  495. * The transparency mode of the material.
  496. */
  497. this._transparencyMode = null;
  498. this.name = name;
  499. const setScene = scene || EngineStore.LastCreatedScene;
  500. if (!setScene) {
  501. return;
  502. }
  503. this._scene = setScene;
  504. this._dirtyCallbacks = {};
  505. this._dirtyCallbacks[1] = this._markAllSubMeshesAsTexturesDirty.bind(this);
  506. this._dirtyCallbacks[2] = this._markAllSubMeshesAsLightsDirty.bind(this);
  507. this._dirtyCallbacks[4] = this._markAllSubMeshesAsFresnelDirty.bind(this);
  508. this._dirtyCallbacks[8] = this._markAllSubMeshesAsAttributesDirty.bind(this);
  509. this._dirtyCallbacks[16] = this._markAllSubMeshesAsMiscDirty.bind(this);
  510. this._dirtyCallbacks[32] = this._markAllSubMeshesAsPrePassDirty.bind(this);
  511. this._dirtyCallbacks[63] = this._markAllSubMeshesAsAllDirty.bind(this);
  512. this.id = name || Tools.RandomId();
  513. this.uniqueId = this._scene.getUniqueId();
  514. this._materialContext = this._scene.getEngine().createMaterialContext();
  515. this._drawWrapper = new DrawWrapper(this._scene.getEngine(), false);
  516. this._drawWrapper.materialContext = this._materialContext;
  517. if (this._scene.useRightHandedSystem) {
  518. this.sideOrientation = Material.ClockWiseSideOrientation;
  519. }
  520. else {
  521. this.sideOrientation = Material.CounterClockWiseSideOrientation;
  522. }
  523. this._uniformBuffer = new UniformBuffer(this._scene.getEngine(), undefined, undefined, name);
  524. this._useUBO = this.getScene().getEngine().supportsUniformBuffers;
  525. if (!doNotAdd) {
  526. this._scene.addMaterial(this);
  527. }
  528. if (this._scene.useMaterialMeshMap) {
  529. this.meshMap = {};
  530. }
  531. Material.OnEventObservable.notifyObservers(this, MaterialPluginEvent.Created);
  532. }
  533. /**
  534. * Returns a string representation of the current material
  535. * @param fullDetails defines a boolean indicating which levels of logging is desired
  536. * @returns a string with material information
  537. */
  538. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  539. toString(fullDetails) {
  540. const ret = "Name: " + this.name;
  541. return ret;
  542. }
  543. /**
  544. * Gets the class name of the material
  545. * @returns a string with the class name of the material
  546. */
  547. getClassName() {
  548. return "Material";
  549. }
  550. /** @internal */
  551. get _isMaterial() {
  552. return true;
  553. }
  554. /**
  555. * Specifies if updates for the material been locked
  556. */
  557. get isFrozen() {
  558. return this.checkReadyOnlyOnce;
  559. }
  560. /**
  561. * Locks updates for the material
  562. */
  563. freeze() {
  564. this.markDirty();
  565. this.checkReadyOnlyOnce = true;
  566. }
  567. /**
  568. * Unlocks updates for the material
  569. */
  570. unfreeze() {
  571. this.markDirty();
  572. this.checkReadyOnlyOnce = false;
  573. }
  574. /**
  575. * Specifies if the material is ready to be used
  576. * @param mesh defines the mesh to check
  577. * @param useInstances specifies if instances should be used
  578. * @returns a boolean indicating if the material is ready to be used
  579. */
  580. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  581. isReady(mesh, useInstances) {
  582. return true;
  583. }
  584. /**
  585. * Specifies that the submesh is ready to be used
  586. * @param mesh defines the mesh to check
  587. * @param subMesh defines which submesh to check
  588. * @param useInstances specifies that instances should be used
  589. * @returns a boolean indicating that the submesh is ready or not
  590. */
  591. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  592. isReadyForSubMesh(mesh, subMesh, useInstances) {
  593. const defines = subMesh.materialDefines;
  594. if (!defines) {
  595. return false;
  596. }
  597. this._eventInfo.isReadyForSubMesh = true;
  598. this._eventInfo.defines = defines;
  599. this._callbackPluginEventIsReadyForSubMesh(this._eventInfo);
  600. return this._eventInfo.isReadyForSubMesh;
  601. }
  602. /**
  603. * Returns the material effect
  604. * @returns the effect associated with the material
  605. */
  606. getEffect() {
  607. return this._drawWrapper.effect;
  608. }
  609. /**
  610. * Returns the current scene
  611. * @returns a Scene
  612. */
  613. getScene() {
  614. return this._scene;
  615. }
  616. /**
  617. * Gets the current transparency mode.
  618. */
  619. get transparencyMode() {
  620. return this._transparencyMode;
  621. }
  622. /**
  623. * Sets the transparency mode of the material.
  624. *
  625. * | Value | Type | Description |
  626. * | ----- | ----------------------------------- | ----------- |
  627. * | 0 | OPAQUE | |
  628. * | 1 | ALPHATEST | |
  629. * | 2 | ALPHABLEND | |
  630. * | 3 | ALPHATESTANDBLEND | |
  631. *
  632. */
  633. set transparencyMode(value) {
  634. if (this._transparencyMode === value) {
  635. return;
  636. }
  637. this._transparencyMode = value;
  638. this._forceAlphaTest = value === Material.MATERIAL_ALPHATESTANDBLEND;
  639. this._markAllSubMeshesAsTexturesAndMiscDirty();
  640. }
  641. /**
  642. * Returns true if alpha blending should be disabled.
  643. */
  644. get _disableAlphaBlending() {
  645. return this._transparencyMode === Material.MATERIAL_OPAQUE || this._transparencyMode === Material.MATERIAL_ALPHATEST;
  646. }
  647. /**
  648. * Specifies whether or not this material should be rendered in alpha blend mode.
  649. * @returns a boolean specifying if alpha blending is needed
  650. */
  651. needAlphaBlending() {
  652. if (this._disableAlphaBlending) {
  653. return false;
  654. }
  655. return this.alpha < 1.0;
  656. }
  657. /**
  658. * Specifies if the mesh will require alpha blending
  659. * @param mesh defines the mesh to check
  660. * @returns a boolean specifying if alpha blending is needed for the mesh
  661. */
  662. needAlphaBlendingForMesh(mesh) {
  663. if (mesh.visibility < 1.0) {
  664. return true;
  665. }
  666. if (this._disableAlphaBlending) {
  667. return false;
  668. }
  669. return mesh.hasVertexAlpha || this.needAlphaBlending();
  670. }
  671. /**
  672. * Specifies whether or not this material should be rendered in alpha test mode.
  673. * @returns a boolean specifying if an alpha test is needed.
  674. */
  675. needAlphaTesting() {
  676. if (this._forceAlphaTest) {
  677. return true;
  678. }
  679. return false;
  680. }
  681. /**
  682. * Specifies if material alpha testing should be turned on for the mesh
  683. * @param mesh defines the mesh to check
  684. * @returns a boolean specifying if alpha testing should be turned on for the mesh
  685. */
  686. _shouldTurnAlphaTestOn(mesh) {
  687. return !this.needAlphaBlendingForMesh(mesh) && this.needAlphaTesting();
  688. }
  689. /**
  690. * Gets the texture used for the alpha test
  691. * @returns the texture to use for alpha testing
  692. */
  693. getAlphaTestTexture() {
  694. return null;
  695. }
  696. /**
  697. * Marks the material to indicate that it needs to be re-calculated
  698. * @param forceMaterialDirty - Forces the material to be marked as dirty for all components (same as this.markAsDirty(Material.AllDirtyFlag)). You should use this flag if the material is frozen and you want to force a recompilation.
  699. */
  700. markDirty(forceMaterialDirty = false) {
  701. const meshes = this.getScene().meshes;
  702. for (const mesh of meshes) {
  703. if (!mesh.subMeshes) {
  704. continue;
  705. }
  706. for (const subMesh of mesh.subMeshes) {
  707. if (subMesh.getMaterial() !== this) {
  708. continue;
  709. }
  710. for (const drawWrapper of subMesh._drawWrappers) {
  711. if (!drawWrapper) {
  712. continue;
  713. }
  714. if (this._materialContext === drawWrapper.materialContext) {
  715. drawWrapper._wasPreviouslyReady = false;
  716. drawWrapper._wasPreviouslyUsingInstances = null;
  717. drawWrapper._forceRebindOnNextCall = forceMaterialDirty;
  718. }
  719. }
  720. }
  721. }
  722. if (forceMaterialDirty) {
  723. this.markAsDirty(Material.AllDirtyFlag);
  724. }
  725. }
  726. /**
  727. * @internal
  728. */
  729. _preBind(effect, overrideOrientation = null) {
  730. const engine = this._scene.getEngine();
  731. const orientation = overrideOrientation == null ? this.sideOrientation : overrideOrientation;
  732. const reverse = orientation === Material.ClockWiseSideOrientation;
  733. engine.enableEffect(effect ? effect : this._getDrawWrapper());
  734. engine.setState(this.backFaceCulling, this.zOffset, false, reverse, this._scene._mirroredCameraPosition ? !this.cullBackFaces : this.cullBackFaces, this.stencil, this.zOffsetUnits);
  735. return reverse;
  736. }
  737. /**
  738. * Binds the material to the mesh
  739. * @param world defines the world transformation matrix
  740. * @param mesh defines the mesh to bind the material to
  741. */
  742. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  743. bind(world, mesh) { }
  744. /**
  745. * Initializes the uniform buffer layout for the shader.
  746. */
  747. buildUniformLayout() {
  748. const ubo = this._uniformBuffer;
  749. this._eventInfo.ubo = ubo;
  750. this._callbackPluginEventGeneric(MaterialPluginEvent.PrepareUniformBuffer, this._eventInfo);
  751. ubo.create();
  752. this._uniformBufferLayoutBuilt = true;
  753. }
  754. /**
  755. * Binds the submesh to the material
  756. * @param world defines the world transformation matrix
  757. * @param mesh defines the mesh containing the submesh
  758. * @param subMesh defines the submesh to bind the material to
  759. */
  760. bindForSubMesh(world, mesh, subMesh) {
  761. const drawWrapper = subMesh._drawWrapper;
  762. this._eventInfo.subMesh = subMesh;
  763. this._callbackPluginEventBindForSubMesh(this._eventInfo);
  764. drawWrapper._forceRebindOnNextCall = false;
  765. }
  766. /**
  767. * Binds the world matrix to the material
  768. * @param world defines the world transformation matrix
  769. */
  770. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  771. bindOnlyWorldMatrix(world) { }
  772. /**
  773. * Binds the view matrix to the effect
  774. * @param effect defines the effect to bind the view matrix to
  775. */
  776. bindView(effect) {
  777. if (!this._useUBO) {
  778. effect.setMatrix("view", this.getScene().getViewMatrix());
  779. }
  780. else {
  781. this._needToBindSceneUbo = true;
  782. }
  783. }
  784. /**
  785. * Binds the view projection and projection matrices to the effect
  786. * @param effect defines the effect to bind the view projection and projection matrices to
  787. */
  788. bindViewProjection(effect) {
  789. if (!this._useUBO) {
  790. effect.setMatrix("viewProjection", this.getScene().getTransformMatrix());
  791. effect.setMatrix("projection", this.getScene().getProjectionMatrix());
  792. }
  793. else {
  794. this._needToBindSceneUbo = true;
  795. }
  796. }
  797. /**
  798. * Binds the view matrix to the effect
  799. * @param effect defines the effect to bind the view matrix to
  800. * @param variableName name of the shader variable that will hold the eye position
  801. */
  802. bindEyePosition(effect, variableName) {
  803. if (!this._useUBO) {
  804. this._scene.bindEyePosition(effect, variableName);
  805. }
  806. else {
  807. this._needToBindSceneUbo = true;
  808. }
  809. }
  810. /**
  811. * Processes to execute after binding the material to a mesh
  812. * @param mesh defines the rendered mesh
  813. * @param effect defines the effect used to bind the material
  814. * @param _subMesh defines the subMesh that the material has been bound for
  815. */
  816. _afterBind(mesh, effect = null, _subMesh) {
  817. this._scene._cachedMaterial = this;
  818. if (this._needToBindSceneUbo) {
  819. if (effect) {
  820. this._needToBindSceneUbo = false;
  821. BindSceneUniformBuffer(effect, this.getScene().getSceneUniformBuffer());
  822. this._scene.finalizeSceneUbo();
  823. }
  824. }
  825. if (mesh) {
  826. this._scene._cachedVisibility = mesh.visibility;
  827. }
  828. else {
  829. this._scene._cachedVisibility = 1;
  830. }
  831. if (this._onBindObservable && mesh) {
  832. this._onBindObservable.notifyObservers(mesh);
  833. }
  834. if (this.disableDepthWrite) {
  835. const engine = this._scene.getEngine();
  836. this._cachedDepthWriteState = engine.getDepthWrite();
  837. engine.setDepthWrite(false);
  838. }
  839. if (this.disableColorWrite) {
  840. const engine = this._scene.getEngine();
  841. this._cachedColorWriteState = engine.getColorWrite();
  842. engine.setColorWrite(false);
  843. }
  844. if (this.depthFunction !== 0) {
  845. const engine = this._scene.getEngine();
  846. this._cachedDepthFunctionState = engine.getDepthFunction() || 0;
  847. engine.setDepthFunction(this.depthFunction);
  848. }
  849. }
  850. /**
  851. * Unbinds the material from the mesh
  852. */
  853. unbind() {
  854. if (this._onUnBindObservable) {
  855. this._onUnBindObservable.notifyObservers(this);
  856. }
  857. if (this.depthFunction !== 0) {
  858. const engine = this._scene.getEngine();
  859. engine.setDepthFunction(this._cachedDepthFunctionState);
  860. }
  861. if (this.disableDepthWrite) {
  862. const engine = this._scene.getEngine();
  863. engine.setDepthWrite(this._cachedDepthWriteState);
  864. }
  865. if (this.disableColorWrite) {
  866. const engine = this._scene.getEngine();
  867. engine.setColorWrite(this._cachedColorWriteState);
  868. }
  869. }
  870. /**
  871. * Returns the animatable textures.
  872. * @returns - Array of animatable textures.
  873. */
  874. getAnimatables() {
  875. this._eventInfo.animatables = [];
  876. this._callbackPluginEventGeneric(MaterialPluginEvent.GetAnimatables, this._eventInfo);
  877. return this._eventInfo.animatables;
  878. }
  879. /**
  880. * Gets the active textures from the material
  881. * @returns an array of textures
  882. */
  883. getActiveTextures() {
  884. this._eventInfo.activeTextures = [];
  885. this._callbackPluginEventGeneric(MaterialPluginEvent.GetActiveTextures, this._eventInfo);
  886. return this._eventInfo.activeTextures;
  887. }
  888. /**
  889. * Specifies if the material uses a texture
  890. * @param texture defines the texture to check against the material
  891. * @returns a boolean specifying if the material uses the texture
  892. */
  893. hasTexture(texture) {
  894. this._eventInfo.hasTexture = false;
  895. this._eventInfo.texture = texture;
  896. this._callbackPluginEventGeneric(MaterialPluginEvent.HasTexture, this._eventInfo);
  897. return this._eventInfo.hasTexture;
  898. }
  899. /**
  900. * Makes a duplicate of the material, and gives it a new name
  901. * @param name defines the new name for the duplicated material
  902. * @returns the cloned material
  903. */
  904. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  905. clone(name) {
  906. return null;
  907. }
  908. _clonePlugins(targetMaterial, rootUrl) {
  909. const serializationObject = {};
  910. // Create plugins in targetMaterial in case they don't exist
  911. this._serializePlugins(serializationObject);
  912. Material._ParsePlugins(serializationObject, targetMaterial, this._scene, rootUrl);
  913. // Copy the properties of the current plugins to the cloned material's plugins
  914. if (this.pluginManager) {
  915. for (const plugin of this.pluginManager._plugins) {
  916. const targetPlugin = targetMaterial.pluginManager.getPlugin(plugin.name);
  917. if (targetPlugin) {
  918. plugin.copyTo(targetPlugin);
  919. }
  920. }
  921. }
  922. }
  923. /**
  924. * Gets the meshes bound to the material
  925. * @returns an array of meshes bound to the material
  926. */
  927. getBindedMeshes() {
  928. if (this.meshMap) {
  929. const result = [];
  930. for (const meshId in this.meshMap) {
  931. const mesh = this.meshMap[meshId];
  932. if (mesh) {
  933. result.push(mesh);
  934. }
  935. }
  936. return result;
  937. }
  938. else {
  939. const meshes = this._scene.meshes;
  940. return meshes.filter((mesh) => mesh.material === this);
  941. }
  942. }
  943. /**
  944. * Force shader compilation
  945. * @param mesh defines the mesh associated with this material
  946. * @param onCompiled defines a function to execute once the material is compiled
  947. * @param options defines the options to configure the compilation
  948. * @param onError defines a function to execute if the material fails compiling
  949. */
  950. forceCompilation(mesh, onCompiled, options, onError) {
  951. const localOptions = {
  952. clipPlane: false,
  953. useInstances: false,
  954. ...options,
  955. };
  956. const scene = this.getScene();
  957. const currentHotSwapingState = this.allowShaderHotSwapping;
  958. this.allowShaderHotSwapping = false; // Turned off to let us evaluate the real compilation state
  959. const checkReady = () => {
  960. if (!this._scene || !this._scene.getEngine()) {
  961. return;
  962. }
  963. const clipPlaneState = scene.clipPlane;
  964. if (localOptions.clipPlane) {
  965. scene.clipPlane = new Plane(0, 0, 0, 1);
  966. }
  967. if (this._storeEffectOnSubMeshes) {
  968. let allDone = true, lastError = null;
  969. if (mesh.subMeshes) {
  970. const tempSubMesh = new SubMesh(0, 0, 0, 0, 0, mesh, undefined, false, false);
  971. if (tempSubMesh.materialDefines) {
  972. tempSubMesh.materialDefines._renderId = -1;
  973. }
  974. if (!this.isReadyForSubMesh(mesh, tempSubMesh, localOptions.useInstances)) {
  975. if (tempSubMesh.effect && tempSubMesh.effect.getCompilationError() && tempSubMesh.effect.allFallbacksProcessed()) {
  976. lastError = tempSubMesh.effect.getCompilationError();
  977. }
  978. else {
  979. allDone = false;
  980. setTimeout(checkReady, 16);
  981. }
  982. }
  983. }
  984. if (allDone) {
  985. this.allowShaderHotSwapping = currentHotSwapingState;
  986. if (lastError) {
  987. if (onError) {
  988. onError(lastError);
  989. }
  990. }
  991. if (onCompiled) {
  992. onCompiled(this);
  993. }
  994. }
  995. }
  996. else {
  997. if (this.isReady()) {
  998. this.allowShaderHotSwapping = currentHotSwapingState;
  999. if (onCompiled) {
  1000. onCompiled(this);
  1001. }
  1002. }
  1003. else {
  1004. setTimeout(checkReady, 16);
  1005. }
  1006. }
  1007. if (localOptions.clipPlane) {
  1008. scene.clipPlane = clipPlaneState;
  1009. }
  1010. };
  1011. checkReady();
  1012. }
  1013. /**
  1014. * Force shader compilation
  1015. * @param mesh defines the mesh that will use this material
  1016. * @param options defines additional options for compiling the shaders
  1017. * @returns a promise that resolves when the compilation completes
  1018. */
  1019. forceCompilationAsync(mesh, options) {
  1020. return new Promise((resolve, reject) => {
  1021. this.forceCompilation(mesh, () => {
  1022. resolve();
  1023. }, options, (reason) => {
  1024. reject(reason);
  1025. });
  1026. });
  1027. }
  1028. /**
  1029. * Marks a define in the material to indicate that it needs to be re-computed
  1030. * @param flag defines a flag used to determine which parts of the material have to be marked as dirty
  1031. */
  1032. markAsDirty(flag) {
  1033. if (this.getScene().blockMaterialDirtyMechanism || this._blockDirtyMechanism) {
  1034. return;
  1035. }
  1036. Material._DirtyCallbackArray.length = 0;
  1037. if (flag & Material.TextureDirtyFlag) {
  1038. Material._DirtyCallbackArray.push(Material._TextureDirtyCallBack);
  1039. }
  1040. if (flag & Material.LightDirtyFlag) {
  1041. Material._DirtyCallbackArray.push(Material._LightsDirtyCallBack);
  1042. }
  1043. if (flag & Material.FresnelDirtyFlag) {
  1044. Material._DirtyCallbackArray.push(Material._FresnelDirtyCallBack);
  1045. }
  1046. if (flag & Material.AttributesDirtyFlag) {
  1047. Material._DirtyCallbackArray.push(Material._AttributeDirtyCallBack);
  1048. }
  1049. if (flag & Material.MiscDirtyFlag) {
  1050. Material._DirtyCallbackArray.push(Material._MiscDirtyCallBack);
  1051. }
  1052. if (flag & Material.PrePassDirtyFlag) {
  1053. Material._DirtyCallbackArray.push(Material._PrePassDirtyCallBack);
  1054. }
  1055. if (Material._DirtyCallbackArray.length) {
  1056. this._markAllSubMeshesAsDirty(Material._RunDirtyCallBacks);
  1057. }
  1058. this.getScene().resetCachedMaterial();
  1059. }
  1060. /**
  1061. * Resets the draw wrappers cache for all submeshes that are using this material
  1062. */
  1063. resetDrawCache() {
  1064. const meshes = this.getScene().meshes;
  1065. for (const mesh of meshes) {
  1066. if (!mesh.subMeshes) {
  1067. continue;
  1068. }
  1069. for (const subMesh of mesh.subMeshes) {
  1070. if (subMesh.getMaterial() !== this) {
  1071. continue;
  1072. }
  1073. subMesh.resetDrawCache();
  1074. }
  1075. }
  1076. }
  1077. /**
  1078. * Marks all submeshes of a material to indicate that their material defines need to be re-calculated
  1079. * @param func defines a function which checks material defines against the submeshes
  1080. */
  1081. _markAllSubMeshesAsDirty(func) {
  1082. if (this.getScene().blockMaterialDirtyMechanism || this._blockDirtyMechanism) {
  1083. return;
  1084. }
  1085. const meshes = this.getScene().meshes;
  1086. for (const mesh of meshes) {
  1087. if (!mesh.subMeshes) {
  1088. continue;
  1089. }
  1090. for (const subMesh of mesh.subMeshes) {
  1091. // We want to skip the submeshes which are not using this material or which have not yet rendered at least once
  1092. if (subMesh.getMaterial(false) !== this) {
  1093. continue;
  1094. }
  1095. for (const drawWrapper of subMesh._drawWrappers) {
  1096. if (!drawWrapper || !drawWrapper.defines || !drawWrapper.defines.markAllAsDirty) {
  1097. continue;
  1098. }
  1099. if (this._materialContext === drawWrapper.materialContext) {
  1100. func(drawWrapper.defines);
  1101. }
  1102. }
  1103. }
  1104. }
  1105. }
  1106. /**
  1107. * Indicates that the scene should check if the rendering now needs a prepass
  1108. */
  1109. _markScenePrePassDirty() {
  1110. if (this.getScene().blockMaterialDirtyMechanism || this._blockDirtyMechanism) {
  1111. return;
  1112. }
  1113. const prePassRenderer = this.getScene().enablePrePassRenderer();
  1114. if (prePassRenderer) {
  1115. prePassRenderer.markAsDirty();
  1116. }
  1117. }
  1118. /**
  1119. * Indicates that we need to re-calculated for all submeshes
  1120. */
  1121. _markAllSubMeshesAsAllDirty() {
  1122. this._markAllSubMeshesAsDirty(Material._AllDirtyCallBack);
  1123. }
  1124. /**
  1125. * Indicates that image processing needs to be re-calculated for all submeshes
  1126. */
  1127. _markAllSubMeshesAsImageProcessingDirty() {
  1128. this._markAllSubMeshesAsDirty(Material._ImageProcessingDirtyCallBack);
  1129. }
  1130. /**
  1131. * Indicates that textures need to be re-calculated for all submeshes
  1132. */
  1133. _markAllSubMeshesAsTexturesDirty() {
  1134. this._markAllSubMeshesAsDirty(Material._TextureDirtyCallBack);
  1135. }
  1136. /**
  1137. * Indicates that fresnel needs to be re-calculated for all submeshes
  1138. */
  1139. _markAllSubMeshesAsFresnelDirty() {
  1140. this._markAllSubMeshesAsDirty(Material._FresnelDirtyCallBack);
  1141. }
  1142. /**
  1143. * Indicates that fresnel and misc need to be re-calculated for all submeshes
  1144. */
  1145. _markAllSubMeshesAsFresnelAndMiscDirty() {
  1146. this._markAllSubMeshesAsDirty(Material._FresnelAndMiscDirtyCallBack);
  1147. }
  1148. /**
  1149. * Indicates that lights need to be re-calculated for all submeshes
  1150. */
  1151. _markAllSubMeshesAsLightsDirty() {
  1152. this._markAllSubMeshesAsDirty(Material._LightsDirtyCallBack);
  1153. }
  1154. /**
  1155. * Indicates that attributes need to be re-calculated for all submeshes
  1156. */
  1157. _markAllSubMeshesAsAttributesDirty() {
  1158. this._markAllSubMeshesAsDirty(Material._AttributeDirtyCallBack);
  1159. }
  1160. /**
  1161. * Indicates that misc needs to be re-calculated for all submeshes
  1162. */
  1163. _markAllSubMeshesAsMiscDirty() {
  1164. this._markAllSubMeshesAsDirty(Material._MiscDirtyCallBack);
  1165. }
  1166. /**
  1167. * Indicates that prepass needs to be re-calculated for all submeshes
  1168. */
  1169. _markAllSubMeshesAsPrePassDirty() {
  1170. this._markAllSubMeshesAsDirty(Material._MiscDirtyCallBack);
  1171. }
  1172. /**
  1173. * Indicates that textures and misc need to be re-calculated for all submeshes
  1174. */
  1175. _markAllSubMeshesAsTexturesAndMiscDirty() {
  1176. this._markAllSubMeshesAsDirty(Material._TextureAndMiscDirtyCallBack);
  1177. }
  1178. _checkScenePerformancePriority() {
  1179. if (this._scene.performancePriority !== ScenePerformancePriority.BackwardCompatible) {
  1180. this.checkReadyOnlyOnce = true;
  1181. // re-set the flag when the perf priority changes
  1182. const observer = this._scene.onScenePerformancePriorityChangedObservable.addOnce(() => {
  1183. this.checkReadyOnlyOnce = false;
  1184. });
  1185. // if this material is disposed before the scene is disposed, cleanup the observer
  1186. this.onDisposeObservable.add(() => {
  1187. this._scene.onScenePerformancePriorityChangedObservable.remove(observer);
  1188. });
  1189. }
  1190. }
  1191. /**
  1192. * Sets the required values to the prepass renderer.
  1193. * @param prePassRenderer defines the prepass renderer to setup.
  1194. * @returns true if the pre pass is needed.
  1195. */
  1196. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  1197. setPrePassRenderer(prePassRenderer) {
  1198. // Do Nothing by default
  1199. return false;
  1200. }
  1201. /**
  1202. * Disposes the material
  1203. * @param forceDisposeEffect specifies if effects should be forcefully disposed
  1204. * @param forceDisposeTextures specifies if textures should be forcefully disposed
  1205. * @param notBoundToMesh specifies if the material that is being disposed is known to be not bound to any mesh
  1206. */
  1207. dispose(forceDisposeEffect, forceDisposeTextures, notBoundToMesh) {
  1208. const scene = this.getScene();
  1209. // Animations
  1210. scene.stopAnimation(this);
  1211. scene.freeProcessedMaterials();
  1212. // Remove from scene
  1213. scene.removeMaterial(this);
  1214. this._eventInfo.forceDisposeTextures = forceDisposeTextures;
  1215. this._callbackPluginEventGeneric(MaterialPluginEvent.Disposed, this._eventInfo);
  1216. if (this._parentContainer) {
  1217. const index = this._parentContainer.materials.indexOf(this);
  1218. if (index > -1) {
  1219. this._parentContainer.materials.splice(index, 1);
  1220. }
  1221. this._parentContainer = null;
  1222. }
  1223. if (notBoundToMesh !== true) {
  1224. // Remove from meshes
  1225. if (this.meshMap) {
  1226. for (const meshId in this.meshMap) {
  1227. const mesh = this.meshMap[meshId];
  1228. if (mesh) {
  1229. mesh.material = null; // will set the entry in the map to undefined
  1230. this.releaseVertexArrayObject(mesh, forceDisposeEffect);
  1231. }
  1232. }
  1233. }
  1234. else {
  1235. const meshes = scene.meshes;
  1236. for (const mesh of meshes) {
  1237. if (mesh.material === this && !mesh.sourceMesh) {
  1238. mesh.material = null;
  1239. this.releaseVertexArrayObject(mesh, forceDisposeEffect);
  1240. }
  1241. }
  1242. }
  1243. }
  1244. this._uniformBuffer.dispose();
  1245. // Shader are kept in cache for further use but we can get rid of this by using forceDisposeEffect
  1246. if (forceDisposeEffect && this._drawWrapper.effect) {
  1247. if (!this._storeEffectOnSubMeshes) {
  1248. this._drawWrapper.effect.dispose();
  1249. }
  1250. this._drawWrapper.effect = null;
  1251. }
  1252. this.metadata = null;
  1253. // Callback
  1254. this.onDisposeObservable.notifyObservers(this);
  1255. this.onDisposeObservable.clear();
  1256. if (this._onBindObservable) {
  1257. this._onBindObservable.clear();
  1258. }
  1259. if (this._onUnBindObservable) {
  1260. this._onUnBindObservable.clear();
  1261. }
  1262. if (this._onEffectCreatedObservable) {
  1263. this._onEffectCreatedObservable.clear();
  1264. }
  1265. if (this._eventInfo) {
  1266. this._eventInfo = {};
  1267. }
  1268. }
  1269. /**
  1270. * @internal
  1271. */
  1272. // eslint-disable-next-line @typescript-eslint/naming-convention
  1273. releaseVertexArrayObject(mesh, forceDisposeEffect) {
  1274. const geometry = mesh.geometry;
  1275. if (geometry) {
  1276. if (this._storeEffectOnSubMeshes) {
  1277. if (mesh.subMeshes) {
  1278. for (const subMesh of mesh.subMeshes) {
  1279. geometry._releaseVertexArrayObject(subMesh.effect);
  1280. if (forceDisposeEffect && subMesh.effect) {
  1281. subMesh.effect.dispose();
  1282. }
  1283. }
  1284. }
  1285. }
  1286. else {
  1287. geometry._releaseVertexArrayObject(this._drawWrapper.effect);
  1288. }
  1289. }
  1290. }
  1291. /**
  1292. * Serializes this material
  1293. * @returns the serialized material object
  1294. */
  1295. serialize() {
  1296. const serializationObject = SerializationHelper.Serialize(this);
  1297. serializationObject.stencil = this.stencil.serialize();
  1298. serializationObject.uniqueId = this.uniqueId;
  1299. this._serializePlugins(serializationObject);
  1300. return serializationObject;
  1301. }
  1302. _serializePlugins(serializationObject) {
  1303. serializationObject.plugins = {};
  1304. if (this.pluginManager) {
  1305. for (const plugin of this.pluginManager._plugins) {
  1306. serializationObject.plugins[plugin.getClassName()] = plugin.serialize();
  1307. }
  1308. }
  1309. }
  1310. /**
  1311. * Creates a material from parsed material data
  1312. * @param parsedMaterial defines parsed material data
  1313. * @param scene defines the hosting scene
  1314. * @param rootUrl defines the root URL to use to load textures
  1315. * @returns a new material
  1316. */
  1317. static Parse(parsedMaterial, scene, rootUrl) {
  1318. if (!parsedMaterial.customType) {
  1319. parsedMaterial.customType = "BABYLON.StandardMaterial";
  1320. }
  1321. else if (parsedMaterial.customType === "BABYLON.PBRMaterial" && parsedMaterial.overloadedAlbedo) {
  1322. parsedMaterial.customType = "BABYLON.LegacyPBRMaterial";
  1323. if (!BABYLON.LegacyPBRMaterial) {
  1324. Logger.Error("Your scene is trying to load a legacy version of the PBRMaterial, please, include it from the materials library.");
  1325. return null;
  1326. }
  1327. }
  1328. const materialType = Tools.Instantiate(parsedMaterial.customType);
  1329. const material = materialType.Parse(parsedMaterial, scene, rootUrl);
  1330. material._loadedUniqueId = parsedMaterial.uniqueId;
  1331. return material;
  1332. }
  1333. static _ParsePlugins(serializationObject, material, scene, rootUrl) {
  1334. if (!serializationObject.plugins) {
  1335. return;
  1336. }
  1337. for (const pluginClassName in serializationObject.plugins) {
  1338. const pluginData = serializationObject.plugins[pluginClassName];
  1339. let plugin = material.pluginManager?.getPlugin(pluginData.name);
  1340. if (!plugin) {
  1341. const pluginClassType = Tools.Instantiate("BABYLON." + pluginClassName);
  1342. if (pluginClassType) {
  1343. plugin = new pluginClassType(material);
  1344. }
  1345. }
  1346. plugin?.parse(pluginData, scene, rootUrl);
  1347. }
  1348. }
  1349. }
  1350. /**
  1351. * Returns the triangle fill mode
  1352. */
  1353. Material.TriangleFillMode = 0;
  1354. /**
  1355. * Returns the wireframe mode
  1356. */
  1357. Material.WireFrameFillMode = 1;
  1358. /**
  1359. * Returns the point fill mode
  1360. */
  1361. Material.PointFillMode = 2;
  1362. /**
  1363. * Returns the point list draw mode
  1364. */
  1365. Material.PointListDrawMode = 3;
  1366. /**
  1367. * Returns the line list draw mode
  1368. */
  1369. Material.LineListDrawMode = 4;
  1370. /**
  1371. * Returns the line loop draw mode
  1372. */
  1373. Material.LineLoopDrawMode = 5;
  1374. /**
  1375. * Returns the line strip draw mode
  1376. */
  1377. Material.LineStripDrawMode = 6;
  1378. /**
  1379. * Returns the triangle strip draw mode
  1380. */
  1381. Material.TriangleStripDrawMode = 7;
  1382. /**
  1383. * Returns the triangle fan draw mode
  1384. */
  1385. Material.TriangleFanDrawMode = 8;
  1386. /**
  1387. * Stores the clock-wise side orientation
  1388. */
  1389. Material.ClockWiseSideOrientation = 0;
  1390. /**
  1391. * Stores the counter clock-wise side orientation
  1392. */
  1393. Material.CounterClockWiseSideOrientation = 1;
  1394. /**
  1395. * The dirty texture flag value
  1396. */
  1397. Material.TextureDirtyFlag = 1;
  1398. /**
  1399. * The dirty light flag value
  1400. */
  1401. Material.LightDirtyFlag = 2;
  1402. /**
  1403. * The dirty fresnel flag value
  1404. */
  1405. Material.FresnelDirtyFlag = 4;
  1406. /**
  1407. * The dirty attribute flag value
  1408. */
  1409. Material.AttributesDirtyFlag = 8;
  1410. /**
  1411. * The dirty misc flag value
  1412. */
  1413. Material.MiscDirtyFlag = 16;
  1414. /**
  1415. * The dirty prepass flag value
  1416. */
  1417. Material.PrePassDirtyFlag = 32;
  1418. /**
  1419. * The all dirty flag value
  1420. */
  1421. Material.AllDirtyFlag = 63;
  1422. /**
  1423. * MaterialTransparencyMode: No transparency mode, Alpha channel is not use.
  1424. */
  1425. Material.MATERIAL_OPAQUE = 0;
  1426. /**
  1427. * MaterialTransparencyMode: Alpha Test mode, pixel are discarded below a certain threshold defined by the alpha cutoff value.
  1428. */
  1429. Material.MATERIAL_ALPHATEST = 1;
  1430. /**
  1431. * MaterialTransparencyMode: Pixels are blended (according to the alpha mode) with the already drawn pixels in the current frame buffer.
  1432. */
  1433. Material.MATERIAL_ALPHABLEND = 2;
  1434. /**
  1435. * MaterialTransparencyMode: Pixels are blended (according to the alpha mode) with the already drawn pixels in the current frame buffer.
  1436. * They are also discarded below the alpha cutoff threshold to improve performances.
  1437. */
  1438. Material.MATERIAL_ALPHATESTANDBLEND = 3;
  1439. /**
  1440. * The Whiteout method is used to blend normals.
  1441. * Details of the algorithm can be found here: https://blog.selfshadow.com/publications/blending-in-detail/
  1442. */
  1443. Material.MATERIAL_NORMALBLENDMETHOD_WHITEOUT = 0;
  1444. /**
  1445. * The Reoriented Normal Mapping method is used to blend normals.
  1446. * Details of the algorithm can be found here: https://blog.selfshadow.com/publications/blending-in-detail/
  1447. */
  1448. Material.MATERIAL_NORMALBLENDMETHOD_RNM = 1;
  1449. /**
  1450. * Event observable which raises global events common to all materials (like MaterialPluginEvent.Created)
  1451. */
  1452. Material.OnEventObservable = new Observable();
  1453. Material._AllDirtyCallBack = (defines) => defines.markAllAsDirty();
  1454. Material._ImageProcessingDirtyCallBack = (defines) => defines.markAsImageProcessingDirty();
  1455. Material._TextureDirtyCallBack = (defines) => defines.markAsTexturesDirty();
  1456. Material._FresnelDirtyCallBack = (defines) => defines.markAsFresnelDirty();
  1457. Material._MiscDirtyCallBack = (defines) => defines.markAsMiscDirty();
  1458. Material._PrePassDirtyCallBack = (defines) => defines.markAsPrePassDirty();
  1459. Material._LightsDirtyCallBack = (defines) => defines.markAsLightDirty();
  1460. Material._AttributeDirtyCallBack = (defines) => defines.markAsAttributesDirty();
  1461. Material._FresnelAndMiscDirtyCallBack = (defines) => {
  1462. Material._FresnelDirtyCallBack(defines);
  1463. Material._MiscDirtyCallBack(defines);
  1464. };
  1465. Material._TextureAndMiscDirtyCallBack = (defines) => {
  1466. Material._TextureDirtyCallBack(defines);
  1467. Material._MiscDirtyCallBack(defines);
  1468. };
  1469. Material._DirtyCallbackArray = [];
  1470. Material._RunDirtyCallBacks = (defines) => {
  1471. for (const cb of Material._DirtyCallbackArray) {
  1472. cb(defines);
  1473. }
  1474. };
  1475. __decorate([
  1476. serialize()
  1477. ], Material.prototype, "id", void 0);
  1478. __decorate([
  1479. serialize()
  1480. ], Material.prototype, "uniqueId", void 0);
  1481. __decorate([
  1482. serialize()
  1483. ], Material.prototype, "name", void 0);
  1484. __decorate([
  1485. serialize()
  1486. ], Material.prototype, "metadata", void 0);
  1487. __decorate([
  1488. serialize()
  1489. ], Material.prototype, "checkReadyOnEveryCall", void 0);
  1490. __decorate([
  1491. serialize()
  1492. ], Material.prototype, "checkReadyOnlyOnce", void 0);
  1493. __decorate([
  1494. serialize()
  1495. ], Material.prototype, "state", void 0);
  1496. __decorate([
  1497. serialize("alpha")
  1498. ], Material.prototype, "_alpha", void 0);
  1499. __decorate([
  1500. serialize("backFaceCulling")
  1501. ], Material.prototype, "_backFaceCulling", void 0);
  1502. __decorate([
  1503. serialize("cullBackFaces")
  1504. ], Material.prototype, "_cullBackFaces", void 0);
  1505. __decorate([
  1506. serialize()
  1507. ], Material.prototype, "sideOrientation", void 0);
  1508. __decorate([
  1509. serialize("alphaMode")
  1510. ], Material.prototype, "_alphaMode", void 0);
  1511. __decorate([
  1512. serialize()
  1513. ], Material.prototype, "_needDepthPrePass", void 0);
  1514. __decorate([
  1515. serialize()
  1516. ], Material.prototype, "disableDepthWrite", void 0);
  1517. __decorate([
  1518. serialize()
  1519. ], Material.prototype, "disableColorWrite", void 0);
  1520. __decorate([
  1521. serialize()
  1522. ], Material.prototype, "forceDepthWrite", void 0);
  1523. __decorate([
  1524. serialize()
  1525. ], Material.prototype, "depthFunction", void 0);
  1526. __decorate([
  1527. serialize()
  1528. ], Material.prototype, "separateCullingPass", void 0);
  1529. __decorate([
  1530. serialize("fogEnabled")
  1531. ], Material.prototype, "_fogEnabled", void 0);
  1532. __decorate([
  1533. serialize()
  1534. ], Material.prototype, "pointSize", void 0);
  1535. __decorate([
  1536. serialize()
  1537. ], Material.prototype, "zOffset", void 0);
  1538. __decorate([
  1539. serialize()
  1540. ], Material.prototype, "zOffsetUnits", void 0);
  1541. __decorate([
  1542. serialize()
  1543. ], Material.prototype, "pointsCloud", null);
  1544. __decorate([
  1545. serialize()
  1546. ], Material.prototype, "fillMode", null);
  1547. __decorate([
  1548. serialize()
  1549. ], Material.prototype, "useLogarithmicDepth", null);
  1550. __decorate([
  1551. serialize()
  1552. ], Material.prototype, "transparencyMode", null);
  1553. //# sourceMappingURL=material.js.map