Skip to content

Commit b9382ac

Browse files
author
Mike Bond
committed
Finish glTFLoader dynamic material load
1 parent 48b9e4d commit b9382ac

File tree

7 files changed

+217
-101
lines changed

7 files changed

+217
-101
lines changed

packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_sheen.ts

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import type { Nullable } from "core/types";
2-
import { PBRMaterial } from "core/Materials/PBR/pbrMaterial";
2+
import type { PBRMaterial } from "core/Materials/PBR/pbrMaterial";
3+
import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial";
34
import type { Material } from "core/Materials/material";
5+
import type { BaseTexture } from "core/Materials/Textures/baseTexture";
46

57
import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces";
68
import type { IGLTFLoaderExtension } from "../glTFLoaderExtension";
@@ -22,6 +24,8 @@ declare module "../../glTFFileLoader" {
2224
}
2325
}
2426

27+
let PBRMaterialClass: typeof PBRMaterial | typeof OpenPBRMaterial;
28+
2529
/**
2630
* [Specification](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_sheen/README.md)
2731
* [Playground Sample](https://www.babylonjs-playground.com/frame.html#BNIZX6#4)
@@ -62,63 +66,78 @@ export class KHR_materials_sheen implements IGLTFLoaderExtension {
6266
* @internal
6367
*/
6468
// eslint-disable-next-line no-restricted-syntax
65-
public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): Nullable<Promise<void>> {
69+
public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, useOpenPBR: boolean = false): Nullable<Promise<void>> {
6670
return GLTFLoader.LoadExtensionAsync<IKHRMaterialsSheen>(context, material, this.name, async (extensionContext, extension) => {
71+
if (useOpenPBR) {
72+
const mod = await import("core/Materials/PBR/openPbrMaterial");
73+
PBRMaterialClass = mod.OpenPBRMaterial;
74+
} else {
75+
const mod = await import("core/Materials/PBR/pbrMaterial");
76+
PBRMaterialClass = mod.PBRMaterial;
77+
}
6778
const promises = new Array<Promise<any>>();
6879
promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial));
69-
promises.push(this._loadSheenPropertiesAsync(extensionContext, extension, babylonMaterial));
80+
promises.push(this._loadSheenPropertiesAsync(extensionContext, extension, babylonMaterial, useOpenPBR));
7081
// eslint-disable-next-line github/no-then
7182
return await Promise.all(promises).then(() => {});
7283
});
7384
}
7485

7586
// eslint-disable-next-line @typescript-eslint/promise-function-async, no-restricted-syntax
76-
private _loadSheenPropertiesAsync(context: string, properties: IKHRMaterialsSheen, babylonMaterial: Material): Promise<void> {
77-
if (!(babylonMaterial instanceof PBRMaterial)) {
87+
private _loadSheenPropertiesAsync(context: string, properties: IKHRMaterialsSheen, babylonMaterial: Material, useOpenPBR: boolean): Promise<void> {
88+
if (!(babylonMaterial instanceof PBRMaterialClass)) {
7889
throw new Error(`${context}: Material type not supported`);
7990
}
8091

81-
const promises = new Array<Promise<any>>();
92+
let sheenColor = Color3.Black();
93+
let sheenColorTexture: Nullable<BaseTexture> = null;
94+
let sheenRoughness = 0.0;
95+
let sheenRoughnessTexture: Nullable<BaseTexture> = null;
8296

83-
babylonMaterial.sheen.isEnabled = true;
84-
babylonMaterial.sheen.intensity = 1;
97+
const promises = new Array<Promise<any>>();
8598

8699
if (properties.sheenColorFactor != undefined) {
87-
babylonMaterial.sheen.color = Color3.FromArray(properties.sheenColorFactor);
88-
} else {
89-
babylonMaterial.sheen.color = Color3.Black();
100+
sheenColor = Color3.FromArray(properties.sheenColorFactor);
90101
}
91102

92103
if (properties.sheenColorTexture) {
93104
promises.push(
94105
this._loader.loadTextureInfoAsync(`${context}/sheenColorTexture`, properties.sheenColorTexture, (texture) => {
95106
texture.name = `${babylonMaterial.name} (Sheen Color)`;
96-
babylonMaterial.sheen.texture = texture;
107+
sheenColorTexture = texture;
97108
})
98109
);
99110
}
100111

101112
if (properties.sheenRoughnessFactor !== undefined) {
102-
babylonMaterial.sheen.roughness = properties.sheenRoughnessFactor;
103-
} else {
104-
babylonMaterial.sheen.roughness = 0;
113+
sheenRoughness = properties.sheenRoughnessFactor;
105114
}
106115

107116
if (properties.sheenRoughnessTexture) {
108117
(properties.sheenRoughnessTexture as ITextureInfo).nonColorData = true;
109118
promises.push(
110119
this._loader.loadTextureInfoAsync(`${context}/sheenRoughnessTexture`, properties.sheenRoughnessTexture, (texture) => {
111120
texture.name = `${babylonMaterial.name} (Sheen Roughness)`;
112-
babylonMaterial.sheen.textureRoughness = texture;
121+
sheenRoughnessTexture = texture;
113122
})
114123
);
115124
}
116125

117-
babylonMaterial.sheen.albedoScaling = true;
118-
babylonMaterial.sheen.useRoughnessFromMainTexture = false;
119-
120126
// eslint-disable-next-line github/no-then
121-
return Promise.all(promises).then(() => {});
127+
return Promise.all(promises).then(() => {
128+
if (useOpenPBR) {
129+
return;
130+
}
131+
const pbrMaterial = babylonMaterial as PBRMaterial;
132+
pbrMaterial.sheen.isEnabled = true;
133+
pbrMaterial.sheen.intensity = 1;
134+
pbrMaterial.sheen.color = sheenColor;
135+
pbrMaterial.sheen.texture = sheenColorTexture;
136+
pbrMaterial.sheen.roughness = sheenRoughness;
137+
pbrMaterial.sheen.textureRoughness = sheenRoughnessTexture;
138+
pbrMaterial.sheen.albedoScaling = true;
139+
pbrMaterial.sheen.useRoughnessFromMainTexture = false;
140+
});
122141
}
123142
}
124143

packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_specular.ts

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { Nullable } from "core/types";
2-
import { PBRMaterial } from "core/Materials/PBR/pbrMaterial";
3-
import { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial";
2+
import type { PBRMaterial } from "core/Materials/PBR/pbrMaterial";
3+
import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial";
44
import type { Material } from "core/Materials/material";
55

66
import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces";
@@ -24,6 +24,8 @@ declare module "../../glTFFileLoader" {
2424
}
2525
}
2626

27+
let PBRMaterialClass: typeof PBRMaterial | typeof OpenPBRMaterial;
28+
2729
/**
2830
* [Specification](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_specular/README.md)
2931
*/
@@ -63,18 +65,25 @@ export class KHR_materials_specular implements IGLTFLoaderExtension {
6365
* @internal
6466
*/
6567
// eslint-disable-next-line no-restricted-syntax
66-
public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): Nullable<Promise<void>> {
68+
public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, useOpenPBR: boolean = false): Nullable<Promise<void>> {
6769
return GLTFLoader.LoadExtensionAsync<IKHRMaterialsSpecular>(context, material, this.name, async (extensionContext, extension) => {
70+
if (useOpenPBR) {
71+
const mod = await import("core/Materials/PBR/openPbrMaterial");
72+
PBRMaterialClass = mod.OpenPBRMaterial;
73+
} else {
74+
const mod = await import("core/Materials/PBR/pbrMaterial");
75+
PBRMaterialClass = mod.PBRMaterial;
76+
}
6877
const promises = new Array<Promise<any>>();
6978
promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial));
70-
promises.push(this._loadSpecularPropertiesAsync(extensionContext, extension, babylonMaterial));
79+
promises.push(this._loadSpecularPropertiesAsync(extensionContext, extension, babylonMaterial, useOpenPBR));
7180
// Handle the EXT_materials_specular_edge_color sub-extension
7281
// https://github.com/KhronosGroup/glTF/blob/2a1111b88f052cbd3e2d82abb9faee56e7494904/extensions/2.0/Vendor/EXT_materials_specular_edge_color/README.md
73-
if (extension.extensions && extension.extensions.EXT_materials_specular_edge_color && babylonMaterial instanceof PBRMaterial) {
82+
if (!useOpenPBR && extension.extensions && extension.extensions.EXT_materials_specular_edge_color) {
7483
const specularEdgeColorExtension = extension.extensions.EXT_materials_specular_edge_color as IEXTMaterialsSpecularEdgeColor;
7584
if (specularEdgeColorExtension.specularEdgeColorEnabled) {
76-
babylonMaterial.brdf.dielectricSpecularModel = Constants.MATERIAL_DIELECTRIC_SPECULAR_MODEL_OPENPBR;
77-
babylonMaterial.brdf.conductorSpecularModel = Constants.MATERIAL_CONDUCTOR_SPECULAR_MODEL_OPENPBR;
85+
(babylonMaterial as PBRMaterial).brdf.dielectricSpecularModel = Constants.MATERIAL_DIELECTRIC_SPECULAR_MODEL_OPENPBR;
86+
(babylonMaterial as PBRMaterial).brdf.conductorSpecularModel = Constants.MATERIAL_CONDUCTOR_SPECULAR_MODEL_OPENPBR;
7887
}
7988
}
8089
// eslint-disable-next-line github/no-then
@@ -83,8 +92,8 @@ export class KHR_materials_specular implements IGLTFLoaderExtension {
8392
}
8493

8594
// eslint-disable-next-line @typescript-eslint/promise-function-async, no-restricted-syntax
86-
private _loadSpecularPropertiesAsync(context: string, properties: IKHRMaterialsSpecular, babylonMaterial: Material): Promise<void> {
87-
if (!(babylonMaterial instanceof PBRMaterial) && !(babylonMaterial instanceof OpenPBRMaterial)) {
95+
private _loadSpecularPropertiesAsync(context: string, properties: IKHRMaterialsSpecular, babylonMaterial: Material, useOpenPBR: boolean): Promise<void> {
96+
if (!(babylonMaterial instanceof PBRMaterialClass)) {
8897
throw new Error(`${context}: Material type not supported`);
8998
}
9099

packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_transmission.ts

Lines changed: 67 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { Nullable } from "core/types";
2-
import { PBRMaterial } from "core/Materials/PBR/pbrMaterial";
2+
import type { PBRMaterial } from "core/Materials/PBR/pbrMaterial";
3+
import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial";
34
import type { Material } from "core/Materials/material";
45
import type { BaseTexture } from "core/Materials/Textures/baseTexture";
56
import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces";
@@ -62,6 +63,8 @@ interface ITransmissionHelperOptions {
6263
clearColor?: Color4;
6364
}
6465

66+
let PBRMaterialClass: typeof PBRMaterial | typeof OpenPBRMaterial;
67+
6568
/**
6669
* A class to handle setting up the rendering of opaque objects to be shown through transmissive objects.
6770
*/
@@ -166,7 +169,7 @@ class TransmissionHelper {
166169
if (!material) {
167170
return false;
168171
}
169-
if (material instanceof PBRMaterial && material.subSurface.isRefractionEnabled) {
172+
if (material instanceof PBRMaterialClass && (material as any).subSurface.isRefractionEnabled) {
170173
return true;
171174
}
172175
return false;
@@ -220,8 +223,8 @@ class TransmissionHelper {
220223
// If the material is transparent, make sure that it's added to the transparent list and removed from the opaque list
221224
const useTransmission = this._shouldRenderAsTransmission(mesh.material);
222225
if (useTransmission) {
223-
if (mesh.material instanceof PBRMaterial) {
224-
mesh.material.subSurface.refractionTexture = this._opaqueRenderTarget;
226+
if (mesh.material instanceof PBRMaterialClass) {
227+
(mesh.material as any).subSurface.refractionTexture = this._opaqueRenderTarget;
225228
}
226229
if (opaqueIdx !== -1) {
227230
this._opaqueMeshesCache.splice(opaqueIdx, 1);
@@ -366,60 +369,87 @@ export class KHR_materials_transmission implements IGLTFLoaderExtension {
366369
* @internal
367370
*/
368371
// eslint-disable-next-line no-restricted-syntax
369-
public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material): Nullable<Promise<void>> {
372+
public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, useOpenPBR: boolean = false): Nullable<Promise<void>> {
370373
return GLTFLoader.LoadExtensionAsync<IKHRMaterialsTransmission>(context, material, this.name, async (extensionContext, extension) => {
374+
if (useOpenPBR) {
375+
const mod = await import("core/Materials/PBR/openPbrMaterial");
376+
PBRMaterialClass = mod.OpenPBRMaterial;
377+
} else {
378+
const mod = await import("core/Materials/PBR/pbrMaterial");
379+
PBRMaterialClass = mod.PBRMaterial;
380+
}
371381
const promises = new Array<Promise<any>>();
372382
promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial));
373-
promises.push(this._loadTransparentPropertiesAsync(extensionContext, material, babylonMaterial, extension));
383+
promises.push(this._loadTransparentPropertiesAsync(extensionContext, material, babylonMaterial, extension, useOpenPBR));
374384
// eslint-disable-next-line github/no-then
375385
return await Promise.all(promises).then(() => {});
376386
});
377387
}
378388

379389
// eslint-disable-next-line no-restricted-syntax, @typescript-eslint/promise-function-async
380-
private _loadTransparentPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, extension: IKHRMaterialsTransmission): Promise<void> {
381-
if (!(babylonMaterial instanceof PBRMaterial)) {
390+
private _loadTransparentPropertiesAsync(
391+
context: string,
392+
material: IMaterial,
393+
babylonMaterial: Material,
394+
extension: IKHRMaterialsTransmission,
395+
useOpenPBR: boolean
396+
): Promise<void> {
397+
if (!(babylonMaterial instanceof PBRMaterialClass)) {
382398
throw new Error(`${context}: Material type not supported`);
383399
}
384-
const pbrMaterial = babylonMaterial;
385-
386-
// Enables "refraction" texture which represents transmitted light.
387-
pbrMaterial.subSurface.isRefractionEnabled = true;
388-
389-
// Since this extension models thin-surface transmission only, we must make IOR = 1.0
390-
pbrMaterial.subSurface.volumeIndexOfRefraction = 1.0;
391400

392-
// Albedo colour will tint transmission.
393-
pbrMaterial.subSurface.useAlbedoToTintRefraction = true;
401+
let transmissionWeight = 0.0;
402+
let transmissionWeightTexture: Nullable<BaseTexture> = null;
394403

404+
const promises = new Array<Promise<any>>();
395405
if (extension.transmissionFactor !== undefined) {
396-
pbrMaterial.subSurface.refractionIntensity = extension.transmissionFactor;
397-
const scene = pbrMaterial.getScene() as unknown as ITransmissionHelperHolder;
398-
if (pbrMaterial.subSurface.refractionIntensity && !scene._transmissionHelper) {
399-
new TransmissionHelper({}, pbrMaterial.getScene());
400-
} else if (pbrMaterial.subSurface.refractionIntensity && !scene._transmissionHelper?._isRenderTargetValid()) {
401-
// If the render target is not valid, recreate it.
402-
scene._transmissionHelper?._setupRenderTargets();
403-
}
406+
transmissionWeight = extension.transmissionFactor;
404407
} else {
405-
pbrMaterial.subSurface.refractionIntensity = 0.0;
406-
pbrMaterial.subSurface.isRefractionEnabled = false;
407408
return Promise.resolve();
408409
}
409-
410-
pbrMaterial.subSurface.minimumThickness = 0.0;
411-
pbrMaterial.subSurface.maximumThickness = 0.0;
412410
if (extension.transmissionTexture) {
413411
(extension.transmissionTexture as ITextureInfo).nonColorData = true;
414412
// eslint-disable-next-line github/no-then
415-
return this._loader.loadTextureInfoAsync(`${context}/transmissionTexture`, extension.transmissionTexture, undefined).then((texture: BaseTexture) => {
416-
texture.name = `${babylonMaterial.name} (Transmission)`;
417-
pbrMaterial.subSurface.refractionIntensityTexture = texture;
418-
pbrMaterial.subSurface.useGltfStyleTextures = true;
419-
});
420-
} else {
421-
return Promise.resolve();
413+
promises.push(
414+
this._loader.loadTextureInfoAsync(`${context}/transmissionTexture`, extension.transmissionTexture, (texture: BaseTexture) => {
415+
texture.name = `${babylonMaterial.name} (Transmission)`;
416+
transmissionWeightTexture = texture;
417+
})
418+
);
422419
}
420+
421+
// eslint-disable-next-line github/no-then
422+
return Promise.all(promises).then(() => {
423+
if (useOpenPBR) {
424+
return;
425+
}
426+
const pbrMaterial = babylonMaterial as PBRMaterial;
427+
428+
// Enables "refraction" texture which represents transmitted light.
429+
pbrMaterial.subSurface.isRefractionEnabled = transmissionWeight !== 0;
430+
431+
// Since this extension models thin-surface transmission only, we must make IOR = 1.0
432+
pbrMaterial.subSurface.volumeIndexOfRefraction = 1.0;
433+
434+
// Albedo colour will tint transmission.
435+
pbrMaterial.subSurface.useAlbedoToTintRefraction = true;
436+
437+
pbrMaterial.subSurface.refractionIntensity = transmissionWeight;
438+
439+
if (transmissionWeight) {
440+
const scene = pbrMaterial.getScene() as unknown as ITransmissionHelperHolder;
441+
if (pbrMaterial.subSurface.refractionIntensity && !scene._transmissionHelper) {
442+
new TransmissionHelper({}, pbrMaterial.getScene());
443+
} else if (pbrMaterial.subSurface.refractionIntensity && !scene._transmissionHelper?._isRenderTargetValid()) {
444+
// If the render target is not valid, recreate it.
445+
scene._transmissionHelper?._setupRenderTargets();
446+
}
447+
}
448+
pbrMaterial.subSurface.minimumThickness = 0.0;
449+
pbrMaterial.subSurface.maximumThickness = 0.0;
450+
pbrMaterial.subSurface.refractionIntensityTexture = transmissionWeightTexture;
451+
pbrMaterial.subSurface.useGltfStyleTextures = true;
452+
});
423453
}
424454
}
425455

0 commit comments

Comments
 (0)