Skip to content

Commit 36decf1

Browse files
author
Mike Bond
committed
Import and export support for EXT_materials_clearcoat_darkening
1 parent 58ea859 commit 36decf1

File tree

6 files changed

+241
-1
lines changed

6 files changed

+241
-1
lines changed
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/* eslint-disable github/no-then */
2+
import type { Nullable } from "core/types";
3+
import type { PBRMaterial } from "core/Materials/PBR/pbrMaterial";
4+
import type { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial";
5+
import type { Material } from "core/Materials/material";
6+
import type { BaseTexture } from "core/Materials/Textures/baseTexture";
7+
import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces";
8+
import type { IGLTFLoaderExtension } from "../glTFLoaderExtension";
9+
import { GLTFLoader } from "../glTFLoader";
10+
import type { IEXTMaterialsClearcoatDarkening } from "babylonjs-gltf2interface";
11+
import { registerGLTFExtension, unregisterGLTFExtension } from "../glTFLoaderExtensionRegistry";
12+
13+
const NAME = "EXT_materials_clearcoat_darkening";
14+
15+
declare module "../../glTFFileLoader" {
16+
// eslint-disable-next-line jsdoc/require-jsdoc, @typescript-eslint/naming-convention
17+
export interface GLTFLoaderExtensionOptions {
18+
/**
19+
* Defines options for the EXT_materials_clearcoat_darkening extension.
20+
*/
21+
// NOTE: Don't use NAME here as it will break the UMD type declarations.
22+
["EXT_materials_clearcoat_darkening"]: {};
23+
}
24+
}
25+
26+
let PBRMaterialClass: typeof PBRMaterial | typeof OpenPBRMaterial;
27+
28+
/**
29+
* [Proposed Specification](https://github.com/KhronosGroup/glTF/pull/2518)
30+
* !!! Experimental Extension Subject to Changes !!!
31+
*/
32+
// eslint-disable-next-line @typescript-eslint/naming-convention
33+
export class EXT_materials_clearcoat_darkening implements IGLTFLoaderExtension {
34+
/**
35+
* The name of this extension.
36+
*/
37+
public readonly name = NAME;
38+
39+
/**
40+
* Defines whether this extension is enabled.
41+
*/
42+
public enabled: boolean;
43+
44+
/**
45+
* Defines a number that determines the order the extensions are applied.
46+
*/
47+
public order = 191;
48+
49+
private _loader: GLTFLoader;
50+
51+
/**
52+
* @internal
53+
*/
54+
constructor(loader: GLTFLoader) {
55+
this._loader = loader;
56+
this.enabled = this._loader.isExtensionUsed(NAME);
57+
}
58+
59+
/** @internal */
60+
public dispose() {
61+
(this._loader as any) = null;
62+
}
63+
64+
/**
65+
* @internal
66+
*/
67+
// eslint-disable-next-line no-restricted-syntax
68+
public loadMaterialPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, useOpenPBR: boolean = false): Nullable<Promise<void>> {
69+
return GLTFLoader.LoadExtensionAsync<IEXTMaterialsClearcoatDarkening>(context, material, this.name, async (extensionContext, extension) => {
70+
const promises = new Array<Promise<any>>();
71+
promises.push(this._loader.loadMaterialPropertiesAsync(context, material, babylonMaterial));
72+
if (useOpenPBR) {
73+
const mod = await import("core/Materials/PBR/openPbrMaterial");
74+
PBRMaterialClass = mod.OpenPBRMaterial;
75+
} else {
76+
// Logger.Warn(`${extensionContext}: The EXT_materials_clearcoat_darkening extension is only supported with OpenPBR materials. Falling back to PBRMaterial.`);
77+
return await Promise.resolve();
78+
}
79+
promises.push(this._loadDarkeningPropertiesAsync(extensionContext, material, babylonMaterial, extension));
80+
return await Promise.all(promises).then(() => {});
81+
});
82+
}
83+
84+
// eslint-disable-next-line no-restricted-syntax, @typescript-eslint/promise-function-async
85+
private _loadDarkeningPropertiesAsync(context: string, material: IMaterial, babylonMaterial: Material, extension: IEXTMaterialsClearcoatDarkening): Promise<void> {
86+
if (!(babylonMaterial instanceof PBRMaterialClass)) {
87+
throw new Error(`${context}: Material type not supported`);
88+
}
89+
90+
let darkeningFactor = 1.0;
91+
let darkeningFactorTexture: Nullable<BaseTexture>;
92+
93+
if (extension.clearcoatDarkeningFactor !== undefined) {
94+
darkeningFactor = extension.clearcoatDarkeningFactor;
95+
}
96+
97+
let texturePromise = Promise.resolve();
98+
99+
if (extension.clearcoatDarkeningTexture) {
100+
(extension.clearcoatDarkeningTexture as ITextureInfo).nonColorData = true;
101+
texturePromise = this._loader.loadTextureInfoAsync(`${context}/clearcoatDarkeningTexture`, extension.clearcoatDarkeningTexture).then((texture: BaseTexture) => {
102+
texture.name = `${babylonMaterial.name} (Clearcoat Darkening)`;
103+
darkeningFactorTexture = texture;
104+
});
105+
}
106+
107+
return texturePromise.then(() => {
108+
const openpbrMaterial = babylonMaterial as OpenPBRMaterial;
109+
openpbrMaterial.coatDarkening = darkeningFactor;
110+
if (darkeningFactorTexture) {
111+
openpbrMaterial.coatDarkeningTexture = darkeningFactorTexture;
112+
}
113+
});
114+
}
115+
}
116+
117+
unregisterGLTFExtension(NAME);
118+
registerGLTFExtension(NAME, true, (loader) => new EXT_materials_clearcoat_darkening(loader));

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import type { IMaterial, ITextureInfo } from "../glTFLoaderInterfaces";
88
import type { IGLTFLoaderExtension } from "../glTFLoaderExtension";
99
import { GLTFLoader } from "../glTFLoader";
1010
import type { IKHRMaterialsClearcoat } from "babylonjs-gltf2interface";
11-
import { registerGLTFExtension, unregisterGLTFExtension } from "../glTFLoaderExtensionRegistry";
11+
import { registeredGLTFExtensions, registerGLTFExtension, unregisterGLTFExtension } from "../glTFLoaderExtensionRegistry";
12+
import type { EXT_materials_clearcoat_darkening } from "./EXT_materials_clearcoat_darkening";
1213

1314
const NAME = "KHR_materials_clearcoat";
1415

@@ -80,6 +81,16 @@ export class KHR_materials_clearcoat implements IGLTFLoaderExtension {
8081
throw new Error(`${context}: Material type not supported`);
8182
}
8283
promises.push(this._loadClearCoatPropertiesAsync(extensionContext, extension, babylonMaterial, useOpenPBR));
84+
if (useOpenPBR && extension.extensions && extension.extensions.EXT_materials_clearcoat_darkening) {
85+
let darkeningExtension = await registeredGLTFExtensions.get("EXT_materials_clearcoat_darkening")?.factory(this._loader);
86+
darkeningExtension = darkeningExtension as EXT_materials_clearcoat_darkening;
87+
if (darkeningExtension && darkeningExtension.enabled && darkeningExtension.loadMaterialPropertiesAsync) {
88+
const promise = darkeningExtension.loadMaterialPropertiesAsync(extensionContext, extension as any, babylonMaterial, useOpenPBR);
89+
if (promise) {
90+
promises.push(promise);
91+
}
92+
}
93+
}
8394
await Promise.all(promises);
8495
});
8596
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export * from "./KHR_lights_punctual";
1111
export * from "./KHR_materials_pbrSpecularGlossiness";
1212
export * from "./KHR_materials_unlit";
1313
export * from "./KHR_materials_clearcoat";
14+
export * from "./EXT_materials_clearcoat_darkening";
1415
export * from "./KHR_materials_iridescence";
1516
export * from "./KHR_materials_anisotropy";
1617
export * from "./KHR_materials_emissive_strength";
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import type { IMaterial, IEXTMaterialsClearcoatDarkening } from "babylonjs-gltf2interface";
2+
import type { IGLTFExporterExtensionV2 } from "../glTFExporterExtension";
3+
import { GLTFExporter } from "../glTFExporter";
4+
import type { Material } from "core/Materials/material";
5+
import type { BaseTexture } from "core/Materials/Textures/baseTexture";
6+
import { OpenPBRMaterial } from "core/Materials/PBR/openPbrMaterial";
7+
import type { Nullable } from "core/types";
8+
9+
const NAME = "EXT_materials_clearcoat_darkening";
10+
11+
/**
12+
* @internal
13+
*/
14+
// eslint-disable-next-line @typescript-eslint/naming-convention
15+
export class EXT_materials_clearcoat_darkening implements IGLTFExporterExtensionV2 {
16+
/** Name of this extension */
17+
public readonly name = NAME;
18+
19+
/** Defines whether this extension is enabled */
20+
public enabled = true;
21+
22+
/** Defines whether this extension is required */
23+
public required = false;
24+
25+
private _exporter: GLTFExporter;
26+
27+
private _wasUsed = false;
28+
29+
constructor(exporter: GLTFExporter) {
30+
this._exporter = exporter;
31+
}
32+
33+
public dispose() {}
34+
35+
/** @internal */
36+
public get wasUsed() {
37+
return this._wasUsed;
38+
}
39+
40+
public postExportMaterialAdditionalTextures?(context: string, node: IMaterial, babylonMaterial: Material): BaseTexture[] {
41+
const additionalTextures: BaseTexture[] = [];
42+
if (babylonMaterial instanceof OpenPBRMaterial) {
43+
if (babylonMaterial.coatDarkening) {
44+
if (babylonMaterial.coatDarkeningTexture) {
45+
additionalTextures.push(babylonMaterial.coatDarkeningTexture);
46+
}
47+
return additionalTextures;
48+
}
49+
}
50+
51+
return [];
52+
}
53+
54+
// eslint-disable-next-line no-restricted-syntax
55+
public postExportMaterialAsync?(context: string, node: IMaterial, babylonMaterial: Material): Promise<IMaterial> {
56+
return new Promise((resolve) => {
57+
let coatDarkeningFactor: Nullable<number> = null;
58+
let coatDarkeningTexture: Nullable<BaseTexture> = null;
59+
if (babylonMaterial instanceof OpenPBRMaterial) {
60+
coatDarkeningFactor = babylonMaterial.coatDarkening;
61+
coatDarkeningTexture = babylonMaterial.coatDarkeningTexture;
62+
}
63+
if (coatDarkeningFactor === null || (coatDarkeningFactor === 1.0 && coatDarkeningTexture === null)) {
64+
resolve(node);
65+
return;
66+
}
67+
68+
this._wasUsed = true;
69+
70+
// This material must have the clearcoat extension already before
71+
// we can add the clearcoat darkening sub-extension
72+
const parentExt = node.extensions ? node.extensions["KHR_materials_clearcoat"] : null;
73+
if (!parentExt) {
74+
resolve(node);
75+
return;
76+
}
77+
78+
const coatDarkeningTextureInfo = this._exporter._materialExporter.getTextureInfo(coatDarkeningTexture);
79+
80+
const coatDarkeningInfo: IEXTMaterialsClearcoatDarkening = {
81+
clearcoatDarkeningFactor: coatDarkeningFactor,
82+
clearcoatDarkeningTexture: coatDarkeningTextureInfo ?? undefined,
83+
};
84+
85+
if (coatDarkeningInfo.clearcoatDarkeningTexture !== null) {
86+
this._exporter._materialNeedsUVsSet.add(babylonMaterial);
87+
}
88+
89+
parentExt.extensions = parentExt.extensions || {};
90+
parentExt.extensions[NAME] = coatDarkeningInfo;
91+
92+
resolve(node);
93+
});
94+
}
95+
}
96+
97+
GLTFExporter.RegisterExtension(NAME, (exporter) => new EXT_materials_clearcoat_darkening(exporter));

packages/dev/serializers/src/glTF/2.0/Extensions/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export * from "./KHR_draco_mesh_compression";
33
export * from "./KHR_lights_punctual";
44
export * from "./KHR_materials_anisotropy";
55
export * from "./KHR_materials_clearcoat";
6+
export * from "./EXT_materials_clearcoat_darkening";
67
export * from "./KHR_materials_diffuse_transmission";
78
export * from "./KHR_materials_dispersion";
89
export * from "./KHR_materials_emissive_strength";

packages/public/glTF2Interface/babylon.glTF2Interface.d.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,6 +1068,18 @@ declare module BABYLON.GLTF2 {
10681068
clearcoatRoughnessFactor?: number;
10691069
clearcoatRoughnessTexture?: ITextureInfo;
10701070
clearcoatNormalTexture?: IMaterialNormalTextureInfo;
1071+
/**
1072+
* Dictionary object with extension-specific objects
1073+
*/
1074+
extensions?: {
1075+
[key: string]: any;
1076+
};
1077+
}
1078+
1079+
/** @internal */
1080+
interface IEXTMaterialsClearcoatDarkening {
1081+
clearcoatDarkeningFactor?: number;
1082+
clearcoatDarkeningTexture?: ITextureInfo;
10711083
}
10721084

10731085
/** @internal */

0 commit comments

Comments
 (0)