babylon.material.ts 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790
  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. private static _TriangleFillMode = 0;
  123. private static _WireFrameFillMode = 1;
  124. private static _PointFillMode = 2;
  125. public static get TriangleFillMode(): number {
  126. return Material._TriangleFillMode;
  127. }
  128. public static get WireFrameFillMode(): number {
  129. return Material._WireFrameFillMode;
  130. }
  131. public static get PointFillMode(): number {
  132. return Material._PointFillMode;
  133. }
  134. private static _ClockWiseSideOrientation = 0;
  135. private static _CounterClockWiseSideOrientation = 1;
  136. public static get ClockWiseSideOrientation(): number {
  137. return Material._ClockWiseSideOrientation;
  138. }
  139. public static get CounterClockWiseSideOrientation(): number {
  140. return Material._CounterClockWiseSideOrientation;
  141. }
  142. private static _TextureDirtyFlag = 1;
  143. private static _LightDirtyFlag = 2;
  144. private static _FresnelDirtyFlag = 4;
  145. private static _AttributesDirtyFlag = 8;
  146. private static _MiscDirtyFlag = 16;
  147. public static get TextureDirtyFlag(): number {
  148. return Material._TextureDirtyFlag;
  149. }
  150. public static get LightDirtyFlag(): number {
  151. return Material._LightDirtyFlag;
  152. }
  153. public static get FresnelDirtyFlag(): number {
  154. return Material._FresnelDirtyFlag;
  155. }
  156. public static get AttributesDirtyFlag(): number {
  157. return Material._AttributesDirtyFlag;
  158. }
  159. public static get MiscDirtyFlag(): number {
  160. return Material._MiscDirtyFlag;
  161. }
  162. @serialize()
  163. public id: string;
  164. @serialize()
  165. public name: string;
  166. @serialize()
  167. public checkReadyOnEveryCall = false;
  168. @serialize()
  169. public checkReadyOnlyOnce = false;
  170. @serialize()
  171. public state = "";
  172. @serialize()
  173. public alpha = 1.0;
  174. @serialize("backFaceCulling")
  175. protected _backFaceCulling = true;
  176. public set backFaceCulling(value : boolean) {
  177. if (this._backFaceCulling === value) {
  178. return;
  179. }
  180. this._backFaceCulling = value;
  181. this.markAsDirty(Material.TextureDirtyFlag);
  182. }
  183. public get backFaceCulling(): boolean {
  184. return this._backFaceCulling;
  185. }
  186. @serialize()
  187. public sideOrientation: number;
  188. public onCompiled: (effect: Effect) => void;
  189. public onError: (effect: Effect, errors: string) => void;
  190. public getRenderTargetTextures: () => SmartArray<RenderTargetTexture>;
  191. public doNotSerialize = false;
  192. public storeEffectOnSubMeshes = false;
  193. public animations: Array<Animation>;
  194. /**
  195. * An event triggered when the material is disposed.
  196. * @type {BABYLON.Observable}
  197. */
  198. public onDisposeObservable = new Observable<Material>();
  199. private _onDisposeObserver: Nullable<Observer<Material>>;
  200. public set onDispose(callback: () => void) {
  201. if (this._onDisposeObserver) {
  202. this.onDisposeObservable.remove(this._onDisposeObserver);
  203. }
  204. this._onDisposeObserver = this.onDisposeObservable.add(callback);
  205. }
  206. /**
  207. * An event triggered when the material is bound.
  208. * @type {BABYLON.Observable}
  209. */
  210. public onBindObservable = new Observable<AbstractMesh>();
  211. private _onBindObserver: Nullable<Observer<AbstractMesh>>;
  212. public set onBind(callback: (Mesh: AbstractMesh) => void) {
  213. if (this._onBindObserver) {
  214. this.onBindObservable.remove(this._onBindObserver);
  215. }
  216. this._onBindObserver = this.onBindObservable.add(callback);
  217. }
  218. /**
  219. * An event triggered when the material is unbound.
  220. * @type {BABYLON.Observable}
  221. */
  222. public onUnBindObservable = new Observable<Material>();
  223. @serialize("alphaMode")
  224. private _alphaMode: number = Engine.ALPHA_COMBINE;
  225. public set alphaMode(value : number) {
  226. if (this._alphaMode === value) {
  227. return;
  228. }
  229. this._alphaMode = value;
  230. this.markAsDirty(Material.TextureDirtyFlag);
  231. }
  232. public get alphaMode(): number {
  233. return this._alphaMode;
  234. }
  235. @serialize()
  236. private _needDepthPrePass = false;
  237. public set needDepthPrePass(value : boolean) {
  238. if (this._needDepthPrePass === value) {
  239. return;
  240. }
  241. this._needDepthPrePass = value;
  242. if (this._needDepthPrePass) {
  243. this.checkReadyOnEveryCall = true;
  244. }
  245. }
  246. public get needDepthPrePass(): boolean {
  247. return this._needDepthPrePass;
  248. }
  249. @serialize()
  250. public disableDepthWrite = false;
  251. @serialize()
  252. public forceDepthWrite = false;
  253. @serialize()
  254. public separateCullingPass = false;
  255. @serialize("fogEnabled")
  256. private _fogEnabled = true;
  257. public set fogEnabled(value : boolean) {
  258. if (this._fogEnabled === value) {
  259. return;
  260. }
  261. this._fogEnabled = value;
  262. this.markAsDirty(Material.MiscDirtyFlag);
  263. }
  264. public get fogEnabled(): boolean {
  265. return this._fogEnabled;
  266. }
  267. @serialize()
  268. public pointSize = 1.0;
  269. @serialize()
  270. public zOffset = 0;
  271. @serialize()
  272. public get wireframe(): boolean {
  273. return this._fillMode === Material.WireFrameFillMode;
  274. }
  275. public set wireframe(value: boolean) {
  276. this._fillMode = (value ? Material.WireFrameFillMode : Material.TriangleFillMode);
  277. }
  278. @serialize()
  279. public get pointsCloud(): boolean {
  280. return this._fillMode === Material.PointFillMode;
  281. }
  282. public set pointsCloud(value: boolean) {
  283. this._fillMode = (value ? Material.PointFillMode : Material.TriangleFillMode);
  284. }
  285. @serialize()
  286. public get fillMode(): number {
  287. return this._fillMode;
  288. }
  289. public set fillMode(value: number) {
  290. if (this._fillMode === value) {
  291. return;
  292. }
  293. this._fillMode = value;
  294. this.markAsDirty(Material.MiscDirtyFlag);
  295. }
  296. public _effect: Nullable<Effect>;
  297. public _wasPreviouslyReady = false;
  298. private _useUBO: boolean;
  299. private _scene: Scene;
  300. private _fillMode = Material.TriangleFillMode;
  301. private _cachedDepthWriteState: boolean;
  302. protected _uniformBuffer: UniformBuffer;
  303. constructor(name: string, scene: Scene, doNotAdd?: boolean) {
  304. this.name = name;
  305. this.id = name || Tools.RandomId();
  306. this._scene = scene || Engine.LastCreatedScene;
  307. if (this._scene.useRightHandedSystem) {
  308. this.sideOrientation = Material.ClockWiseSideOrientation;
  309. } else {
  310. this.sideOrientation = Material.CounterClockWiseSideOrientation;
  311. }
  312. this._uniformBuffer = new UniformBuffer(this._scene.getEngine());
  313. this._useUBO = this.getScene().getEngine().supportsUniformBuffers;
  314. if (!doNotAdd) {
  315. this._scene.materials.push(this);
  316. }
  317. }
  318. /**
  319. * @param {boolean} fullDetails - support for multiple levels of logging within scene loading
  320. * subclasses should override adding information pertainent to themselves
  321. */
  322. public toString(fullDetails? : boolean) : string {
  323. var ret = "Name: " + this.name;
  324. if (fullDetails){
  325. }
  326. return ret;
  327. }
  328. /**
  329. * Child classes can use it to update shaders
  330. */
  331. public getClassName(): string {
  332. return "Material";
  333. }
  334. public get isFrozen(): boolean {
  335. return this.checkReadyOnlyOnce;
  336. }
  337. public freeze(): void {
  338. this.checkReadyOnlyOnce = true;
  339. }
  340. public unfreeze(): void {
  341. this.checkReadyOnlyOnce = false;
  342. }
  343. public isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean {
  344. return true;
  345. }
  346. public isReadyForSubMesh(mesh: AbstractMesh, subMesh: BaseSubMesh, useInstances?: boolean): boolean {
  347. return false;
  348. }
  349. public getEffect(): Nullable<Effect> {
  350. return this._effect;
  351. }
  352. public getScene(): Scene {
  353. return this._scene;
  354. }
  355. public needAlphaBlending(): boolean {
  356. return (this.alpha < 1.0);
  357. }
  358. public needAlphaBlendingForMesh(mesh: AbstractMesh): boolean {
  359. return this.needAlphaBlending() || (mesh.visibility < 1.0) || mesh.hasVertexAlpha;
  360. }
  361. public needAlphaTesting(): boolean {
  362. return false;
  363. }
  364. public getAlphaTestTexture(): Nullable<BaseTexture> {
  365. return null;
  366. }
  367. public markDirty(): void {
  368. this._wasPreviouslyReady = false;
  369. }
  370. public _preBind(effect?: Effect, overrideOrientation : Nullable<number> = null): boolean {
  371. var engine = this._scene.getEngine();
  372. var orientation = (overrideOrientation == null) ? this.sideOrientation : overrideOrientation;
  373. var reverse = orientation === Material.ClockWiseSideOrientation;
  374. engine.enableEffect(effect ? effect : this._effect);
  375. engine.setState(this.backFaceCulling, this.zOffset, false, reverse);
  376. return reverse;
  377. }
  378. public bind(world: Matrix, mesh?: Mesh): void {
  379. }
  380. public bindForSubMesh(world: Matrix, mesh: Mesh, subMesh: SubMesh): void {
  381. }
  382. public bindOnlyWorldMatrix(world: Matrix): void {
  383. }
  384. public bindSceneUniformBuffer(effect: Effect, sceneUbo: UniformBuffer): void {
  385. sceneUbo.bindToEffect(effect, "Scene");
  386. }
  387. public bindView(effect: Effect): void {
  388. if (!this._useUBO) {
  389. effect.setMatrix("view", this.getScene().getViewMatrix());
  390. } else {
  391. this.bindSceneUniformBuffer(effect, this.getScene().getSceneUniformBuffer());
  392. }
  393. }
  394. public bindViewProjection(effect: Effect): void {
  395. if (!this._useUBO) {
  396. effect.setMatrix("viewProjection", this.getScene().getTransformMatrix());
  397. } else {
  398. this.bindSceneUniformBuffer(effect, this.getScene().getSceneUniformBuffer());
  399. }
  400. }
  401. protected _afterBind(mesh?: Mesh): void {
  402. this._scene._cachedMaterial = this;
  403. if (mesh) {
  404. this._scene._cachedVisibility = mesh.visibility;
  405. } else {
  406. this._scene._cachedVisibility = 1;
  407. }
  408. if (mesh) {
  409. this.onBindObservable.notifyObservers(mesh);
  410. }
  411. if (this.disableDepthWrite) {
  412. var engine = this._scene.getEngine();
  413. this._cachedDepthWriteState = engine.getDepthWrite();
  414. engine.setDepthWrite(false);
  415. }
  416. }
  417. public unbind(): void {
  418. this.onUnBindObservable.notifyObservers(this);
  419. if (this.disableDepthWrite) {
  420. var engine = this._scene.getEngine();
  421. engine.setDepthWrite(this._cachedDepthWriteState);
  422. }
  423. }
  424. public getActiveTextures(): BaseTexture[] {
  425. return [];
  426. }
  427. public hasTexture(texture: BaseTexture): boolean {
  428. return false;
  429. }
  430. public clone(name: string): Nullable<Material> {
  431. return null;
  432. }
  433. public getBindedMeshes(): AbstractMesh[] {
  434. var result = new Array<AbstractMesh>();
  435. for (var index = 0; index < this._scene.meshes.length; index++) {
  436. var mesh = this._scene.meshes[index];
  437. if (mesh.material === this) {
  438. result.push(mesh);
  439. }
  440. }
  441. return result;
  442. }
  443. /**
  444. * Force shader compilation including textures ready check
  445. */
  446. public forceCompilation(mesh: AbstractMesh, onCompiled?: (material: Material) => void, options?: Partial<{ alphaTest: Nullable<boolean>, clipPlane: boolean }>): void {
  447. let localOptions = {
  448. alphaTest: null,
  449. clipPlane: false,
  450. ...options
  451. };
  452. var subMesh = new BaseSubMesh();
  453. var scene = this.getScene();
  454. var engine = scene.getEngine();
  455. var checkReady = () => {
  456. if (!this._scene || !this._scene.getEngine()) {
  457. return;
  458. }
  459. if (subMesh._materialDefines) {
  460. subMesh._materialDefines._renderId = -1;
  461. }
  462. var alphaTestState = engine.getAlphaTesting();
  463. var clipPlaneState = scene.clipPlane;
  464. engine.setAlphaTesting(localOptions.alphaTest || (!this.needAlphaBlendingForMesh(mesh) && this.needAlphaTesting()));
  465. if (localOptions.clipPlane) {
  466. scene.clipPlane = new Plane(0, 0, 0, 1);
  467. }
  468. if (this.storeEffectOnSubMeshes) {
  469. if (this.isReadyForSubMesh(mesh, subMesh)) {
  470. if (onCompiled) {
  471. onCompiled(this);
  472. }
  473. }
  474. else {
  475. setTimeout(checkReady, 16);
  476. }
  477. } else {
  478. if (this.isReady(mesh)) {
  479. if (onCompiled) {
  480. onCompiled(this);
  481. }
  482. }
  483. else {
  484. setTimeout(checkReady, 16);
  485. }
  486. }
  487. engine.setAlphaTesting(alphaTestState);
  488. if (options && options.clipPlane) {
  489. scene.clipPlane = clipPlaneState;
  490. }
  491. };
  492. checkReady();
  493. }
  494. public markAsDirty(flag: number): void {
  495. if (flag & Material.TextureDirtyFlag) {
  496. this._markAllSubMeshesAsTexturesDirty();
  497. }
  498. if (flag & Material.LightDirtyFlag) {
  499. this._markAllSubMeshesAsLightsDirty();
  500. }
  501. if (flag & Material.FresnelDirtyFlag) {
  502. this._markAllSubMeshesAsFresnelDirty();
  503. }
  504. if (flag & Material.AttributesDirtyFlag) {
  505. this._markAllSubMeshesAsAttributesDirty();
  506. }
  507. if (flag & Material.MiscDirtyFlag) {
  508. this._markAllSubMeshesAsMiscDirty();
  509. }
  510. this.getScene().resetCachedMaterial();
  511. }
  512. protected _markAllSubMeshesAsDirty(func: (defines: MaterialDefines) => void) {
  513. for (var mesh of this.getScene().meshes) {
  514. if (!mesh.subMeshes) {
  515. continue;
  516. }
  517. for (var subMesh of mesh.subMeshes) {
  518. if (subMesh.getMaterial() !== this) {
  519. continue;
  520. }
  521. if (!subMesh._materialDefines) {
  522. continue;
  523. }
  524. func(subMesh._materialDefines);
  525. }
  526. }
  527. }
  528. protected _markAllSubMeshesAsImageProcessingDirty() {
  529. this._markAllSubMeshesAsDirty(defines => defines.markAsImageProcessingDirty());
  530. }
  531. protected _markAllSubMeshesAsTexturesDirty() {
  532. this._markAllSubMeshesAsDirty(defines => defines.markAsTexturesDirty());
  533. }
  534. protected _markAllSubMeshesAsFresnelDirty() {
  535. this._markAllSubMeshesAsDirty(defines => defines.markAsFresnelDirty());
  536. }
  537. protected _markAllSubMeshesAsLightsDirty() {
  538. this._markAllSubMeshesAsDirty(defines => defines.markAsLightDirty());
  539. }
  540. protected _markAllSubMeshesAsAttributesDirty() {
  541. this._markAllSubMeshesAsDirty(defines => defines.markAsAttributesDirty());
  542. }
  543. protected _markAllSubMeshesAsMiscDirty() {
  544. this._markAllSubMeshesAsDirty(defines => defines.markAsMiscDirty());
  545. }
  546. public dispose(forceDisposeEffect?: boolean, forceDisposeTextures?: boolean): void {
  547. // Animations
  548. this.getScene().stopAnimation(this);
  549. // Remove from scene
  550. var index = this._scene.materials.indexOf(this);
  551. if (index >= 0) {
  552. this._scene.materials.splice(index, 1);
  553. }
  554. // Remove from meshes
  555. for (index = 0; index < this._scene.meshes.length; index++) {
  556. var mesh = this._scene.meshes[index];
  557. if (mesh.material === this) {
  558. mesh.material = null;
  559. if ((<Mesh>mesh).geometry) {
  560. var geometry = <Geometry>((<Mesh>mesh).geometry);
  561. if (this.storeEffectOnSubMeshes) {
  562. for (var subMesh of mesh.subMeshes) {
  563. geometry._releaseVertexArrayObject(subMesh._materialEffect);
  564. if (forceDisposeEffect && subMesh._materialEffect) {
  565. this._scene.getEngine()._releaseEffect(subMesh._materialEffect);
  566. }
  567. }
  568. } else {
  569. geometry._releaseVertexArrayObject(this._effect)
  570. }
  571. }
  572. }
  573. }
  574. this._uniformBuffer.dispose();
  575. // Shader are kept in cache for further use but we can get rid of this by using forceDisposeEffect
  576. if (forceDisposeEffect && this._effect) {
  577. if (!this.storeEffectOnSubMeshes) {
  578. this._scene.getEngine()._releaseEffect(this._effect);
  579. }
  580. this._effect = null;
  581. }
  582. // Callback
  583. this.onDisposeObservable.notifyObservers(this);
  584. this.onDisposeObservable.clear();
  585. this.onBindObservable.clear();
  586. this.onUnBindObservable.clear();
  587. }
  588. public serialize(): any {
  589. return SerializationHelper.Serialize(this);
  590. }
  591. public static ParseMultiMaterial(parsedMultiMaterial: any, scene: Scene): MultiMaterial {
  592. var multiMaterial = new BABYLON.MultiMaterial(parsedMultiMaterial.name, scene);
  593. multiMaterial.id = parsedMultiMaterial.id;
  594. if (Tags) {
  595. Tags.AddTagsTo(multiMaterial, parsedMultiMaterial.tags);
  596. }
  597. for (var matIndex = 0; matIndex < parsedMultiMaterial.materials.length; matIndex++) {
  598. var subMatId = parsedMultiMaterial.materials[matIndex];
  599. if (subMatId) {
  600. multiMaterial.subMaterials.push(scene.getMaterialByID(subMatId));
  601. } else {
  602. multiMaterial.subMaterials.push(null);
  603. }
  604. }
  605. return multiMaterial;
  606. }
  607. public static Parse(parsedMaterial: any, scene: Scene, rootUrl: string) {
  608. if (!parsedMaterial.customType) {
  609. return StandardMaterial.Parse(parsedMaterial, scene, rootUrl);
  610. }
  611. if (parsedMaterial.customType === "BABYLON.PBRMaterial" && parsedMaterial.overloadedAlbedo) {
  612. parsedMaterial.customType = "BABYLON.LegacyPBRMaterial";
  613. if (!(<any>BABYLON).LegacyPBRMaterial) {
  614. BABYLON.Tools.Error("Your scene is trying to load a legacy version of the PBRMaterial, please, include it from the materials library.");
  615. return;
  616. }
  617. }
  618. var materialType = Tools.Instantiate(parsedMaterial.customType);
  619. return materialType.Parse(parsedMaterial, scene, rootUrl);;
  620. }
  621. }
  622. }