material.ts 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503
  1. import { serialize, SerializationHelper } from "../Misc/decorators";
  2. import { Tools } from "../Misc/tools";
  3. import { IAnimatable } from '../Animations/animatable.interface';
  4. import { SmartArray } from "../Misc/smartArray";
  5. import { Observer, Observable } from "../Misc/observable";
  6. import { Nullable } from "../types";
  7. import { Matrix } from "../Maths/math.vector";
  8. import { EngineStore } from "../Engines/engineStore";
  9. import { SubMesh } from "../Meshes/subMesh";
  10. import { Geometry } from "../Meshes/geometry";
  11. import { AbstractMesh } from "../Meshes/abstractMesh";
  12. import { UniformBuffer } from "./uniformBuffer";
  13. import { Effect } from "./effect";
  14. import { BaseTexture } from "../Materials/Textures/baseTexture";
  15. import { RenderTargetTexture } from "../Materials/Textures/renderTargetTexture";
  16. import { MaterialDefines } from "./materialDefines";
  17. import { Constants } from "../Engines/constants";
  18. import { Logger } from "../Misc/logger";
  19. import { IInspectable } from '../Misc/iInspectable';
  20. import { Plane } from '../Maths/math.plane';
  21. import { ShadowDepthWrapper } from './shadowDepthWrapper';
  22. import { MaterialHelper } from './materialHelper';
  23. declare type PrePassRenderer = import("../Rendering/prePassRenderer").PrePassRenderer;
  24. declare type Mesh = import("../Meshes/mesh").Mesh;
  25. declare type Animation = import("../Animations/animation").Animation;
  26. declare type InstancedMesh = import('../Meshes/instancedMesh').InstancedMesh;
  27. declare type Scene = import("../scene").Scene;
  28. declare var BABYLON: any;
  29. /**
  30. * Options for compiling materials.
  31. */
  32. export interface IMaterialCompilationOptions {
  33. /**
  34. * Defines whether clip planes are enabled.
  35. */
  36. clipPlane: boolean;
  37. /**
  38. * Defines whether instances are enabled.
  39. */
  40. useInstances: boolean;
  41. }
  42. /**
  43. * Options passed when calling customShaderNameResolve
  44. */
  45. export interface ICustomShaderNameResolveOptions {
  46. /**
  47. * If provided, will be called two times with the vertex and fragment code so that this code can be updated before it is compiled by the GPU
  48. */
  49. processFinalCode?: Nullable<(shaderType: string, code: string) => string>;
  50. }
  51. /**
  52. * Base class for the main features of a material in Babylon.js
  53. */
  54. export class Material implements IAnimatable {
  55. /**
  56. * Returns the triangle fill mode
  57. */
  58. public static readonly TriangleFillMode = Constants.MATERIAL_TriangleFillMode;
  59. /**
  60. * Returns the wireframe mode
  61. */
  62. public static readonly WireFrameFillMode = Constants.MATERIAL_WireFrameFillMode;
  63. /**
  64. * Returns the point fill mode
  65. */
  66. public static readonly PointFillMode = Constants.MATERIAL_PointFillMode;
  67. /**
  68. * Returns the point list draw mode
  69. */
  70. public static readonly PointListDrawMode = Constants.MATERIAL_PointListDrawMode;
  71. /**
  72. * Returns the line list draw mode
  73. */
  74. public static readonly LineListDrawMode = Constants.MATERIAL_LineListDrawMode;
  75. /**
  76. * Returns the line loop draw mode
  77. */
  78. public static readonly LineLoopDrawMode = Constants.MATERIAL_LineLoopDrawMode;
  79. /**
  80. * Returns the line strip draw mode
  81. */
  82. public static readonly LineStripDrawMode = Constants.MATERIAL_LineStripDrawMode;
  83. /**
  84. * Returns the triangle strip draw mode
  85. */
  86. public static readonly TriangleStripDrawMode = Constants.MATERIAL_TriangleStripDrawMode;
  87. /**
  88. * Returns the triangle fan draw mode
  89. */
  90. public static readonly TriangleFanDrawMode = Constants.MATERIAL_TriangleFanDrawMode;
  91. /**
  92. * Stores the clock-wise side orientation
  93. */
  94. public static readonly ClockWiseSideOrientation = Constants.MATERIAL_ClockWiseSideOrientation;
  95. /**
  96. * Stores the counter clock-wise side orientation
  97. */
  98. public static readonly CounterClockWiseSideOrientation = Constants.MATERIAL_CounterClockWiseSideOrientation;
  99. /**
  100. * The dirty texture flag value
  101. */
  102. public static readonly TextureDirtyFlag = Constants.MATERIAL_TextureDirtyFlag;
  103. /**
  104. * The dirty light flag value
  105. */
  106. public static readonly LightDirtyFlag = Constants.MATERIAL_LightDirtyFlag;
  107. /**
  108. * The dirty fresnel flag value
  109. */
  110. public static readonly FresnelDirtyFlag = Constants.MATERIAL_FresnelDirtyFlag;
  111. /**
  112. * The dirty attribute flag value
  113. */
  114. public static readonly AttributesDirtyFlag = Constants.MATERIAL_AttributesDirtyFlag;
  115. /**
  116. * The dirty misc flag value
  117. */
  118. public static readonly MiscDirtyFlag = Constants.MATERIAL_MiscDirtyFlag;
  119. /**
  120. * The dirty prepass flag value
  121. */
  122. public static readonly PrePassDirtyFlag = Constants.MATERIAL_PrePassDirtyFlag;
  123. /**
  124. * The all dirty flag value
  125. */
  126. public static readonly AllDirtyFlag = Constants.MATERIAL_AllDirtyFlag;
  127. /**
  128. * MaterialTransparencyMode: No transparency mode, Alpha channel is not use.
  129. */
  130. public static readonly MATERIAL_OPAQUE = 0;
  131. /**
  132. * MaterialTransparencyMode: Alpha Test mode, pixel are discarded below a certain threshold defined by the alpha cutoff value.
  133. */
  134. public static readonly MATERIAL_ALPHATEST = 1;
  135. /**
  136. * MaterialTransparencyMode: Pixels are blended (according to the alpha mode) with the already drawn pixels in the current frame buffer.
  137. */
  138. public static readonly MATERIAL_ALPHABLEND = 2;
  139. /**
  140. * MaterialTransparencyMode: Pixels are blended (according to the alpha mode) with the already drawn pixels in the current frame buffer.
  141. * They are also discarded below the alpha cutoff threshold to improve performances.
  142. */
  143. public static readonly MATERIAL_ALPHATESTANDBLEND = 3;
  144. /**
  145. * The Whiteout method is used to blend normals.
  146. * Details of the algorithm can be found here: https://blog.selfshadow.com/publications/blending-in-detail/
  147. */
  148. public static readonly MATERIAL_NORMALBLENDMETHOD_WHITEOUT = 0;
  149. /**
  150. * The Reoriented Normal Mapping method is used to blend normals.
  151. * Details of the algorithm can be found here: https://blog.selfshadow.com/publications/blending-in-detail/
  152. */
  153. public static readonly MATERIAL_NORMALBLENDMETHOD_RNM = 1;
  154. /**
  155. * Custom callback helping to override the default shader used in the material.
  156. */
  157. public customShaderNameResolve: (shaderName: string, uniforms: string[], uniformBuffers: string[], samplers: string[], defines: MaterialDefines | string[], attributes?: string[], options?: ICustomShaderNameResolveOptions) => string;
  158. /**
  159. * Custom shadow depth material to use for shadow rendering instead of the in-built one
  160. */
  161. public shadowDepthWrapper: Nullable<ShadowDepthWrapper> = null;
  162. /**
  163. * Gets or sets a boolean indicating that the material is allowed (if supported) to do shader hot swapping.
  164. * This means that the material can keep using a previous shader while a new one is being compiled.
  165. * This is mostly used when shader parallel compilation is supported (true by default)
  166. */
  167. public allowShaderHotSwapping = true;
  168. /**
  169. * The ID of the material
  170. */
  171. @serialize()
  172. public id: string;
  173. /**
  174. * Gets or sets the unique id of the material
  175. */
  176. @serialize()
  177. public uniqueId: number;
  178. /**
  179. * The name of the material
  180. */
  181. @serialize()
  182. public name: string;
  183. /**
  184. * Gets or sets user defined metadata
  185. */
  186. public metadata: any = null;
  187. /**
  188. * For internal use only. Please do not use.
  189. */
  190. public reservedDataStore: any = null;
  191. /**
  192. * Specifies if the ready state should be checked on each call
  193. */
  194. @serialize()
  195. public checkReadyOnEveryCall = false;
  196. /**
  197. * Specifies if the ready state should be checked once
  198. */
  199. @serialize()
  200. public checkReadyOnlyOnce = false;
  201. /**
  202. * The state of the material
  203. */
  204. @serialize()
  205. public state = "";
  206. /**
  207. * If the material can be rendered to several textures with MRT extension
  208. */
  209. public get canRenderToMRT() : boolean {
  210. // By default, shaders are not compatible with MRTs
  211. // Base classes should override that if their shader supports MRT
  212. return false;
  213. }
  214. /**
  215. * The alpha value of the material
  216. */
  217. @serialize("alpha")
  218. protected _alpha = 1.0;
  219. /**
  220. * List of inspectable custom properties (used by the Inspector)
  221. * @see https://doc.babylonjs.com/how_to/debug_layer#extensibility
  222. */
  223. public inspectableCustomProperties: IInspectable[];
  224. /**
  225. * Sets the alpha value of the material
  226. */
  227. public set alpha(value: number) {
  228. if (this._alpha === value) {
  229. return;
  230. }
  231. this._alpha = value;
  232. this.markAsDirty(Material.MiscDirtyFlag);
  233. }
  234. /**
  235. * Gets the alpha value of the material
  236. */
  237. public get alpha(): number {
  238. return this._alpha;
  239. }
  240. /**
  241. * Specifies if back face culling is enabled
  242. */
  243. @serialize("backFaceCulling")
  244. protected _backFaceCulling = true;
  245. /**
  246. * Sets the back-face culling state
  247. */
  248. public set backFaceCulling(value: boolean) {
  249. if (this._backFaceCulling === value) {
  250. return;
  251. }
  252. this._backFaceCulling = value;
  253. this.markAsDirty(Material.TextureDirtyFlag);
  254. }
  255. /**
  256. * Gets the back-face culling state
  257. */
  258. public get backFaceCulling(): boolean {
  259. return this._backFaceCulling;
  260. }
  261. /**
  262. * Stores the value for side orientation
  263. */
  264. @serialize()
  265. public sideOrientation: number;
  266. /**
  267. * Callback triggered when the material is compiled
  268. */
  269. public onCompiled: Nullable<(effect: Effect) => void> = null;
  270. /**
  271. * Callback triggered when an error occurs
  272. */
  273. public onError: Nullable<(effect: Effect, errors: string) => void> = null;
  274. /**
  275. * Callback triggered to get the render target textures
  276. */
  277. public getRenderTargetTextures: Nullable<() => SmartArray<RenderTargetTexture>> = null;
  278. /**
  279. * Gets a boolean indicating that current material needs to register RTT
  280. */
  281. public get hasRenderTargetTextures(): boolean {
  282. return false;
  283. }
  284. /**
  285. * Specifies if the material should be serialized
  286. */
  287. public doNotSerialize = false;
  288. /**
  289. * @hidden
  290. */
  291. public _storeEffectOnSubMeshes = false;
  292. /**
  293. * Stores the animations for the material
  294. */
  295. public animations: Nullable<Array<Animation>> = null;
  296. /**
  297. * An event triggered when the material is disposed
  298. */
  299. public onDisposeObservable = new Observable<Material>();
  300. /**
  301. * An observer which watches for dispose events
  302. */
  303. private _onDisposeObserver: Nullable<Observer<Material>> = null;
  304. private _onUnBindObservable: Nullable<Observable<Material>> = null;
  305. /**
  306. * Called during a dispose event
  307. */
  308. public set onDispose(callback: () => void) {
  309. if (this._onDisposeObserver) {
  310. this.onDisposeObservable.remove(this._onDisposeObserver);
  311. }
  312. this._onDisposeObserver = this.onDisposeObservable.add(callback);
  313. }
  314. private _onBindObservable: Nullable<Observable<AbstractMesh>>;
  315. /**
  316. * An event triggered when the material is bound
  317. */
  318. public get onBindObservable(): Observable<AbstractMesh> {
  319. if (!this._onBindObservable) {
  320. this._onBindObservable = new Observable<AbstractMesh>();
  321. }
  322. return this._onBindObservable;
  323. }
  324. /**
  325. * An observer which watches for bind events
  326. */
  327. private _onBindObserver: Nullable<Observer<AbstractMesh>> = null;
  328. /**
  329. * Called during a bind event
  330. */
  331. public set onBind(callback: (Mesh: AbstractMesh) => void) {
  332. if (this._onBindObserver) {
  333. this.onBindObservable.remove(this._onBindObserver);
  334. }
  335. this._onBindObserver = this.onBindObservable.add(callback);
  336. }
  337. /**
  338. * An event triggered when the material is unbound
  339. */
  340. public get onUnBindObservable(): Observable<Material> {
  341. if (!this._onUnBindObservable) {
  342. this._onUnBindObservable = new Observable<Material>();
  343. }
  344. return this._onUnBindObservable;
  345. }
  346. protected _onEffectCreatedObservable: Nullable<Observable<{ effect: Effect, subMesh: Nullable<SubMesh>}>>;
  347. /**
  348. * An event triggered when the effect is (re)created
  349. */
  350. public get onEffectCreatedObservable(): Observable<{ effect: Effect, subMesh: Nullable<SubMesh>}> {
  351. if (!this._onEffectCreatedObservable) {
  352. this._onEffectCreatedObservable = new Observable<{effect: Effect, subMesh: Nullable<SubMesh>}>();
  353. }
  354. return this._onEffectCreatedObservable;
  355. }
  356. /**
  357. * Stores the value of the alpha mode
  358. */
  359. @serialize("alphaMode")
  360. private _alphaMode: number = Constants.ALPHA_COMBINE;
  361. /**
  362. * Sets the value of the alpha mode.
  363. *
  364. * | Value | Type | Description |
  365. * | --- | --- | --- |
  366. * | 0 | ALPHA_DISABLE | |
  367. * | 1 | ALPHA_ADD | |
  368. * | 2 | ALPHA_COMBINE | |
  369. * | 3 | ALPHA_SUBTRACT | |
  370. * | 4 | ALPHA_MULTIPLY | |
  371. * | 5 | ALPHA_MAXIMIZED | |
  372. * | 6 | ALPHA_ONEONE | |
  373. * | 7 | ALPHA_PREMULTIPLIED | |
  374. * | 8 | ALPHA_PREMULTIPLIED_PORTERDUFF | |
  375. * | 9 | ALPHA_INTERPOLATE | |
  376. * | 10 | ALPHA_SCREENMODE | |
  377. *
  378. */
  379. public set alphaMode(value: number) {
  380. if (this._alphaMode === value) {
  381. return;
  382. }
  383. this._alphaMode = value;
  384. this.markAsDirty(Material.TextureDirtyFlag);
  385. }
  386. /**
  387. * Gets the value of the alpha mode
  388. */
  389. public get alphaMode(): number {
  390. return this._alphaMode;
  391. }
  392. /**
  393. * Stores the state of the need depth pre-pass value
  394. */
  395. @serialize()
  396. private _needDepthPrePass = false;
  397. /**
  398. * Sets the need depth pre-pass value
  399. */
  400. public set needDepthPrePass(value: boolean) {
  401. if (this._needDepthPrePass === value) {
  402. return;
  403. }
  404. this._needDepthPrePass = value;
  405. if (this._needDepthPrePass) {
  406. this.checkReadyOnEveryCall = true;
  407. }
  408. }
  409. /**
  410. * Gets the depth pre-pass value
  411. */
  412. public get needDepthPrePass(): boolean {
  413. return this._needDepthPrePass;
  414. }
  415. /**
  416. * Specifies if depth writing should be disabled
  417. */
  418. @serialize()
  419. public disableDepthWrite = false;
  420. /**
  421. * Specifies if color writing should be disabled
  422. */
  423. @serialize()
  424. public disableColorWrite = false;
  425. /**
  426. * Specifies if depth writing should be forced
  427. */
  428. @serialize()
  429. public forceDepthWrite = false;
  430. /**
  431. * Specifies the depth function that should be used. 0 means the default engine function
  432. */
  433. @serialize()
  434. public depthFunction = 0;
  435. /**
  436. * Specifies if there should be a separate pass for culling
  437. */
  438. @serialize()
  439. public separateCullingPass = false;
  440. /**
  441. * Stores the state specifying if fog should be enabled
  442. */
  443. @serialize("fogEnabled")
  444. private _fogEnabled = true;
  445. /**
  446. * Sets the state for enabling fog
  447. */
  448. public set fogEnabled(value: boolean) {
  449. if (this._fogEnabled === value) {
  450. return;
  451. }
  452. this._fogEnabled = value;
  453. this.markAsDirty(Material.MiscDirtyFlag);
  454. }
  455. /**
  456. * Gets the value of the fog enabled state
  457. */
  458. public get fogEnabled(): boolean {
  459. return this._fogEnabled;
  460. }
  461. /**
  462. * Stores the size of points
  463. */
  464. @serialize()
  465. public pointSize = 1.0;
  466. /**
  467. * Stores the z offset value
  468. */
  469. @serialize()
  470. public zOffset = 0;
  471. public get wireframe(): boolean {
  472. switch (this._fillMode) {
  473. case Material.WireFrameFillMode:
  474. case Material.LineListDrawMode:
  475. case Material.LineLoopDrawMode:
  476. case Material.LineStripDrawMode:
  477. return true;
  478. }
  479. return this._scene.forceWireframe;
  480. }
  481. /**
  482. * Sets the state of wireframe mode
  483. */
  484. public set wireframe(value: boolean) {
  485. this.fillMode = (value ? Material.WireFrameFillMode : Material.TriangleFillMode);
  486. }
  487. /**
  488. * Gets the value specifying if point clouds are enabled
  489. */
  490. @serialize()
  491. public get pointsCloud(): boolean {
  492. switch (this._fillMode) {
  493. case Material.PointFillMode:
  494. case Material.PointListDrawMode:
  495. return true;
  496. }
  497. return this._scene.forcePointsCloud;
  498. }
  499. /**
  500. * Sets the state of point cloud mode
  501. */
  502. public set pointsCloud(value: boolean) {
  503. this.fillMode = (value ? Material.PointFillMode : Material.TriangleFillMode);
  504. }
  505. /**
  506. * Gets the material fill mode
  507. */
  508. @serialize()
  509. public get fillMode(): number {
  510. return this._fillMode;
  511. }
  512. /**
  513. * Sets the material fill mode
  514. */
  515. public set fillMode(value: number) {
  516. if (this._fillMode === value) {
  517. return;
  518. }
  519. this._fillMode = value;
  520. this.markAsDirty(Material.MiscDirtyFlag);
  521. }
  522. /**
  523. * @hidden
  524. * Stores the effects for the material
  525. */
  526. public _effect: Nullable<Effect> = null;
  527. /**
  528. * Specifies if uniform buffers should be used
  529. */
  530. private _useUBO: boolean = false;
  531. /**
  532. * Stores a reference to the scene
  533. */
  534. private _scene: Scene;
  535. private _needToBindSceneUbo: boolean;
  536. /**
  537. * Stores the fill mode state
  538. */
  539. private _fillMode = Material.TriangleFillMode;
  540. /**
  541. * Specifies if the depth write state should be cached
  542. */
  543. private _cachedDepthWriteState: boolean = false;
  544. /**
  545. * Specifies if the color write state should be cached
  546. */
  547. private _cachedColorWriteState: boolean = false;
  548. /**
  549. * Specifies if the depth function state should be cached
  550. */
  551. private _cachedDepthFunctionState: number = 0;
  552. /**
  553. * Stores the uniform buffer
  554. */
  555. protected _uniformBuffer: UniformBuffer;
  556. /** @hidden */
  557. public _indexInSceneMaterialArray = -1;
  558. /** @hidden */
  559. public meshMap: Nullable<{ [id: string]: AbstractMesh | undefined }> = null;
  560. /**
  561. * Creates a material instance
  562. * @param name defines the name of the material
  563. * @param scene defines the scene to reference
  564. * @param doNotAdd specifies if the material should be added to the scene
  565. */
  566. constructor(name: string, scene: Scene, doNotAdd?: boolean) {
  567. this.name = name;
  568. this._scene = scene || EngineStore.LastCreatedScene;
  569. this.id = name || Tools.RandomId();
  570. this.uniqueId = this._scene.getUniqueId();
  571. if (this._scene.useRightHandedSystem) {
  572. this.sideOrientation = Material.ClockWiseSideOrientation;
  573. } else {
  574. this.sideOrientation = Material.CounterClockWiseSideOrientation;
  575. }
  576. this._uniformBuffer = new UniformBuffer(this._scene.getEngine(), undefined, undefined, name);
  577. this._useUBO = this.getScene().getEngine().supportsUniformBuffers;
  578. if (!doNotAdd) {
  579. this._scene.addMaterial(this);
  580. }
  581. if (this._scene.useMaterialMeshMap) {
  582. this.meshMap = {};
  583. }
  584. }
  585. /**
  586. * Returns a string representation of the current material
  587. * @param fullDetails defines a boolean indicating which levels of logging is desired
  588. * @returns a string with material information
  589. */
  590. public toString(fullDetails?: boolean): string {
  591. var ret = "Name: " + this.name;
  592. if (fullDetails) {
  593. }
  594. return ret;
  595. }
  596. /**
  597. * Gets the class name of the material
  598. * @returns a string with the class name of the material
  599. */
  600. public getClassName(): string {
  601. return "Material";
  602. }
  603. /**
  604. * Specifies if updates for the material been locked
  605. */
  606. public get isFrozen(): boolean {
  607. return this.checkReadyOnlyOnce;
  608. }
  609. /**
  610. * Locks updates for the material
  611. */
  612. public freeze(): void {
  613. this.markDirty();
  614. this.checkReadyOnlyOnce = true;
  615. }
  616. /**
  617. * Unlocks updates for the material
  618. */
  619. public unfreeze(): void {
  620. this.markDirty();
  621. this.checkReadyOnlyOnce = false;
  622. }
  623. /**
  624. * Specifies if the material is ready to be used
  625. * @param mesh defines the mesh to check
  626. * @param useInstances specifies if instances should be used
  627. * @returns a boolean indicating if the material is ready to be used
  628. */
  629. public isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean {
  630. return true;
  631. }
  632. /**
  633. * Specifies that the submesh is ready to be used
  634. * @param mesh defines the mesh to check
  635. * @param subMesh defines which submesh to check
  636. * @param useInstances specifies that instances should be used
  637. * @returns a boolean indicating that the submesh is ready or not
  638. */
  639. public isReadyForSubMesh(mesh: AbstractMesh, subMesh: SubMesh, useInstances?: boolean): boolean {
  640. return false;
  641. }
  642. /**
  643. * Returns the material effect
  644. * @returns the effect associated with the material
  645. */
  646. public getEffect(): Nullable<Effect> {
  647. return this._effect;
  648. }
  649. /**
  650. * Returns the current scene
  651. * @returns a Scene
  652. */
  653. public getScene(): Scene {
  654. return this._scene;
  655. }
  656. /**
  657. * Enforces alpha test in opaque or blend mode in order to improve the performances of some situations.
  658. */
  659. protected _forceAlphaTest = false;
  660. /**
  661. * The transparency mode of the material.
  662. */
  663. protected _transparencyMode: Nullable<number> = null;
  664. /**
  665. * Gets the current transparency mode.
  666. */
  667. @serialize()
  668. public get transparencyMode(): Nullable<number> {
  669. return this._transparencyMode;
  670. }
  671. /**
  672. * Sets the transparency mode of the material.
  673. *
  674. * | Value | Type | Description |
  675. * | ----- | ----------------------------------- | ----------- |
  676. * | 0 | OPAQUE | |
  677. * | 1 | ALPHATEST | |
  678. * | 2 | ALPHABLEND | |
  679. * | 3 | ALPHATESTANDBLEND | |
  680. *
  681. */
  682. public set transparencyMode(value: Nullable<number>) {
  683. if (this._transparencyMode === value) {
  684. return;
  685. }
  686. this._transparencyMode = value;
  687. this._forceAlphaTest = (value === Material.MATERIAL_ALPHATESTANDBLEND);
  688. this._markAllSubMeshesAsTexturesAndMiscDirty();
  689. }
  690. /**
  691. * Returns true if alpha blending should be disabled.
  692. */
  693. protected get _disableAlphaBlending(): boolean {
  694. return (this._transparencyMode === Material.MATERIAL_OPAQUE ||
  695. this._transparencyMode === Material.MATERIAL_ALPHATEST);
  696. }
  697. /**
  698. * Specifies whether or not this material should be rendered in alpha blend mode.
  699. * @returns a boolean specifying if alpha blending is needed
  700. */
  701. public needAlphaBlending(): boolean {
  702. if (this._disableAlphaBlending) {
  703. return false;
  704. }
  705. return (this.alpha < 1.0);
  706. }
  707. /**
  708. * Specifies if the mesh will require alpha blending
  709. * @param mesh defines the mesh to check
  710. * @returns a boolean specifying if alpha blending is needed for the mesh
  711. */
  712. public needAlphaBlendingForMesh(mesh: AbstractMesh): boolean {
  713. if (this._disableAlphaBlending && mesh.visibility >= 1.0) {
  714. return false;
  715. }
  716. return this.needAlphaBlending() || (mesh.visibility < 1.0) || mesh.hasVertexAlpha;
  717. }
  718. /**
  719. * Specifies whether or not this material should be rendered in alpha test mode.
  720. * @returns a boolean specifying if an alpha test is needed.
  721. */
  722. public needAlphaTesting(): boolean {
  723. if (this._forceAlphaTest) {
  724. return true;
  725. }
  726. return false;
  727. }
  728. /**
  729. * Specifies if material alpha testing should be turned on for the mesh
  730. * @param mesh defines the mesh to check
  731. */
  732. protected _shouldTurnAlphaTestOn(mesh: AbstractMesh): boolean {
  733. return (!this.needAlphaBlendingForMesh(mesh) && this.needAlphaTesting());
  734. }
  735. /**
  736. * Gets the texture used for the alpha test
  737. * @returns the texture to use for alpha testing
  738. */
  739. public getAlphaTestTexture(): Nullable<BaseTexture> {
  740. return null;
  741. }
  742. /**
  743. * Marks the material to indicate that it needs to be re-calculated
  744. */
  745. public markDirty(): void {
  746. const meshes = this.getScene().meshes;
  747. for (var mesh of meshes) {
  748. if (!mesh.subMeshes) {
  749. continue;
  750. }
  751. for (var subMesh of mesh.subMeshes) {
  752. if (subMesh.getMaterial() !== this) {
  753. continue;
  754. }
  755. if (!subMesh.effect) {
  756. continue;
  757. }
  758. subMesh.effect._wasPreviouslyReady = false;
  759. }
  760. }
  761. }
  762. /** @hidden */
  763. public _preBind(effect?: Effect, overrideOrientation: Nullable<number> = null): boolean {
  764. var engine = this._scene.getEngine();
  765. var orientation = (overrideOrientation == null) ? this.sideOrientation : overrideOrientation;
  766. var reverse = orientation === Material.ClockWiseSideOrientation;
  767. engine.enableEffect(effect ? effect : this._effect);
  768. engine.setState(this.backFaceCulling, this.zOffset, false, reverse);
  769. return reverse;
  770. }
  771. /**
  772. * Binds the material to the mesh
  773. * @param world defines the world transformation matrix
  774. * @param mesh defines the mesh to bind the material to
  775. */
  776. public bind(world: Matrix, mesh?: Mesh): void {
  777. }
  778. /**
  779. * Binds the submesh to the material
  780. * @param world defines the world transformation matrix
  781. * @param mesh defines the mesh containing the submesh
  782. * @param subMesh defines the submesh to bind the material to
  783. */
  784. public bindForSubMesh(world: Matrix, mesh: Mesh, subMesh: SubMesh): void {
  785. }
  786. /**
  787. * Binds the world matrix to the material
  788. * @param world defines the world transformation matrix
  789. */
  790. public bindOnlyWorldMatrix(world: Matrix): void {
  791. }
  792. /**
  793. * Update the scene ubo before it can be used in rendering processing
  794. * @param scene the scene to retrieve the ubo from
  795. * @returns the scene UniformBuffer
  796. */
  797. public finalizeSceneUbo(scene: Scene): UniformBuffer {
  798. const ubo = scene.getSceneUniformBuffer();
  799. const eyePosition = MaterialHelper.BindEyePosition(null, scene);
  800. ubo.updateFloat4("vEyePosition",
  801. eyePosition.x,
  802. eyePosition.y,
  803. eyePosition.z,
  804. eyePosition.w);
  805. ubo.update();
  806. return ubo;
  807. }
  808. /**
  809. * Binds the scene's uniform buffer to the effect.
  810. * @param effect defines the effect to bind to the scene uniform buffer
  811. * @param sceneUbo defines the uniform buffer storing scene data
  812. */
  813. public bindSceneUniformBuffer(effect: Effect, sceneUbo: UniformBuffer): void {
  814. sceneUbo.bindToEffect(effect, "Scene");
  815. }
  816. /**
  817. * Binds the view matrix to the effect
  818. * @param effect defines the effect to bind the view matrix to
  819. */
  820. public bindView(effect: Effect): void {
  821. if (!this._useUBO) {
  822. effect.setMatrix("view", this.getScene().getViewMatrix());
  823. } else {
  824. this._needToBindSceneUbo = true;
  825. }
  826. }
  827. /**
  828. * Binds the view projection and projection matrices to the effect
  829. * @param effect defines the effect to bind the view projection and projection matrices to
  830. */
  831. public bindViewProjection(effect: Effect): void {
  832. if (!this._useUBO) {
  833. effect.setMatrix("viewProjection", this.getScene().getTransformMatrix());
  834. effect.setMatrix("projection", this.getScene().getProjectionMatrix());
  835. } else {
  836. this._needToBindSceneUbo = true;
  837. }
  838. }
  839. /**
  840. * Binds the view matrix to the effect
  841. * @param effect defines the effect to bind the view matrix to
  842. * @param variableName name of the shader variable that will hold the eye position
  843. */
  844. public bindEyePosition(effect: Effect, variableName?: string): void {
  845. if (!this._useUBO) {
  846. MaterialHelper.BindEyePosition(effect, this._scene, variableName);
  847. } else {
  848. this._needToBindSceneUbo = true;
  849. }
  850. }
  851. /**
  852. * Processes to execute after binding the material to a mesh
  853. * @param mesh defines the rendered mesh
  854. */
  855. protected _afterBind(mesh?: Mesh, effect: Nullable<Effect> = null): void {
  856. this._scene._cachedMaterial = this;
  857. if (this._needToBindSceneUbo) {
  858. if (effect) {
  859. this._needToBindSceneUbo = false;
  860. this.finalizeSceneUbo(this.getScene());
  861. this.bindSceneUniformBuffer(effect, this.getScene().getSceneUniformBuffer());
  862. }
  863. }
  864. if (mesh) {
  865. this._scene._cachedVisibility = mesh.visibility;
  866. } else {
  867. this._scene._cachedVisibility = 1;
  868. }
  869. if (this._onBindObservable && mesh) {
  870. this._onBindObservable.notifyObservers(mesh);
  871. }
  872. if (this.disableDepthWrite) {
  873. var engine = this._scene.getEngine();
  874. this._cachedDepthWriteState = engine.getDepthWrite();
  875. engine.setDepthWrite(false);
  876. }
  877. if (this.disableColorWrite) {
  878. var engine = this._scene.getEngine();
  879. this._cachedColorWriteState = engine.getColorWrite();
  880. engine.setColorWrite(false);
  881. }
  882. if (this.depthFunction !== 0) {
  883. var engine = this._scene.getEngine();
  884. this._cachedDepthFunctionState = engine.getDepthFunction() || 0;
  885. engine.setDepthFunction(this.depthFunction);
  886. }
  887. }
  888. /**
  889. * Unbinds the material from the mesh
  890. */
  891. public unbind(): void {
  892. if (this._onUnBindObservable) {
  893. this._onUnBindObservable.notifyObservers(this);
  894. }
  895. if (this.depthFunction !== 0) {
  896. var engine = this._scene.getEngine();
  897. engine.setDepthFunction(this._cachedDepthFunctionState);
  898. }
  899. if (this.disableDepthWrite) {
  900. var engine = this._scene.getEngine();
  901. engine.setDepthWrite(this._cachedDepthWriteState);
  902. }
  903. if (this.disableColorWrite) {
  904. var engine = this._scene.getEngine();
  905. engine.setColorWrite(this._cachedColorWriteState);
  906. }
  907. }
  908. /**
  909. * Gets the active textures from the material
  910. * @returns an array of textures
  911. */
  912. public getActiveTextures(): BaseTexture[] {
  913. return [];
  914. }
  915. /**
  916. * Specifies if the material uses a texture
  917. * @param texture defines the texture to check against the material
  918. * @returns a boolean specifying if the material uses the texture
  919. */
  920. public hasTexture(texture: BaseTexture): boolean {
  921. return false;
  922. }
  923. /**
  924. * Makes a duplicate of the material, and gives it a new name
  925. * @param name defines the new name for the duplicated material
  926. * @returns the cloned material
  927. */
  928. public clone(name: string): Nullable<Material> {
  929. return null;
  930. }
  931. /**
  932. * Gets the meshes bound to the material
  933. * @returns an array of meshes bound to the material
  934. */
  935. public getBindedMeshes(): AbstractMesh[] {
  936. if (this.meshMap) {
  937. var result = new Array<AbstractMesh>();
  938. for (let meshId in this.meshMap) {
  939. const mesh = this.meshMap[meshId];
  940. if (mesh) {
  941. result.push(mesh);
  942. }
  943. }
  944. return result;
  945. }
  946. else {
  947. const meshes = this._scene.meshes;
  948. return meshes.filter((mesh) => mesh.material === this);
  949. }
  950. }
  951. /**
  952. * Force shader compilation
  953. * @param mesh defines the mesh associated with this material
  954. * @param onCompiled defines a function to execute once the material is compiled
  955. * @param options defines the options to configure the compilation
  956. * @param onError defines a function to execute if the material fails compiling
  957. */
  958. public forceCompilation(mesh: AbstractMesh, onCompiled?: (material: Material) => void, options?: Partial<IMaterialCompilationOptions>, onError?: (reason: string) => void): void {
  959. let localOptions = {
  960. clipPlane: false,
  961. useInstances: false,
  962. ...options
  963. };
  964. var scene = this.getScene();
  965. let currentHotSwapingState = this.allowShaderHotSwapping;
  966. this.allowShaderHotSwapping = false; // Turned off to let us evaluate the real compilation state
  967. var checkReady = () => {
  968. if (!this._scene || !this._scene.getEngine()) {
  969. return;
  970. }
  971. var clipPlaneState = scene.clipPlane;
  972. if (localOptions.clipPlane) {
  973. scene.clipPlane = new Plane(0, 0, 0, 1);
  974. }
  975. if (this._storeEffectOnSubMeshes) {
  976. var allDone = true, lastError = null;
  977. if (mesh.subMeshes) {
  978. let tempSubMesh = new SubMesh(0, 0, 0, 0, 0, mesh, undefined, false, false);
  979. if (tempSubMesh._materialDefines) {
  980. tempSubMesh._materialDefines._renderId = -1;
  981. }
  982. if (!this.isReadyForSubMesh(mesh, tempSubMesh, localOptions.useInstances)) {
  983. if (tempSubMesh.effect && tempSubMesh.effect.getCompilationError() && tempSubMesh.effect.allFallbacksProcessed()) {
  984. lastError = tempSubMesh.effect.getCompilationError();
  985. } else {
  986. allDone = false;
  987. setTimeout(checkReady, 16);
  988. }
  989. }
  990. }
  991. if (allDone) {
  992. this.allowShaderHotSwapping = currentHotSwapingState;
  993. if (lastError) {
  994. if (onError) {
  995. onError(lastError);
  996. }
  997. }
  998. if (onCompiled) {
  999. onCompiled(this);
  1000. }
  1001. }
  1002. } else {
  1003. if (this.isReady()) {
  1004. this.allowShaderHotSwapping = currentHotSwapingState;
  1005. if (onCompiled) {
  1006. onCompiled(this);
  1007. }
  1008. }
  1009. else {
  1010. setTimeout(checkReady, 16);
  1011. }
  1012. }
  1013. if (localOptions.clipPlane) {
  1014. scene.clipPlane = clipPlaneState;
  1015. }
  1016. };
  1017. checkReady();
  1018. }
  1019. /**
  1020. * Force shader compilation
  1021. * @param mesh defines the mesh that will use this material
  1022. * @param options defines additional options for compiling the shaders
  1023. * @returns a promise that resolves when the compilation completes
  1024. */
  1025. public forceCompilationAsync(mesh: AbstractMesh, options?: Partial<IMaterialCompilationOptions>): Promise<void> {
  1026. return new Promise((resolve, reject) => {
  1027. this.forceCompilation(mesh, () => {
  1028. resolve();
  1029. }, options, (reason) => {
  1030. reject(reason);
  1031. });
  1032. });
  1033. }
  1034. private static readonly _AllDirtyCallBack = (defines: MaterialDefines) => defines.markAllAsDirty();
  1035. private static readonly _ImageProcessingDirtyCallBack = (defines: MaterialDefines) => defines.markAsImageProcessingDirty();
  1036. private static readonly _TextureDirtyCallBack = (defines: MaterialDefines) => defines.markAsTexturesDirty();
  1037. private static readonly _FresnelDirtyCallBack = (defines: MaterialDefines) => defines.markAsFresnelDirty();
  1038. private static readonly _MiscDirtyCallBack = (defines: MaterialDefines) => defines.markAsMiscDirty();
  1039. private static readonly _PrePassDirtyCallBack = (defines: MaterialDefines) => defines.markAsPrePassDirty();
  1040. private static readonly _LightsDirtyCallBack = (defines: MaterialDefines) => defines.markAsLightDirty();
  1041. private static readonly _AttributeDirtyCallBack = (defines: MaterialDefines) => defines.markAsAttributesDirty();
  1042. private static _FresnelAndMiscDirtyCallBack = (defines: MaterialDefines) => {
  1043. Material._FresnelDirtyCallBack(defines);
  1044. Material._MiscDirtyCallBack(defines);
  1045. }
  1046. private static _TextureAndMiscDirtyCallBack = (defines: MaterialDefines) => {
  1047. Material._TextureDirtyCallBack(defines);
  1048. Material._MiscDirtyCallBack(defines);
  1049. }
  1050. private static readonly _DirtyCallbackArray: Array<(defines: MaterialDefines) => void> = [];
  1051. private static readonly _RunDirtyCallBacks = (defines: MaterialDefines) => {
  1052. for (const cb of Material._DirtyCallbackArray) {
  1053. cb(defines);
  1054. }
  1055. }
  1056. /**
  1057. * Marks a define in the material to indicate that it needs to be re-computed
  1058. * @param flag defines a flag used to determine which parts of the material have to be marked as dirty
  1059. */
  1060. public markAsDirty(flag: number): void {
  1061. if (this.getScene().blockMaterialDirtyMechanism) {
  1062. return;
  1063. }
  1064. Material._DirtyCallbackArray.length = 0;
  1065. if (flag & Material.TextureDirtyFlag) {
  1066. Material._DirtyCallbackArray.push(Material._TextureDirtyCallBack);
  1067. }
  1068. if (flag & Material.LightDirtyFlag) {
  1069. Material._DirtyCallbackArray.push(Material._LightsDirtyCallBack);
  1070. }
  1071. if (flag & Material.FresnelDirtyFlag) {
  1072. Material._DirtyCallbackArray.push(Material._FresnelDirtyCallBack);
  1073. }
  1074. if (flag & Material.AttributesDirtyFlag) {
  1075. Material._DirtyCallbackArray.push(Material._AttributeDirtyCallBack);
  1076. }
  1077. if (flag & Material.MiscDirtyFlag) {
  1078. Material._DirtyCallbackArray.push(Material._MiscDirtyCallBack);
  1079. }
  1080. if (flag & Material.PrePassDirtyFlag) {
  1081. Material._DirtyCallbackArray.push(Material._PrePassDirtyCallBack);
  1082. }
  1083. if (Material._DirtyCallbackArray.length) {
  1084. this._markAllSubMeshesAsDirty(Material._RunDirtyCallBacks);
  1085. }
  1086. this.getScene().resetCachedMaterial();
  1087. }
  1088. /**
  1089. * Marks all submeshes of a material to indicate that their material defines need to be re-calculated
  1090. * @param func defines a function which checks material defines against the submeshes
  1091. */
  1092. protected _markAllSubMeshesAsDirty(func: (defines: MaterialDefines) => void) {
  1093. if (this.getScene().blockMaterialDirtyMechanism) {
  1094. return;
  1095. }
  1096. const meshes = this.getScene().meshes;
  1097. for (var mesh of meshes) {
  1098. if (!mesh.subMeshes) {
  1099. continue;
  1100. }
  1101. for (var subMesh of mesh.subMeshes) {
  1102. if (subMesh.getMaterial() !== this) {
  1103. continue;
  1104. }
  1105. if (!subMesh._materialDefines) {
  1106. continue;
  1107. }
  1108. func(subMesh._materialDefines);
  1109. }
  1110. }
  1111. }
  1112. /**
  1113. * Indicates that the scene should check if the rendering now needs a prepass
  1114. */
  1115. protected _markScenePrePassDirty() {
  1116. if (this.getScene().blockMaterialDirtyMechanism) {
  1117. return;
  1118. }
  1119. const prePassRenderer = this.getScene().enablePrePassRenderer();
  1120. if (prePassRenderer) {
  1121. prePassRenderer.markAsDirty();
  1122. }
  1123. }
  1124. /**
  1125. * Indicates that we need to re-calculated for all submeshes
  1126. */
  1127. protected _markAllSubMeshesAsAllDirty() {
  1128. this._markAllSubMeshesAsDirty(Material._AllDirtyCallBack);
  1129. }
  1130. /**
  1131. * Indicates that image processing needs to be re-calculated for all submeshes
  1132. */
  1133. protected _markAllSubMeshesAsImageProcessingDirty() {
  1134. this._markAllSubMeshesAsDirty(Material._ImageProcessingDirtyCallBack);
  1135. }
  1136. /**
  1137. * Indicates that textures need to be re-calculated for all submeshes
  1138. */
  1139. protected _markAllSubMeshesAsTexturesDirty() {
  1140. this._markAllSubMeshesAsDirty(Material._TextureDirtyCallBack);
  1141. }
  1142. /**
  1143. * Indicates that fresnel needs to be re-calculated for all submeshes
  1144. */
  1145. protected _markAllSubMeshesAsFresnelDirty() {
  1146. this._markAllSubMeshesAsDirty(Material._FresnelDirtyCallBack);
  1147. }
  1148. /**
  1149. * Indicates that fresnel and misc need to be re-calculated for all submeshes
  1150. */
  1151. protected _markAllSubMeshesAsFresnelAndMiscDirty() {
  1152. this._markAllSubMeshesAsDirty(Material._FresnelAndMiscDirtyCallBack);
  1153. }
  1154. /**
  1155. * Indicates that lights need to be re-calculated for all submeshes
  1156. */
  1157. protected _markAllSubMeshesAsLightsDirty() {
  1158. this._markAllSubMeshesAsDirty(Material._LightsDirtyCallBack);
  1159. }
  1160. /**
  1161. * Indicates that attributes need to be re-calculated for all submeshes
  1162. */
  1163. protected _markAllSubMeshesAsAttributesDirty() {
  1164. this._markAllSubMeshesAsDirty(Material._AttributeDirtyCallBack);
  1165. }
  1166. /**
  1167. * Indicates that misc needs to be re-calculated for all submeshes
  1168. */
  1169. protected _markAllSubMeshesAsMiscDirty() {
  1170. this._markAllSubMeshesAsDirty(Material._MiscDirtyCallBack);
  1171. }
  1172. /**
  1173. * Indicates that prepass needs to be re-calculated for all submeshes
  1174. */
  1175. protected _markAllSubMeshesAsPrePassDirty() {
  1176. this._markAllSubMeshesAsDirty(Material._MiscDirtyCallBack);
  1177. }
  1178. /**
  1179. * Indicates that textures and misc need to be re-calculated for all submeshes
  1180. */
  1181. protected _markAllSubMeshesAsTexturesAndMiscDirty() {
  1182. this._markAllSubMeshesAsDirty(Material._TextureAndMiscDirtyCallBack);
  1183. }
  1184. /**
  1185. * Sets the required values to the prepass renderer.
  1186. * @param prePassRenderer defines the prepass renderer to setup.
  1187. * @returns true if the pre pass is needed.
  1188. */
  1189. public setPrePassRenderer(prePassRenderer: PrePassRenderer): boolean {
  1190. // Do Nothing by default
  1191. return false;
  1192. }
  1193. /**
  1194. * Disposes the material
  1195. * @param forceDisposeEffect specifies if effects should be forcefully disposed
  1196. * @param forceDisposeTextures specifies if textures should be forcefully disposed
  1197. * @param notBoundToMesh specifies if the material that is being disposed is known to be not bound to any mesh
  1198. */
  1199. public dispose(forceDisposeEffect?: boolean, forceDisposeTextures?: boolean, notBoundToMesh?: boolean): void {
  1200. const scene = this.getScene();
  1201. // Animations
  1202. scene.stopAnimation(this);
  1203. scene.freeProcessedMaterials();
  1204. // Remove from scene
  1205. scene.removeMaterial(this);
  1206. if (notBoundToMesh !== true) {
  1207. // Remove from meshes
  1208. if (this.meshMap) {
  1209. for (let meshId in this.meshMap) {
  1210. const mesh = this.meshMap[meshId];
  1211. if (mesh) {
  1212. mesh.material = null; // will set the entry in the map to undefined
  1213. this.releaseVertexArrayObject(mesh, forceDisposeEffect);
  1214. }
  1215. }
  1216. }
  1217. else {
  1218. const meshes = scene.meshes;
  1219. for (let mesh of meshes) {
  1220. if (mesh.material === this && !(mesh as InstancedMesh).sourceMesh) {
  1221. mesh.material = null;
  1222. this.releaseVertexArrayObject(mesh, forceDisposeEffect);
  1223. }
  1224. }
  1225. }
  1226. }
  1227. this._uniformBuffer.dispose();
  1228. // Shader are kept in cache for further use but we can get rid of this by using forceDisposeEffect
  1229. if (forceDisposeEffect && this._effect) {
  1230. if (!this._storeEffectOnSubMeshes) {
  1231. this._effect.dispose();
  1232. }
  1233. this._effect = null;
  1234. }
  1235. // Callback
  1236. this.onDisposeObservable.notifyObservers(this);
  1237. this.onDisposeObservable.clear();
  1238. if (this._onBindObservable) {
  1239. this._onBindObservable.clear();
  1240. }
  1241. if (this._onUnBindObservable) {
  1242. this._onUnBindObservable.clear();
  1243. }
  1244. if (this._onEffectCreatedObservable) {
  1245. this._onEffectCreatedObservable.clear();
  1246. }
  1247. }
  1248. /** @hidden */
  1249. private releaseVertexArrayObject(mesh: AbstractMesh, forceDisposeEffect?: boolean) {
  1250. if ((<Mesh>mesh).geometry) {
  1251. var geometry = <Geometry>((<Mesh>mesh).geometry);
  1252. if (this._storeEffectOnSubMeshes) {
  1253. for (var subMesh of mesh.subMeshes) {
  1254. geometry._releaseVertexArrayObject(subMesh._materialEffect);
  1255. if (forceDisposeEffect && subMesh._materialEffect) {
  1256. subMesh._materialEffect.dispose();
  1257. }
  1258. }
  1259. } else {
  1260. geometry._releaseVertexArrayObject(this._effect);
  1261. }
  1262. }
  1263. }
  1264. /**
  1265. * Serializes this material
  1266. * @returns the serialized material object
  1267. */
  1268. public serialize(): any {
  1269. return SerializationHelper.Serialize(this);
  1270. }
  1271. /**
  1272. * Creates a material from parsed material data
  1273. * @param parsedMaterial defines parsed material data
  1274. * @param scene defines the hosting scene
  1275. * @param rootUrl defines the root URL to use to load textures
  1276. * @returns a new material
  1277. */
  1278. public static Parse(parsedMaterial: any, scene: Scene, rootUrl: string): Nullable<Material> {
  1279. if (!parsedMaterial.customType) {
  1280. parsedMaterial.customType = "BABYLON.StandardMaterial";
  1281. }
  1282. else if (parsedMaterial.customType === "BABYLON.PBRMaterial" && parsedMaterial.overloadedAlbedo) {
  1283. parsedMaterial.customType = "BABYLON.LegacyPBRMaterial";
  1284. if (!BABYLON.LegacyPBRMaterial) {
  1285. Logger.Error("Your scene is trying to load a legacy version of the PBRMaterial, please, include it from the materials library.");
  1286. return null;
  1287. }
  1288. }
  1289. var materialType = Tools.Instantiate(parsedMaterial.customType);
  1290. return materialType.Parse(parsedMaterial, scene, rootUrl);
  1291. }
  1292. }