babylon.material.ts 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849
  1. module BABYLON {
  2. export class MaterialDefines {
  3. private _keys: string[];
  4. private _isDirty = true;
  5. public _renderId: number;
  6. public _areLightsDirty = true;
  7. public _areAttributesDirty = true;
  8. public _areTexturesDirty = true;
  9. public _areFresnelDirty = true;
  10. public _areMiscDirty = true;
  11. public _areImageProcessingDirty = true;
  12. public _normals = false;
  13. public _uvs = false;
  14. public _needNormals = false;
  15. public _needUVs = false;
  16. public get isDirty(): boolean {
  17. return this._isDirty;
  18. }
  19. public markAsProcessed() {
  20. this._isDirty = false;
  21. this._areAttributesDirty = false;
  22. this._areTexturesDirty = false;
  23. this._areFresnelDirty = false;
  24. this._areLightsDirty = false;
  25. this._areMiscDirty = false;
  26. this._areImageProcessingDirty = false;
  27. }
  28. public markAsUnprocessed() {
  29. this._isDirty = true;
  30. }
  31. public markAllAsDirty() {
  32. this._areTexturesDirty = true;
  33. this._areAttributesDirty = true;
  34. this._areLightsDirty = true;
  35. this._areFresnelDirty = true;
  36. this._areMiscDirty = true;
  37. this._areImageProcessingDirty = true;
  38. this._isDirty = true;
  39. }
  40. public markAsImageProcessingDirty() {
  41. this._areImageProcessingDirty = true;
  42. this._isDirty = true;
  43. }
  44. public markAsLightDirty() {
  45. this._areLightsDirty = true;
  46. this._isDirty = true;
  47. }
  48. public markAsAttributesDirty() {
  49. this._areAttributesDirty = true;
  50. this._isDirty = true;
  51. }
  52. public markAsTexturesDirty() {
  53. this._areTexturesDirty = true;
  54. this._isDirty = true;
  55. }
  56. public markAsFresnelDirty() {
  57. this._areFresnelDirty = true;
  58. this._isDirty = true;
  59. }
  60. public markAsMiscDirty() {
  61. this._areMiscDirty = true;
  62. this._isDirty = true;
  63. }
  64. public rebuild() {
  65. if (this._keys) {
  66. delete this._keys;
  67. }
  68. this._keys = [];
  69. for (var key of Object.keys(this)) {
  70. if (key[0] === "_") {
  71. continue;
  72. }
  73. this._keys.push(key);
  74. }
  75. }
  76. public isEqual(other: MaterialDefines): boolean {
  77. if (this._keys.length !== other._keys.length) {
  78. return false;
  79. }
  80. for (var index = 0; index < this._keys.length; index++) {
  81. var prop = this._keys[index];
  82. if ((<any>this)[prop] !== (<any>other)[prop]) {
  83. return false;
  84. }
  85. }
  86. return true;
  87. }
  88. public cloneTo(other: MaterialDefines): void {
  89. if (this._keys.length !== other._keys.length) {
  90. other._keys = this._keys.slice(0);
  91. }
  92. for (var index = 0; index < this._keys.length; index++) {
  93. var prop = this._keys[index];
  94. (<any>other)[prop] = (<any>this)[prop];
  95. }
  96. }
  97. public reset(): void {
  98. for (var index = 0; index < this._keys.length; index++) {
  99. var prop = this._keys[index];
  100. if (typeof ((<any>this)[prop]) === "number") {
  101. (<any>this)[prop] = 0;
  102. } else {
  103. (<any>this)[prop] = false;
  104. }
  105. }
  106. }
  107. public toString(): string {
  108. var result = "";
  109. for (var index = 0; index < this._keys.length; index++) {
  110. var prop = this._keys[index];
  111. var value = (<any>this)[prop];
  112. if (typeof (value) === "number") {
  113. result += "#define " + prop + " " + (<any>this)[prop] + "\n";
  114. } else if (value) {
  115. result += "#define " + prop + "\n";
  116. }
  117. }
  118. return result;
  119. }
  120. }
  121. export class Material implements IAnimatable {
  122. // Triangle views
  123. private static _TriangleFillMode = 0;
  124. private static _WireFrameFillMode = 1;
  125. private static _PointFillMode = 2;
  126. // Draw modes
  127. private static _PointListDrawMode = 3;
  128. private static _LineListDrawMode = 4;
  129. private static _LineLoopDrawMode = 5;
  130. private static _LineStripDrawMode = 6;
  131. private static _TriangleStripDrawMode = 7;
  132. private static _TriangleFanDrawMode = 8;
  133. public static get TriangleFillMode(): number {
  134. return Material._TriangleFillMode;
  135. }
  136. public static get WireFrameFillMode(): number {
  137. return Material._WireFrameFillMode;
  138. }
  139. public static get PointFillMode(): number {
  140. return Material._PointFillMode;
  141. }
  142. public static get PointListDrawMode(): number {
  143. return Material._PointListDrawMode;
  144. }
  145. public static get LineListDrawMode(): number {
  146. return Material._LineListDrawMode;
  147. }
  148. public static get LineLoopDrawMode(): number {
  149. return Material._LineLoopDrawMode;
  150. }
  151. public static get LineStripDrawMode(): number {
  152. return Material._LineStripDrawMode;
  153. }
  154. public static get TriangleStripDrawMode(): number {
  155. return Material._TriangleStripDrawMode;
  156. }
  157. public static get TriangleFanDrawMode(): number {
  158. return Material._TriangleFanDrawMode;
  159. }
  160. private static _ClockWiseSideOrientation = 0;
  161. private static _CounterClockWiseSideOrientation = 1;
  162. public static get ClockWiseSideOrientation(): number {
  163. return Material._ClockWiseSideOrientation;
  164. }
  165. public static get CounterClockWiseSideOrientation(): number {
  166. return Material._CounterClockWiseSideOrientation;
  167. }
  168. private static _TextureDirtyFlag = 1;
  169. private static _LightDirtyFlag = 2;
  170. private static _FresnelDirtyFlag = 4;
  171. private static _AttributesDirtyFlag = 8;
  172. private static _MiscDirtyFlag = 16;
  173. public static get TextureDirtyFlag(): number {
  174. return Material._TextureDirtyFlag;
  175. }
  176. public static get LightDirtyFlag(): number {
  177. return Material._LightDirtyFlag;
  178. }
  179. public static get FresnelDirtyFlag(): number {
  180. return Material._FresnelDirtyFlag;
  181. }
  182. public static get AttributesDirtyFlag(): number {
  183. return Material._AttributesDirtyFlag;
  184. }
  185. public static get MiscDirtyFlag(): number {
  186. return Material._MiscDirtyFlag;
  187. }
  188. @serialize()
  189. public id: string;
  190. @serialize()
  191. public name: string;
  192. @serialize()
  193. public checkReadyOnEveryCall = false;
  194. @serialize()
  195. public checkReadyOnlyOnce = false;
  196. @serialize()
  197. public state = "";
  198. @serialize()
  199. public alpha = 1.0;
  200. @serialize("backFaceCulling")
  201. protected _backFaceCulling = true;
  202. public set backFaceCulling(value : boolean) {
  203. if (this._backFaceCulling === value) {
  204. return;
  205. }
  206. this._backFaceCulling = value;
  207. this.markAsDirty(Material.TextureDirtyFlag);
  208. }
  209. public get backFaceCulling(): boolean {
  210. return this._backFaceCulling;
  211. }
  212. @serialize()
  213. public sideOrientation: number;
  214. public onCompiled: (effect: Effect) => void;
  215. public onError: (effect: Effect, errors: string) => void;
  216. public getRenderTargetTextures: () => SmartArray<RenderTargetTexture>;
  217. public doNotSerialize = false;
  218. public storeEffectOnSubMeshes = false;
  219. public animations: Array<Animation>;
  220. /**
  221. * An event triggered when the material is disposed.
  222. * @type {BABYLON.Observable}
  223. */
  224. public onDisposeObservable = new Observable<Material>();
  225. private _onDisposeObserver: Nullable<Observer<Material>>;
  226. public set onDispose(callback: () => void) {
  227. if (this._onDisposeObserver) {
  228. this.onDisposeObservable.remove(this._onDisposeObserver);
  229. }
  230. this._onDisposeObserver = this.onDisposeObservable.add(callback);
  231. }
  232. /**
  233. * An event triggered when the material is bound.
  234. * @type {BABYLON.Observable}
  235. */
  236. public onBindObservable = new Observable<AbstractMesh>();
  237. private _onBindObserver: Nullable<Observer<AbstractMesh>>;
  238. public set onBind(callback: (Mesh: AbstractMesh) => void) {
  239. if (this._onBindObserver) {
  240. this.onBindObservable.remove(this._onBindObserver);
  241. }
  242. this._onBindObserver = this.onBindObservable.add(callback);
  243. }
  244. /**
  245. * An event triggered when the material is unbound.
  246. * @type {BABYLON.Observable}
  247. */
  248. public onUnBindObservable = new Observable<Material>();
  249. @serialize("alphaMode")
  250. private _alphaMode: number = Engine.ALPHA_COMBINE;
  251. public set alphaMode(value : number) {
  252. if (this._alphaMode === value) {
  253. return;
  254. }
  255. this._alphaMode = value;
  256. this.markAsDirty(Material.TextureDirtyFlag);
  257. }
  258. public get alphaMode(): number {
  259. return this._alphaMode;
  260. }
  261. @serialize()
  262. private _needDepthPrePass = false;
  263. public set needDepthPrePass(value : boolean) {
  264. if (this._needDepthPrePass === value) {
  265. return;
  266. }
  267. this._needDepthPrePass = value;
  268. if (this._needDepthPrePass) {
  269. this.checkReadyOnEveryCall = true;
  270. }
  271. }
  272. public get needDepthPrePass(): boolean {
  273. return this._needDepthPrePass;
  274. }
  275. @serialize()
  276. public disableDepthWrite = false;
  277. @serialize()
  278. public forceDepthWrite = false;
  279. @serialize()
  280. public separateCullingPass = false;
  281. @serialize("fogEnabled")
  282. private _fogEnabled = true;
  283. public set fogEnabled(value : boolean) {
  284. if (this._fogEnabled === value) {
  285. return;
  286. }
  287. this._fogEnabled = value;
  288. this.markAsDirty(Material.MiscDirtyFlag);
  289. }
  290. public get fogEnabled(): boolean {
  291. return this._fogEnabled;
  292. }
  293. @serialize()
  294. public pointSize = 1.0;
  295. @serialize()
  296. public zOffset = 0;
  297. @serialize()
  298. public get wireframe(): boolean {
  299. return this._fillMode === Material.WireFrameFillMode;
  300. }
  301. public set wireframe(value: boolean) {
  302. this._fillMode = (value ? Material.WireFrameFillMode : Material.TriangleFillMode);
  303. }
  304. @serialize()
  305. public get pointsCloud(): boolean {
  306. return this._fillMode === Material.PointFillMode;
  307. }
  308. public set pointsCloud(value: boolean) {
  309. this._fillMode = (value ? Material.PointFillMode : Material.TriangleFillMode);
  310. }
  311. @serialize()
  312. public get fillMode(): number {
  313. return this._fillMode;
  314. }
  315. public set fillMode(value: number) {
  316. if (this._fillMode === value) {
  317. return;
  318. }
  319. this._fillMode = value;
  320. this.markAsDirty(Material.MiscDirtyFlag);
  321. }
  322. public static fillModeToDrawType(fillMode: number): Engine.DrawType {
  323. switch (fillMode) {
  324. // Triangle views
  325. case Material.TriangleFillMode:
  326. return Engine.DrawType.TRIANGLES;
  327. case Material.PointFillMode:
  328. return Engine.DrawType.POINTS;
  329. case Material.WireFrameFillMode:
  330. return Engine.DrawType.LINES;
  331. // Draw modes
  332. case Material.PointListDrawMode:
  333. return Engine.DrawType.POINTS
  334. case Material.LineListDrawMode:
  335. return Engine.DrawType.LINES;
  336. case Material.LineLoopDrawMode:
  337. return Engine.DrawType.LINE_LOOP
  338. case Material.LineStripDrawMode:
  339. return Engine.DrawType.LINE_STRIP
  340. case Material.TriangleStripDrawMode:
  341. return Engine.DrawType.TRIANGLE_STRIP
  342. case Material.TriangleFanDrawMode:
  343. return Engine.DrawType.TRIANGLE_FAN;
  344. default:
  345. return Engine.DrawType.TRIANGLES;
  346. }
  347. }
  348. public _effect: Nullable<Effect>;
  349. public _wasPreviouslyReady = false;
  350. private _useUBO: boolean;
  351. private _scene: Scene;
  352. private _fillMode = Material.TriangleFillMode;
  353. private _cachedDepthWriteState: boolean;
  354. protected _uniformBuffer: UniformBuffer;
  355. constructor(name: string, scene: Scene, doNotAdd?: boolean) {
  356. this.name = name;
  357. this.id = name || Tools.RandomId();
  358. this._scene = scene || Engine.LastCreatedScene;
  359. if (this._scene.useRightHandedSystem) {
  360. this.sideOrientation = Material.ClockWiseSideOrientation;
  361. } else {
  362. this.sideOrientation = Material.CounterClockWiseSideOrientation;
  363. }
  364. this._uniformBuffer = new UniformBuffer(this._scene.getEngine());
  365. this._useUBO = this.getScene().getEngine().supportsUniformBuffers;
  366. if (!doNotAdd) {
  367. this._scene.materials.push(this);
  368. }
  369. }
  370. /**
  371. * @param {boolean} fullDetails - support for multiple levels of logging within scene loading
  372. * subclasses should override adding information pertainent to themselves
  373. */
  374. public toString(fullDetails? : boolean) : string {
  375. var ret = "Name: " + this.name;
  376. if (fullDetails){
  377. }
  378. return ret;
  379. }
  380. /**
  381. * Child classes can use it to update shaders
  382. */
  383. public getClassName(): string {
  384. return "Material";
  385. }
  386. public get isFrozen(): boolean {
  387. return this.checkReadyOnlyOnce;
  388. }
  389. public freeze(): void {
  390. this.checkReadyOnlyOnce = true;
  391. }
  392. public unfreeze(): void {
  393. this.checkReadyOnlyOnce = false;
  394. }
  395. public isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean {
  396. return true;
  397. }
  398. public isReadyForSubMesh(mesh: AbstractMesh, subMesh: BaseSubMesh, useInstances?: boolean): boolean {
  399. return false;
  400. }
  401. public getEffect(): Nullable<Effect> {
  402. return this._effect;
  403. }
  404. public getScene(): Scene {
  405. return this._scene;
  406. }
  407. public needAlphaBlending(): boolean {
  408. return (this.alpha < 1.0);
  409. }
  410. public needAlphaBlendingForMesh(mesh: AbstractMesh): boolean {
  411. return this.needAlphaBlending() || (mesh.visibility < 1.0) || mesh.hasVertexAlpha;
  412. }
  413. public needAlphaTesting(): boolean {
  414. return false;
  415. }
  416. public getAlphaTestTexture(): Nullable<BaseTexture> {
  417. return null;
  418. }
  419. public markDirty(): void {
  420. this._wasPreviouslyReady = false;
  421. }
  422. public _preBind(effect?: Effect, overrideOrientation : Nullable<number> = null): boolean {
  423. var engine = this._scene.getEngine();
  424. var orientation = (overrideOrientation == null) ? this.sideOrientation : overrideOrientation;
  425. var reverse = orientation === Material.ClockWiseSideOrientation;
  426. engine.enableEffect(effect ? effect : this._effect);
  427. engine.setState(this.backFaceCulling, this.zOffset, false, reverse);
  428. return reverse;
  429. }
  430. public bind(world: Matrix, mesh?: Mesh): void {
  431. }
  432. public bindForSubMesh(world: Matrix, mesh: Mesh, subMesh: SubMesh): void {
  433. }
  434. public bindOnlyWorldMatrix(world: Matrix): void {
  435. }
  436. public bindSceneUniformBuffer(effect: Effect, sceneUbo: UniformBuffer): void {
  437. sceneUbo.bindToEffect(effect, "Scene");
  438. }
  439. public bindView(effect: Effect): void {
  440. if (!this._useUBO) {
  441. effect.setMatrix("view", this.getScene().getViewMatrix());
  442. } else {
  443. this.bindSceneUniformBuffer(effect, this.getScene().getSceneUniformBuffer());
  444. }
  445. }
  446. public bindViewProjection(effect: Effect): void {
  447. if (!this._useUBO) {
  448. effect.setMatrix("viewProjection", this.getScene().getTransformMatrix());
  449. } else {
  450. this.bindSceneUniformBuffer(effect, this.getScene().getSceneUniformBuffer());
  451. }
  452. }
  453. protected _afterBind(mesh?: Mesh): void {
  454. this._scene._cachedMaterial = this;
  455. if (mesh) {
  456. this._scene._cachedVisibility = mesh.visibility;
  457. } else {
  458. this._scene._cachedVisibility = 1;
  459. }
  460. if (mesh) {
  461. this.onBindObservable.notifyObservers(mesh);
  462. }
  463. if (this.disableDepthWrite) {
  464. var engine = this._scene.getEngine();
  465. this._cachedDepthWriteState = engine.getDepthWrite();
  466. engine.setDepthWrite(false);
  467. }
  468. }
  469. public unbind(): void {
  470. this.onUnBindObservable.notifyObservers(this);
  471. if (this.disableDepthWrite) {
  472. var engine = this._scene.getEngine();
  473. engine.setDepthWrite(this._cachedDepthWriteState);
  474. }
  475. }
  476. public getActiveTextures(): BaseTexture[] {
  477. return [];
  478. }
  479. public hasTexture(texture: BaseTexture): boolean {
  480. return false;
  481. }
  482. public clone(name: string): Nullable<Material> {
  483. return null;
  484. }
  485. public getBindedMeshes(): AbstractMesh[] {
  486. var result = new Array<AbstractMesh>();
  487. for (var index = 0; index < this._scene.meshes.length; index++) {
  488. var mesh = this._scene.meshes[index];
  489. if (mesh.material === this) {
  490. result.push(mesh);
  491. }
  492. }
  493. return result;
  494. }
  495. /**
  496. * Force shader compilation including textures ready check
  497. */
  498. public forceCompilation(mesh: AbstractMesh, onCompiled?: (material: Material) => void, options?: Partial<{ alphaTest: Nullable<boolean>, clipPlane: boolean }>): void {
  499. let localOptions = {
  500. alphaTest: null,
  501. clipPlane: false,
  502. ...options
  503. };
  504. var subMesh = new BaseSubMesh();
  505. var scene = this.getScene();
  506. var engine = scene.getEngine();
  507. var checkReady = () => {
  508. if (!this._scene || !this._scene.getEngine()) {
  509. return;
  510. }
  511. if (subMesh._materialDefines) {
  512. subMesh._materialDefines._renderId = -1;
  513. }
  514. var alphaTestState = engine.getAlphaTesting();
  515. var clipPlaneState = scene.clipPlane;
  516. engine.setAlphaTesting(localOptions.alphaTest || (!this.needAlphaBlendingForMesh(mesh) && this.needAlphaTesting()));
  517. if (localOptions.clipPlane) {
  518. scene.clipPlane = new Plane(0, 0, 0, 1);
  519. }
  520. if (this.storeEffectOnSubMeshes) {
  521. if (this.isReadyForSubMesh(mesh, subMesh)) {
  522. if (onCompiled) {
  523. onCompiled(this);
  524. }
  525. }
  526. else {
  527. setTimeout(checkReady, 16);
  528. }
  529. } else {
  530. if (this.isReady(mesh)) {
  531. if (onCompiled) {
  532. onCompiled(this);
  533. }
  534. }
  535. else {
  536. setTimeout(checkReady, 16);
  537. }
  538. }
  539. engine.setAlphaTesting(alphaTestState);
  540. if (options && options.clipPlane) {
  541. scene.clipPlane = clipPlaneState;
  542. }
  543. };
  544. checkReady();
  545. }
  546. public markAsDirty(flag: number): void {
  547. if (flag & Material.TextureDirtyFlag) {
  548. this._markAllSubMeshesAsTexturesDirty();
  549. }
  550. if (flag & Material.LightDirtyFlag) {
  551. this._markAllSubMeshesAsLightsDirty();
  552. }
  553. if (flag & Material.FresnelDirtyFlag) {
  554. this._markAllSubMeshesAsFresnelDirty();
  555. }
  556. if (flag & Material.AttributesDirtyFlag) {
  557. this._markAllSubMeshesAsAttributesDirty();
  558. }
  559. if (flag & Material.MiscDirtyFlag) {
  560. this._markAllSubMeshesAsMiscDirty();
  561. }
  562. this.getScene().resetCachedMaterial();
  563. }
  564. protected _markAllSubMeshesAsDirty(func: (defines: MaterialDefines) => void) {
  565. for (var mesh of this.getScene().meshes) {
  566. if (!mesh.subMeshes) {
  567. continue;
  568. }
  569. for (var subMesh of mesh.subMeshes) {
  570. if (subMesh.getMaterial() !== this) {
  571. continue;
  572. }
  573. if (!subMesh._materialDefines) {
  574. continue;
  575. }
  576. func(subMesh._materialDefines);
  577. }
  578. }
  579. }
  580. protected _markAllSubMeshesAsImageProcessingDirty() {
  581. this._markAllSubMeshesAsDirty(defines => defines.markAsImageProcessingDirty());
  582. }
  583. protected _markAllSubMeshesAsTexturesDirty() {
  584. this._markAllSubMeshesAsDirty(defines => defines.markAsTexturesDirty());
  585. }
  586. protected _markAllSubMeshesAsFresnelDirty() {
  587. this._markAllSubMeshesAsDirty(defines => defines.markAsFresnelDirty());
  588. }
  589. protected _markAllSubMeshesAsLightsDirty() {
  590. this._markAllSubMeshesAsDirty(defines => defines.markAsLightDirty());
  591. }
  592. protected _markAllSubMeshesAsAttributesDirty() {
  593. this._markAllSubMeshesAsDirty(defines => defines.markAsAttributesDirty());
  594. }
  595. protected _markAllSubMeshesAsMiscDirty() {
  596. this._markAllSubMeshesAsDirty(defines => defines.markAsMiscDirty());
  597. }
  598. public dispose(forceDisposeEffect?: boolean, forceDisposeTextures?: boolean): void {
  599. // Animations
  600. this.getScene().stopAnimation(this);
  601. // Remove from scene
  602. var index = this._scene.materials.indexOf(this);
  603. if (index >= 0) {
  604. this._scene.materials.splice(index, 1);
  605. }
  606. // Remove from meshes
  607. for (index = 0; index < this._scene.meshes.length; index++) {
  608. var mesh = this._scene.meshes[index];
  609. if (mesh.material === this) {
  610. mesh.material = null;
  611. if ((<Mesh>mesh).geometry) {
  612. var geometry = <Geometry>((<Mesh>mesh).geometry);
  613. if (this.storeEffectOnSubMeshes) {
  614. for (var subMesh of mesh.subMeshes) {
  615. geometry._releaseVertexArrayObject(subMesh._materialEffect);
  616. if (forceDisposeEffect && subMesh._materialEffect) {
  617. this._scene.getEngine()._releaseEffect(subMesh._materialEffect);
  618. }
  619. }
  620. } else {
  621. geometry._releaseVertexArrayObject(this._effect)
  622. }
  623. }
  624. }
  625. }
  626. this._uniformBuffer.dispose();
  627. // Shader are kept in cache for further use but we can get rid of this by using forceDisposeEffect
  628. if (forceDisposeEffect && this._effect) {
  629. if (!this.storeEffectOnSubMeshes) {
  630. this._scene.getEngine()._releaseEffect(this._effect);
  631. }
  632. this._effect = null;
  633. }
  634. // Callback
  635. this.onDisposeObservable.notifyObservers(this);
  636. this.onDisposeObservable.clear();
  637. this.onBindObservable.clear();
  638. this.onUnBindObservable.clear();
  639. }
  640. public serialize(): any {
  641. return SerializationHelper.Serialize(this);
  642. }
  643. public static ParseMultiMaterial(parsedMultiMaterial: any, scene: Scene): MultiMaterial {
  644. var multiMaterial = new BABYLON.MultiMaterial(parsedMultiMaterial.name, scene);
  645. multiMaterial.id = parsedMultiMaterial.id;
  646. if (Tags) {
  647. Tags.AddTagsTo(multiMaterial, parsedMultiMaterial.tags);
  648. }
  649. for (var matIndex = 0; matIndex < parsedMultiMaterial.materials.length; matIndex++) {
  650. var subMatId = parsedMultiMaterial.materials[matIndex];
  651. if (subMatId) {
  652. multiMaterial.subMaterials.push(scene.getMaterialByID(subMatId));
  653. } else {
  654. multiMaterial.subMaterials.push(null);
  655. }
  656. }
  657. return multiMaterial;
  658. }
  659. public static Parse(parsedMaterial: any, scene: Scene, rootUrl: string) {
  660. if (!parsedMaterial.customType) {
  661. return StandardMaterial.Parse(parsedMaterial, scene, rootUrl);
  662. }
  663. if (parsedMaterial.customType === "BABYLON.PBRMaterial" && parsedMaterial.overloadedAlbedo) {
  664. parsedMaterial.customType = "BABYLON.LegacyPBRMaterial";
  665. if (!(<any>BABYLON).LegacyPBRMaterial) {
  666. BABYLON.Tools.Error("Your scene is trying to load a legacy version of the PBRMaterial, please, include it from the materials library.");
  667. return;
  668. }
  669. }
  670. var materialType = Tools.Instantiate(parsedMaterial.customType);
  671. return materialType.Parse(parsedMaterial, scene, rootUrl);;
  672. }
  673. }
  674. }