@babylonjs/loaders 9.6.1 → 9.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -11,10 +11,20 @@ export interface IMaterialLoadingAdapter {
11
11
  * Gets the underlying material
12
12
  */
13
13
  readonly material: Material;
14
+ /** @deprecated Use finalizeAsync instead. */
15
+ finalize?(): void;
14
16
  /**
15
- * Finalizes material properties after loading is complete.
17
+ * Finalizes material properties after all loading is complete.
18
+ * May return a Promise for async work (e.g. GPU texture processing). Any returned
19
+ * Promise is tracked by the loader and awaited before the COMPLETE state is reached,
20
+ * so callers can rely on onCompleteObservable for fully processed materials.
21
+ *
22
+ * The loader passes an AbortSignal that is aborted when the loader is disposed.
23
+ * Implementations should check `signal.aborted` after each await point and, if
24
+ * aborted, release any intermediate resources and return early.
25
+ * @param signal An AbortSignal that fires when the loader is disposed mid-flight.
16
26
  */
17
- finalize?(): void;
27
+ finalizeAsync?(signal: AbortSignal): Promise<void> | void;
18
28
  /**
19
29
  * Whether the material should be treated as unlit
20
30
  */
@@ -76,6 +86,10 @@ export interface IMaterialLoadingAdapter {
76
86
  * @param enableEdgeColor - Whether to enable edge color support
77
87
  */
78
88
  enableSpecularEdgeColor(enableEdgeColor?: boolean): void;
89
+ /**
90
+ * Enable the specular/glossiness workflow and disable metallic/roughness.
91
+ */
92
+ configureSpecularGlossiness(): void;
79
93
  /**
80
94
  * Sets/gets the specular weight
81
95
  */
@@ -104,6 +118,11 @@ export interface IMaterialLoadingAdapter {
104
118
  * Sets/gets the specular IOR
105
119
  */
106
120
  specularIor: number;
121
+ /**
122
+ * Sets/gets the glossiness (inverted roughness)
123
+ * ONLY used for specular/glossiness workflow; has no effect when metallic/roughness workflow is active
124
+ */
125
+ glossiness: number;
107
126
  /**
108
127
  * Sets/gets the emissive color
109
128
  */
@@ -220,6 +239,9 @@ export interface IMaterialLoadingAdapter {
220
239
  * Configures transmission for thin-surface transmission (KHR_materials_transmission)
221
240
  */
222
241
  configureTransmission(): void;
242
+ /**
243
+ * Configures volume properties for volumetric transmission (KHR_materials_volume)
244
+ */
223
245
  configureVolume(): void;
224
246
  /**
225
247
  * Sets whether the material is thin-walled (i.e. non-volumetric) or not.
@@ -1 +1 @@
1
- {"version":3,"file":"materialLoadingAdapter.js","sourceRoot":"","sources":["../../../../../dev/loaders/src/glTF/2.0/materialLoadingAdapter.ts"],"names":[],"mappings":"","sourcesContent":["import { type Material } from \"core/Materials/material\";\r\nimport { type BaseTexture } from \"core/Materials/Textures/baseTexture\";\r\nimport { type Nullable } from \"core/types\";\r\nimport { type Color3 } from \"core/Maths/math.color\";\r\n\r\n/**\r\n * Interface for material loading adapters that provides a unified OpenPBR-like interface\r\n * for both OpenPBR and PBR materials, eliminating conditional branches in extensions.\r\n */\r\nexport interface IMaterialLoadingAdapter {\r\n /**\r\n * Gets the underlying material\r\n */\r\n readonly material: Material;\r\n\r\n /**\r\n * Finalizes material properties after loading is complete.\r\n */\r\n finalize?(): void;\r\n\r\n /**\r\n * Whether the material should be treated as unlit\r\n */\r\n isUnlit: boolean;\r\n\r\n // ========================================\r\n // CULLING PROPERTIES\r\n // ========================================\r\n\r\n /**\r\n * Sets/gets the back face culling\r\n */\r\n backFaceCulling: boolean;\r\n\r\n /**\r\n * Sets/gets the two sided lighting\r\n */\r\n twoSidedLighting: boolean;\r\n\r\n // ========================================\r\n // ALPHA PROPERTIES\r\n // ========================================\r\n\r\n /**\r\n * Sets/gets the alpha cutoff value (used for alpha test mode)\r\n */\r\n alphaCutOff: number;\r\n\r\n /**\r\n * Sets/gets whether to use alpha from albedo/base color texture\r\n */\r\n useAlphaFromBaseColorTexture: boolean;\r\n\r\n /**\r\n * Sets/Gets whether the transparency is treated as alpha coverage\r\n */\r\n transparencyAsAlphaCoverage: boolean;\r\n\r\n // ========================================\r\n // BASE PARAMETERS\r\n // ========================================\r\n\r\n /**\r\n * Sets/gets the base color\r\n */\r\n baseColor: Color3;\r\n\r\n /**\r\n * Sets/gets the base color texture\r\n */\r\n baseColorTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets/gets the base diffuse roughness\r\n */\r\n baseDiffuseRoughness: number;\r\n\r\n /**\r\n * Sets/gets the base diffuse roughness texture\r\n */\r\n baseDiffuseRoughnessTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets/gets the base metalness\r\n */\r\n baseMetalness: number;\r\n\r\n /**\r\n * Sets/gets the base metalness texture\r\n */\r\n baseMetalnessTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets whether to use roughness from metallic texture green channel\r\n */\r\n useRoughnessFromMetallicTextureGreen: boolean;\r\n\r\n /**\r\n * Sets whether to use metallic from metallic texture blue channel\r\n */\r\n useMetallicFromMetallicTextureBlue: boolean;\r\n\r\n // ========================================\r\n // SPECULAR PARAMETERS\r\n // ========================================\r\n\r\n /**\r\n * Configures specular properties and enables OpenPBR BRDF model for edge color support\r\n * @param enableEdgeColor - Whether to enable edge color support\r\n */\r\n enableSpecularEdgeColor(enableEdgeColor?: boolean): void;\r\n\r\n /**\r\n * Sets/gets the specular weight\r\n */\r\n specularWeight: number;\r\n\r\n /**\r\n * Sets/gets the specular weight texture\r\n */\r\n specularWeightTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets/gets the specular color\r\n */\r\n specularColor: Color3;\r\n\r\n /**\r\n * Sets/gets the specular color texture\r\n */\r\n specularColorTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets/gets the specular roughness\r\n */\r\n specularRoughness: number;\r\n\r\n /**\r\n * Sets/gets the specular roughness texture\r\n */\r\n specularRoughnessTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets/gets the specular IOR\r\n */\r\n specularIor: number;\r\n\r\n // ========================================\r\n // EMISSION PARAMETERS\r\n // ========================================\r\n\r\n /**\r\n * Sets/gets the emissive color\r\n */\r\n emissionColor: Color3;\r\n\r\n /**\r\n * Sets/gets the emissive luminance\r\n */\r\n emissionLuminance: number;\r\n\r\n /**\r\n * Sets/gets the emissive texture\r\n */\r\n emissionColorTexture: Nullable<BaseTexture>;\r\n\r\n // ========================================\r\n // AMBIENT OCCLUSION\r\n // ========================================\r\n\r\n /**\r\n * Sets/gets the ambient occlusion texture\r\n */\r\n ambientOcclusionTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets/gets the ambient occlusion texture strength/level\r\n */\r\n ambientOcclusionTextureStrength: number;\r\n\r\n // ========================================\r\n // COAT PARAMETERS\r\n // ========================================\r\n\r\n /**\r\n * Configures clear coat for PBR material\r\n */\r\n configureCoat(): void;\r\n\r\n /**\r\n * Sets/gets the coat weight\r\n */\r\n coatWeight: number;\r\n\r\n /**\r\n * Sets/gets the coat weight texture\r\n */\r\n coatWeightTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets the coat color\r\n */\r\n coatColor: Color3;\r\n\r\n /**\r\n * Sets the coat color texture\r\n */\r\n coatColorTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets/gets the coat roughness\r\n */\r\n coatRoughness: number;\r\n\r\n /**\r\n * Sets/gets the coat roughness texture\r\n */\r\n coatRoughnessTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets the coat index of refraction (IOR)\r\n */\r\n coatIor: number;\r\n\r\n /**\r\n * Sets the coat darkening\r\n */\r\n coatDarkening: number;\r\n\r\n /**\r\n * Sets the coat darkening texture\r\n */\r\n coatDarkeningTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets/gets the coat roughness anisotropy\r\n */\r\n coatRoughnessAnisotropy: number;\r\n\r\n /**\r\n * Sets the coat tangent angle for anisotropy\r\n */\r\n geometryCoatTangentAngle: number;\r\n\r\n /**\r\n * Sets the coat tangent texture for anisotropy\r\n */\r\n geometryCoatTangentTexture: Nullable<BaseTexture>;\r\n\r\n // ========================================\r\n // TRANSMISSION LAYER\r\n // ========================================\r\n\r\n /**\r\n * Sets the transmission weight\r\n */\r\n transmissionWeight: number;\r\n\r\n /**\r\n * Sets the transmission weight texture\r\n */\r\n transmissionWeightTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets the attenuation distance\r\n */\r\n transmissionDepth: number;\r\n\r\n /**\r\n * Sets the attenuation color\r\n */\r\n transmissionColor: Color3;\r\n\r\n /**\r\n * Sets the scattering coefficient\r\n */\r\n transmissionScatter: Color3;\r\n\r\n /**\r\n * Sets the transmission scatter texture\r\n */\r\n transmissionScatterTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets the scattering anisotropy (-1 to 1)\r\n */\r\n transmissionScatterAnisotropy: number;\r\n\r\n /**\r\n * Sets the dispersion Abbe number\r\n */\r\n transmissionDispersionAbbeNumber: number;\r\n\r\n /**\r\n * Sets the dispersion scale\r\n */\r\n transmissionDispersionScale: number;\r\n\r\n /**\r\n * The refraction background texture\r\n */\r\n refractionBackgroundTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Configures transmission for thin-surface transmission (KHR_materials_transmission)\r\n */\r\n configureTransmission(): void;\r\n\r\n // ========================================\r\n // VOLUME PROPERTIES\r\n // ========================================\r\n\r\n configureVolume(): void;\r\n\r\n /**\r\n * Sets whether the material is thin-walled (i.e. non-volumetric) or not.\r\n */\r\n geometryThinWalled: boolean;\r\n\r\n /**\r\n * Sets the thickness texture\r\n */\r\n volumeThicknessTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets the thickness factor\r\n */\r\n volumeThickness: number;\r\n\r\n // ========================================\r\n // SUBSURFACE PROPERTIES (Subsurface Scattering)\r\n // ========================================\r\n\r\n /**\r\n * Configures subsurface properties\r\n */\r\n configureSubsurface(): void;\r\n\r\n /**\r\n * Sets/gets the subsurface weight\r\n */\r\n subsurfaceWeight: number;\r\n\r\n /**\r\n * Sets/gets the subsurface weight texture\r\n */\r\n subsurfaceWeightTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets/gets the subsurface color\r\n */\r\n subsurfaceColor: Color3;\r\n\r\n /**\r\n * Sets/gets the subsurface color texture\r\n */\r\n subsurfaceColorTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets/gets the diffuse transmission tint of the material\r\n */\r\n diffuseTransmissionTint: Color3;\r\n\r\n /**\r\n * Sets/gets the diffuse transmission tint texture of the material\r\n */\r\n diffuseTransmissionTintTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets/gets the subsurface radius (used for subsurface scattering)\r\n */\r\n subsurfaceRadius: number;\r\n\r\n /**\r\n * Sets/gets the subsurface radius scale (used for subsurface scattering)\r\n */\r\n subsurfaceRadiusScale: Color3;\r\n\r\n /**\r\n * Sets/gets the subsurface scattering anisotropy\r\n */\r\n subsurfaceScatterAnisotropy: number;\r\n\r\n /**\r\n * Does this material have a translucent surface (i.e. either transmission or subsurface)?\r\n */\r\n isTranslucent(): boolean;\r\n\r\n // ========================================\r\n // FUZZ LAYER (Sheen)\r\n // ========================================\r\n\r\n /**\r\n * Configures initial settings for fuzz for material.\r\n */\r\n configureFuzz(): void;\r\n\r\n /**\r\n * Sets the fuzz weight\r\n */\r\n fuzzWeight: number;\r\n\r\n /**\r\n * Sets the fuzz weight texture\r\n */\r\n fuzzWeightTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets the fuzz color\r\n */\r\n fuzzColor: Color3;\r\n\r\n /**\r\n * Sets the fuzz color texture\r\n */\r\n fuzzColorTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets the fuzz roughness\r\n */\r\n fuzzRoughness: number;\r\n\r\n /**\r\n * Sets the fuzz roughness texture\r\n */\r\n fuzzRoughnessTexture: Nullable<BaseTexture>;\r\n\r\n // ========================================\r\n // ANISOTROPY\r\n // ========================================\r\n\r\n /**\r\n * Sets/gets the specular roughness anisotropy\r\n */\r\n specularRoughnessAnisotropy: number;\r\n\r\n /**\r\n * Sets the anisotropy rotation\r\n */\r\n geometryTangentAngle: number;\r\n\r\n /**\r\n * Sets/gets the anisotropy texture\r\n */\r\n geometryTangentTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Configures glTF-style anisotropy for OpenPBR materials\r\n * @param useGltfStyle - Whether to use glTF-style anisotropy (default: true)\r\n */\r\n configureGltfStyleAnisotropy(useGltfStyle?: boolean): void;\r\n\r\n // ========================================\r\n // THIN FILM IRIDESCENCE\r\n // ========================================\r\n\r\n /**\r\n * Sets the thin film weight\r\n */\r\n thinFilmWeight: number;\r\n\r\n /**\r\n * Sets the thin film IOR\r\n */\r\n thinFilmIor: number;\r\n\r\n /**\r\n * Sets the thin film thickness minimum\r\n */\r\n thinFilmThicknessMinimum: number;\r\n\r\n /**\r\n * Sets the thin film thickness maximum\r\n */\r\n thinFilmThicknessMaximum: number;\r\n\r\n /**\r\n * Sets the thin film iridescence texture\r\n */\r\n thinFilmWeightTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets the thin film thickness texture\r\n */\r\n thinFilmThicknessTexture: Nullable<BaseTexture>;\r\n\r\n // ========================================\r\n // UNLIT MATERIALS\r\n // ========================================\r\n\r\n /**\r\n * Sets the unlit flag\r\n */\r\n unlit: boolean;\r\n\r\n // ========================================\r\n // GEOMETRY PARAMETERS\r\n // ========================================\r\n\r\n /**\r\n * Sets/gets the geometry opacity\r\n */\r\n geometryOpacity: number;\r\n\r\n /**\r\n * Sets/gets the geometry normal texture\r\n */\r\n geometryNormalTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets the normal map inversions for PBR material only\r\n * @param invertX - Whether to invert the normal map on the X axis\r\n * @param invertY - Whether to invert the normal map on the Y axis\r\n */\r\n setNormalMapInversions(invertX: boolean, invertY: boolean): void;\r\n\r\n /**\r\n * Sets/gets the coat normal texture\r\n */\r\n geometryCoatNormalTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets the coat normal texture scale\r\n */\r\n geometryCoatNormalTextureScale: number;\r\n}\r\n"]}
1
+ {"version":3,"file":"materialLoadingAdapter.js","sourceRoot":"","sources":["../../../../../dev/loaders/src/glTF/2.0/materialLoadingAdapter.ts"],"names":[],"mappings":"","sourcesContent":["import { type Material } from \"core/Materials/material\";\r\nimport { type BaseTexture } from \"core/Materials/Textures/baseTexture\";\r\nimport { type Nullable } from \"core/types\";\r\nimport { type Color3 } from \"core/Maths/math.color\";\r\n\r\n/**\r\n * Interface for material loading adapters that provides a unified OpenPBR-like interface\r\n * for both OpenPBR and PBR materials, eliminating conditional branches in extensions.\r\n */\r\nexport interface IMaterialLoadingAdapter {\r\n /**\r\n * Gets the underlying material\r\n */\r\n readonly material: Material;\r\n\r\n /** @deprecated Use finalizeAsync instead. */\r\n finalize?(): void;\r\n\r\n /**\r\n * Finalizes material properties after all loading is complete.\r\n * May return a Promise for async work (e.g. GPU texture processing). Any returned\r\n * Promise is tracked by the loader and awaited before the COMPLETE state is reached,\r\n * so callers can rely on onCompleteObservable for fully processed materials.\r\n *\r\n * The loader passes an AbortSignal that is aborted when the loader is disposed.\r\n * Implementations should check `signal.aborted` after each await point and, if\r\n * aborted, release any intermediate resources and return early.\r\n * @param signal An AbortSignal that fires when the loader is disposed mid-flight.\r\n */\r\n finalizeAsync?(signal: AbortSignal): Promise<void> | void;\r\n\r\n /**\r\n * Whether the material should be treated as unlit\r\n */\r\n isUnlit: boolean;\r\n\r\n // ========================================\r\n // CULLING PROPERTIES\r\n // ========================================\r\n\r\n /**\r\n * Sets/gets the back face culling\r\n */\r\n backFaceCulling: boolean;\r\n\r\n /**\r\n * Sets/gets the two sided lighting\r\n */\r\n twoSidedLighting: boolean;\r\n\r\n // ========================================\r\n // ALPHA PROPERTIES\r\n // ========================================\r\n\r\n /**\r\n * Sets/gets the alpha cutoff value (used for alpha test mode)\r\n */\r\n alphaCutOff: number;\r\n\r\n /**\r\n * Sets/gets whether to use alpha from albedo/base color texture\r\n */\r\n useAlphaFromBaseColorTexture: boolean;\r\n\r\n /**\r\n * Sets/Gets whether the transparency is treated as alpha coverage\r\n */\r\n transparencyAsAlphaCoverage: boolean;\r\n\r\n // ========================================\r\n // BASE PARAMETERS\r\n // ========================================\r\n\r\n /**\r\n * Sets/gets the base color\r\n */\r\n baseColor: Color3;\r\n\r\n /**\r\n * Sets/gets the base color texture\r\n */\r\n baseColorTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets/gets the base diffuse roughness\r\n */\r\n baseDiffuseRoughness: number;\r\n\r\n /**\r\n * Sets/gets the base diffuse roughness texture\r\n */\r\n baseDiffuseRoughnessTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets/gets the base metalness\r\n */\r\n baseMetalness: number;\r\n\r\n /**\r\n * Sets/gets the base metalness texture\r\n */\r\n baseMetalnessTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets whether to use roughness from metallic texture green channel\r\n */\r\n useRoughnessFromMetallicTextureGreen: boolean;\r\n\r\n /**\r\n * Sets whether to use metallic from metallic texture blue channel\r\n */\r\n useMetallicFromMetallicTextureBlue: boolean;\r\n\r\n // ========================================\r\n // SPECULAR PARAMETERS\r\n // ========================================\r\n\r\n /**\r\n * Configures specular properties and enables OpenPBR BRDF model for edge color support\r\n * @param enableEdgeColor - Whether to enable edge color support\r\n */\r\n enableSpecularEdgeColor(enableEdgeColor?: boolean): void;\r\n\r\n /**\r\n * Enable the specular/glossiness workflow and disable metallic/roughness.\r\n */\r\n configureSpecularGlossiness(): void;\r\n\r\n /**\r\n * Sets/gets the specular weight\r\n */\r\n specularWeight: number;\r\n\r\n /**\r\n * Sets/gets the specular weight texture\r\n */\r\n specularWeightTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets/gets the specular color\r\n */\r\n specularColor: Color3;\r\n\r\n /**\r\n * Sets/gets the specular color texture\r\n */\r\n specularColorTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets/gets the specular roughness\r\n */\r\n specularRoughness: number;\r\n\r\n /**\r\n * Sets/gets the specular roughness texture\r\n */\r\n specularRoughnessTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets/gets the specular IOR\r\n */\r\n specularIor: number;\r\n\r\n /**\r\n * Sets/gets the glossiness (inverted roughness)\r\n * ONLY used for specular/glossiness workflow; has no effect when metallic/roughness workflow is active\r\n */\r\n glossiness: number;\r\n\r\n // ========================================\r\n // EMISSION PARAMETERS\r\n // ========================================\r\n\r\n /**\r\n * Sets/gets the emissive color\r\n */\r\n emissionColor: Color3;\r\n\r\n /**\r\n * Sets/gets the emissive luminance\r\n */\r\n emissionLuminance: number;\r\n\r\n /**\r\n * Sets/gets the emissive texture\r\n */\r\n emissionColorTexture: Nullable<BaseTexture>;\r\n\r\n // ========================================\r\n // AMBIENT OCCLUSION\r\n // ========================================\r\n\r\n /**\r\n * Sets/gets the ambient occlusion texture\r\n */\r\n ambientOcclusionTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets/gets the ambient occlusion texture strength/level\r\n */\r\n ambientOcclusionTextureStrength: number;\r\n\r\n // ========================================\r\n // COAT PARAMETERS\r\n // ========================================\r\n\r\n /**\r\n * Configures clear coat for PBR material\r\n */\r\n configureCoat(): void;\r\n\r\n /**\r\n * Sets/gets the coat weight\r\n */\r\n coatWeight: number;\r\n\r\n /**\r\n * Sets/gets the coat weight texture\r\n */\r\n coatWeightTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets the coat color\r\n */\r\n coatColor: Color3;\r\n\r\n /**\r\n * Sets the coat color texture\r\n */\r\n coatColorTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets/gets the coat roughness\r\n */\r\n coatRoughness: number;\r\n\r\n /**\r\n * Sets/gets the coat roughness texture\r\n */\r\n coatRoughnessTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets the coat index of refraction (IOR)\r\n */\r\n coatIor: number;\r\n\r\n /**\r\n * Sets the coat darkening\r\n */\r\n coatDarkening: number;\r\n\r\n /**\r\n * Sets the coat darkening texture\r\n */\r\n coatDarkeningTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets/gets the coat roughness anisotropy\r\n */\r\n coatRoughnessAnisotropy: number;\r\n\r\n /**\r\n * Sets the coat tangent angle for anisotropy\r\n */\r\n geometryCoatTangentAngle: number;\r\n\r\n /**\r\n * Sets the coat tangent texture for anisotropy\r\n */\r\n geometryCoatTangentTexture: Nullable<BaseTexture>;\r\n\r\n // ========================================\r\n // TRANSMISSION LAYER\r\n // ========================================\r\n\r\n /**\r\n * Sets the transmission weight\r\n */\r\n transmissionWeight: number;\r\n\r\n /**\r\n * Sets the transmission weight texture\r\n */\r\n transmissionWeightTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets the attenuation distance\r\n */\r\n transmissionDepth: number;\r\n\r\n /**\r\n * Sets the attenuation color\r\n */\r\n transmissionColor: Color3;\r\n\r\n /**\r\n * Sets the scattering coefficient\r\n */\r\n transmissionScatter: Color3;\r\n\r\n /**\r\n * Sets the transmission scatter texture\r\n */\r\n transmissionScatterTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets the scattering anisotropy (-1 to 1)\r\n */\r\n transmissionScatterAnisotropy: number;\r\n\r\n /**\r\n * Sets the dispersion Abbe number\r\n */\r\n transmissionDispersionAbbeNumber: number;\r\n\r\n /**\r\n * Sets the dispersion scale\r\n */\r\n transmissionDispersionScale: number;\r\n\r\n /**\r\n * The refraction background texture\r\n */\r\n refractionBackgroundTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Configures transmission for thin-surface transmission (KHR_materials_transmission)\r\n */\r\n configureTransmission(): void;\r\n\r\n // ========================================\r\n // VOLUME PROPERTIES\r\n // ========================================\r\n\r\n /**\r\n * Configures volume properties for volumetric transmission (KHR_materials_volume)\r\n */\r\n configureVolume(): void;\r\n\r\n /**\r\n * Sets whether the material is thin-walled (i.e. non-volumetric) or not.\r\n */\r\n geometryThinWalled: boolean;\r\n\r\n /**\r\n * Sets the thickness texture\r\n */\r\n volumeThicknessTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets the thickness factor\r\n */\r\n volumeThickness: number;\r\n\r\n // ========================================\r\n // SUBSURFACE PROPERTIES (Subsurface Scattering)\r\n // ========================================\r\n\r\n /**\r\n * Configures subsurface properties\r\n */\r\n configureSubsurface(): void;\r\n\r\n /**\r\n * Sets/gets the subsurface weight\r\n */\r\n subsurfaceWeight: number;\r\n\r\n /**\r\n * Sets/gets the subsurface weight texture\r\n */\r\n subsurfaceWeightTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets/gets the subsurface color\r\n */\r\n subsurfaceColor: Color3;\r\n\r\n /**\r\n * Sets/gets the subsurface color texture\r\n */\r\n subsurfaceColorTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets/gets the diffuse transmission tint of the material\r\n */\r\n diffuseTransmissionTint: Color3;\r\n\r\n /**\r\n * Sets/gets the diffuse transmission tint texture of the material\r\n */\r\n diffuseTransmissionTintTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets/gets the subsurface radius (used for subsurface scattering)\r\n */\r\n subsurfaceRadius: number;\r\n\r\n /**\r\n * Sets/gets the subsurface radius scale (used for subsurface scattering)\r\n */\r\n subsurfaceRadiusScale: Color3;\r\n\r\n /**\r\n * Sets/gets the subsurface scattering anisotropy\r\n */\r\n subsurfaceScatterAnisotropy: number;\r\n\r\n /**\r\n * Does this material have a translucent surface (i.e. either transmission or subsurface)?\r\n */\r\n isTranslucent(): boolean;\r\n\r\n // ========================================\r\n // FUZZ LAYER (Sheen)\r\n // ========================================\r\n\r\n /**\r\n * Configures initial settings for fuzz for material.\r\n */\r\n configureFuzz(): void;\r\n\r\n /**\r\n * Sets the fuzz weight\r\n */\r\n fuzzWeight: number;\r\n\r\n /**\r\n * Sets the fuzz weight texture\r\n */\r\n fuzzWeightTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets the fuzz color\r\n */\r\n fuzzColor: Color3;\r\n\r\n /**\r\n * Sets the fuzz color texture\r\n */\r\n fuzzColorTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets the fuzz roughness\r\n */\r\n fuzzRoughness: number;\r\n\r\n /**\r\n * Sets the fuzz roughness texture\r\n */\r\n fuzzRoughnessTexture: Nullable<BaseTexture>;\r\n\r\n // ========================================\r\n // ANISOTROPY\r\n // ========================================\r\n\r\n /**\r\n * Sets/gets the specular roughness anisotropy\r\n */\r\n specularRoughnessAnisotropy: number;\r\n\r\n /**\r\n * Sets the anisotropy rotation\r\n */\r\n geometryTangentAngle: number;\r\n\r\n /**\r\n * Sets/gets the anisotropy texture\r\n */\r\n geometryTangentTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Configures glTF-style anisotropy for OpenPBR materials\r\n * @param useGltfStyle - Whether to use glTF-style anisotropy (default: true)\r\n */\r\n configureGltfStyleAnisotropy(useGltfStyle?: boolean): void;\r\n\r\n // ========================================\r\n // THIN FILM IRIDESCENCE\r\n // ========================================\r\n\r\n /**\r\n * Sets the thin film weight\r\n */\r\n thinFilmWeight: number;\r\n\r\n /**\r\n * Sets the thin film IOR\r\n */\r\n thinFilmIor: number;\r\n\r\n /**\r\n * Sets the thin film thickness minimum\r\n */\r\n thinFilmThicknessMinimum: number;\r\n\r\n /**\r\n * Sets the thin film thickness maximum\r\n */\r\n thinFilmThicknessMaximum: number;\r\n\r\n /**\r\n * Sets the thin film iridescence texture\r\n */\r\n thinFilmWeightTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets the thin film thickness texture\r\n */\r\n thinFilmThicknessTexture: Nullable<BaseTexture>;\r\n\r\n // ========================================\r\n // UNLIT MATERIALS\r\n // ========================================\r\n\r\n /**\r\n * Sets the unlit flag\r\n */\r\n unlit: boolean;\r\n\r\n // ========================================\r\n // GEOMETRY PARAMETERS\r\n // ========================================\r\n\r\n /**\r\n * Sets/gets the geometry opacity\r\n */\r\n geometryOpacity: number;\r\n\r\n /**\r\n * Sets/gets the geometry normal texture\r\n */\r\n geometryNormalTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets the normal map inversions for PBR material only\r\n * @param invertX - Whether to invert the normal map on the X axis\r\n * @param invertY - Whether to invert the normal map on the Y axis\r\n */\r\n setNormalMapInversions(invertX: boolean, invertY: boolean): void;\r\n\r\n /**\r\n * Sets/gets the coat normal texture\r\n */\r\n geometryCoatNormalTexture: Nullable<BaseTexture>;\r\n\r\n /**\r\n * Sets the coat normal texture scale\r\n */\r\n geometryCoatNormalTextureScale: number;\r\n}\r\n"]}
@@ -9,6 +9,7 @@ import { type IMaterialLoadingAdapter } from "./materialLoadingAdapter.js";
9
9
  */
10
10
  export declare class OpenPBRMaterialLoadingAdapter implements IMaterialLoadingAdapter {
11
11
  private _material;
12
+ private _specWorkflow;
12
13
  /**
13
14
  * Creates a new instance of the OpenPBRMaterialLoadingAdapter.
14
15
  * @param material - The OpenPBR material to adapt.
@@ -151,6 +152,7 @@ export declare class OpenPBRMaterialLoadingAdapter implements IMaterialLoadingAd
151
152
  * @param _enableEdgeColor Whether to enable edge color support (ignored for OpenPBR)
152
153
  */
153
154
  enableSpecularEdgeColor(_enableEdgeColor?: boolean): void;
155
+ configureSpecularGlossiness(): void;
154
156
  /**
155
157
  * Sets the specular weight of the OpenPBR material.
156
158
  * @param value The specular weight value (0-1)
@@ -223,6 +225,11 @@ export declare class OpenPBRMaterialLoadingAdapter implements IMaterialLoadingAd
223
225
  * @returns The IOR value
224
226
  */
225
227
  get specularIor(): number;
228
+ /**
229
+ * Sets the glossiness (inverted roughness) of the OpenPBR material.
230
+ */
231
+ set glossiness(value: number);
232
+ get glossiness(): number;
226
233
  /**
227
234
  * Sets the emission color of the OpenPBR material.
228
235
  * @param value The emission color as a Color3
@@ -303,6 +310,10 @@ export declare class OpenPBRMaterialLoadingAdapter implements IMaterialLoadingAd
303
310
  * @param value The coat color as a Color3
304
311
  */
305
312
  set coatColor(value: Color3);
313
+ /**
314
+ * Gets the coat color of the OpenPBR material.
315
+ */
316
+ get coatColor(): Color3;
306
317
  /**
307
318
  * Sets the coat color texture of the OpenPBR material.
308
319
  * @param value The coat color texture or null
@@ -332,11 +343,13 @@ export declare class OpenPBRMaterialLoadingAdapter implements IMaterialLoadingAd
332
343
  * Sets the coat index of refraction (IOR) of the OpenPBR material.
333
344
  */
334
345
  set coatIor(value: number);
346
+ get coatIor(): number;
335
347
  /**
336
348
  * Sets the coat darkening value of the OpenPBR material.
337
349
  * @param value The coat darkening value
338
350
  */
339
351
  set coatDarkening(value: number);
352
+ get coatDarkening(): number;
340
353
  /**
341
354
  * Sets the coat darkening texture (OpenPBR: coatDarkeningTexture, no PBR equivalent)
342
355
  */
@@ -385,6 +398,7 @@ export declare class OpenPBRMaterialLoadingAdapter implements IMaterialLoadingAd
385
398
  * @param value The transmission weight texture or null
386
399
  */
387
400
  set transmissionWeightTexture(value: Nullable<BaseTexture>);
401
+ get transmissionWeightTexture(): Nullable<BaseTexture>;
388
402
  /**
389
403
  * Gets the transmission weight.
390
404
  * @returns Currently returns 0 as transmission is not yet available
@@ -453,6 +467,9 @@ export declare class OpenPBRMaterialLoadingAdapter implements IMaterialLoadingAd
453
467
  * @param value The refraction background texture or null
454
468
  */
455
469
  set refractionBackgroundTexture(value: Nullable<BaseTexture>);
470
+ /**
471
+ * Configures volume properties for OpenPBR material.
472
+ */
456
473
  configureVolume(): void;
457
474
  /**
458
475
  * Sets whether the material is thin-walled (i.e. non-volumetric) or not.
@@ -485,6 +502,7 @@ export declare class OpenPBRMaterialLoadingAdapter implements IMaterialLoadingAd
485
502
  * Sets the subsurface weight texture
486
503
  */
487
504
  set subsurfaceWeightTexture(value: Nullable<BaseTexture>);
505
+ get subsurfaceWeightTexture(): Nullable<BaseTexture>;
488
506
  /**
489
507
  * Sets the subsurface color.
490
508
  * @param value The subsurface tint color as a Color3
@@ -684,5 +702,11 @@ export declare class OpenPBRMaterialLoadingAdapter implements IMaterialLoadingAd
684
702
  * @param value The scale value for the coat normal texture
685
703
  */
686
704
  set geometryCoatNormalTextureScale(value: number);
687
- finalize(): void;
705
+ /**
706
+ * Finalizes material properties after all loading is complete.
707
+ * @param signal An AbortSignal that fires when the loader is disposed. Intermediate
708
+ * textures are disposed and the method returns early when aborted.
709
+ */
710
+ finalizeAsync(signal: AbortSignal): Promise<void>;
711
+ private copySurfaceToCoatAsync;
688
712
  }
@@ -1,4 +1,5 @@
1
- import { Color3 } from "@babylonjs/core/Maths/math.color.js";
1
+ import { Color3, Color4 } from "@babylonjs/core/Maths/math.color.js";
2
+ import { MultiplyTexturesAsync, LerpTexturesAsync, CreateTextureWithFactorOperand, TextureChannel, TextureColorSpace, InvertTextureAsync, ExtractChannelAsync, ChannelMask, ExtractMaxChannelAsync, } from "@babylonjs/core/Materials/Textures/textureProcessor.js";
2
3
  /**
3
4
  * Material Loading Adapter for OpenPBR materials that provides a unified OpenPBR-like interface.
4
5
  */
@@ -8,6 +9,7 @@ export class OpenPBRMaterialLoadingAdapter {
8
9
  * @param material - The OpenPBR material to adapt.
9
10
  */
10
11
  constructor(material) {
12
+ this._specWorkflow = false;
11
13
  this._diffuseTransmissionTint = Color3.White();
12
14
  this._diffuseTransmissionTintTexture = null;
13
15
  this._material = material;
@@ -218,6 +220,9 @@ export class OpenPBRMaterialLoadingAdapter {
218
220
  enableSpecularEdgeColor(_enableEdgeColor = false) {
219
221
  // OpenPBR already supports edge color natively, no configuration needed
220
222
  }
223
+ configureSpecularGlossiness() {
224
+ this._specWorkflow = true;
225
+ }
221
226
  /**
222
227
  * Sets the specular weight of the OpenPBR material.
223
228
  * @param value The specular weight value (0-1)
@@ -330,6 +335,15 @@ export class OpenPBRMaterialLoadingAdapter {
330
335
  get specularIor() {
331
336
  return this._material.specularIor;
332
337
  }
338
+ /**
339
+ * Sets the glossiness (inverted roughness) of the OpenPBR material.
340
+ */
341
+ set glossiness(value) {
342
+ this._material.specularRoughness = Math.max(1.0 - value, 0.0);
343
+ }
344
+ get glossiness() {
345
+ return 1.0 - this._material.specularRoughness;
346
+ }
333
347
  // ========================================
334
348
  // EMISSION PARAMETERS
335
349
  // ========================================
@@ -455,6 +469,12 @@ export class OpenPBRMaterialLoadingAdapter {
455
469
  set coatColor(value) {
456
470
  this._material.coatColor = value;
457
471
  }
472
+ /**
473
+ * Gets the coat color of the OpenPBR material.
474
+ */
475
+ get coatColor() {
476
+ return this._material.coatColor;
477
+ }
458
478
  /**
459
479
  * Sets the coat color texture of the OpenPBR material.
460
480
  * @param value The coat color texture or null
@@ -499,6 +519,9 @@ export class OpenPBRMaterialLoadingAdapter {
499
519
  set coatIor(value) {
500
520
  this._material.coatIor = value;
501
521
  }
522
+ get coatIor() {
523
+ return this._material.coatIor;
524
+ }
502
525
  /**
503
526
  * Sets the coat darkening value of the OpenPBR material.
504
527
  * @param value The coat darkening value
@@ -506,6 +529,9 @@ export class OpenPBRMaterialLoadingAdapter {
506
529
  set coatDarkening(value) {
507
530
  this._material.coatDarkening = value;
508
531
  }
532
+ get coatDarkening() {
533
+ return this._material.coatDarkening;
534
+ }
509
535
  /**
510
536
  * Sets the coat darkening texture (OpenPBR: coatDarkeningTexture, no PBR equivalent)
511
537
  */
@@ -580,6 +606,9 @@ export class OpenPBRMaterialLoadingAdapter {
580
606
  set transmissionWeightTexture(value) {
581
607
  this._material.transmissionWeightTexture = value;
582
608
  }
609
+ get transmissionWeightTexture() {
610
+ return this._material.transmissionWeightTexture;
611
+ }
583
612
  /**
584
613
  * Gets the transmission weight.
585
614
  * @returns Currently returns 0 as transmission is not yet available
@@ -692,6 +721,9 @@ export class OpenPBRMaterialLoadingAdapter {
692
721
  // ========================================
693
722
  // VOLUME PROPERTIES
694
723
  // ========================================
724
+ /**
725
+ * Configures volume properties for OpenPBR material.
726
+ */
695
727
  configureVolume() {
696
728
  // If we're configuring volume, we assume the material is not thin-walled (i.e. it's volumetric).
697
729
  this._material.geometryThinWalled = 0.0;
@@ -748,6 +780,10 @@ export class OpenPBRMaterialLoadingAdapter {
748
780
  */
749
781
  set subsurfaceWeightTexture(value) {
750
782
  this._material.subsurfaceWeightTexture = value;
783
+ this._material._useSubsurfaceWeightFromTextureAlpha = true;
784
+ }
785
+ get subsurfaceWeightTexture() {
786
+ return this._material.subsurfaceWeightTexture;
751
787
  }
752
788
  /**
753
789
  * Sets the subsurface color.
@@ -1044,7 +1080,12 @@ export class OpenPBRMaterialLoadingAdapter {
1044
1080
  this._material.geometryCoatNormalTexture.level = value;
1045
1081
  }
1046
1082
  }
1047
- finalize() {
1083
+ /**
1084
+ * Finalizes material properties after all loading is complete.
1085
+ * @param signal An AbortSignal that fires when the loader is disposed. Intermediate
1086
+ * textures are disposed and the method returns early when aborted.
1087
+ */
1088
+ async finalizeAsync(signal) {
1048
1089
  // Do final configuration for the material to handle any interactions/dependencies between properties that we had to defer until all properties were loaded.
1049
1090
  // If the material is volumetric, we may need to create a coat layer to handle the surface tint.
1050
1091
  if ((this._diffuseTransmissionTint && !this._diffuseTransmissionTint.equals(Color3.White())) || this._diffuseTransmissionTintTexture) {
@@ -1054,20 +1095,10 @@ export class OpenPBRMaterialLoadingAdapter {
1054
1095
  this.subsurfaceColorTexture = this._diffuseTransmissionTintTexture;
1055
1096
  }
1056
1097
  else {
1057
- // The material is volumetric and we have surface tinting, so we need to move that tinting to the coat layer to preserve it.
1058
- // TODO: If we already have a coat slab, we'll have to merge the two.
1059
- if (this._material.coatWeight == 0 && (!this.baseColor.equals(Color3.White()) || this.baseColorTexture)) {
1060
- this._material.coatWeight = this.subsurfaceWeight;
1061
- this._material.coatWeightTexture = this.subsurfaceWeightTexture;
1062
- this._material.coatColor = this._diffuseTransmissionTint;
1063
- this._material.coatColorTexture = this._diffuseTransmissionTintTexture;
1064
- this._material.coatIor = this._material.specularIor; // Use the same IOR for the coat as the specular layer to try to match the original reflection as closely as possible.
1065
- this._material.coatDarkening = 0.0;
1066
- this._material.coatRoughness = this._material.specularRoughness;
1067
- this._material.coatRoughnessTexture = this._material.specularRoughnessTexture;
1068
- // To simulate diffuse transmission, set the specular roughness to maximum and remove the roughness texture.
1069
- this._material.specularRoughness = 1.0;
1070
- this._material.specularRoughnessTexture = null;
1098
+ // Otherwise, we have volumetric attenuation so we need to use the coat layer to preserve the base color tinting of glTF.
1099
+ await this.copySurfaceToCoatAsync(this.subsurfaceWeight, this.subsurfaceWeightTexture, TextureChannel.A, this._diffuseTransmissionTint, this._diffuseTransmissionTintTexture, true, signal);
1100
+ if (signal.aborted) {
1101
+ return;
1071
1102
  }
1072
1103
  }
1073
1104
  }
@@ -1078,17 +1109,139 @@ export class OpenPBRMaterialLoadingAdapter {
1078
1109
  this._material.transmissionColor = this._material.baseColor;
1079
1110
  this._material.transmissionColorTexture = this._material.baseColorTexture;
1080
1111
  }
1081
- else if (this._material.coatWeight == 0 && (!this.baseColor.equals(Color3.White()) || this.baseColorTexture !== null)) {
1112
+ else if (!this.baseColor.equals(Color3.White()) || this.baseColorTexture !== null) {
1082
1113
  // Otherwise, we have volumetric attenuation so we need to use the coat layer to preserve the base color tinting of glTF.
1083
- // TODO: If we already have a coat slab, we'll have to merge the two.
1084
- this._material.coatWeight = this.transmissionWeight;
1085
- this._material.coatWeightTexture = this.transmissionWeightTexture;
1086
- this._material.coatColor = this.baseColor;
1087
- this._material.coatColorTexture = this.baseColorTexture;
1088
- this._material.coatIor = this._material.specularIor; // Use the same IOR for the coat as the specular layer to try to match the original reflection as closely as possible.
1089
- this._material.coatDarkening = 0.0;
1090
- this._material.coatRoughness = this._material.specularRoughness;
1091
- this._material.coatRoughnessTexture = this._material.specularRoughnessTexture;
1114
+ await this.copySurfaceToCoatAsync(this.transmissionWeight, this.transmissionWeightTexture, TextureChannel.R, this.baseColor, this.baseColorTexture, false, signal);
1115
+ if (signal.aborted) {
1116
+ return;
1117
+ }
1118
+ }
1119
+ }
1120
+ if (this._specWorkflow) {
1121
+ // To convert from spec-gloss to OpenPBR, we'll grab the specular color's alpha channel (which contains glossiness) and
1122
+ // invert it to get roughness.
1123
+ const newRoughnessTexture = await InvertTextureAsync("newRoughnessTexture (" + this._material.name + ")", await ExtractChannelAsync("glossiness (" + this._material.name + ")", CreateTextureWithFactorOperand(this.specularColorTexture, new Color4(this.specularColor.r, this.specularColor.g, this.specularColor.b, this.glossiness), TextureChannel.A, TextureColorSpace.Linear), TextureChannel.A, this._material.getScene(), TextureColorSpace.Linear, ChannelMask.R), this._material.getScene(), ChannelMask.R, TextureColorSpace.Linear, ChannelMask.R);
1124
+ if (signal.aborted) {
1125
+ newRoughnessTexture.texture?.dispose();
1126
+ return;
1127
+ }
1128
+ this.specularRoughnessTexture = newRoughnessTexture.texture;
1129
+ this.specularRoughness = newRoughnessTexture.factor ? newRoughnessTexture.factor.r : 1.0;
1130
+ // Metallic = max(linearize(specular).rgb). The specular texture is sRGB so we must
1131
+ // linearize it first (TextureColorSpace.SRGB). The factor is already linear per convention.
1132
+ // We store metallic as linear (no outputColorSpace) because it is a data/scalar value;
1133
+ // encoding it as sRGB would corrupt it when it is used as the lerp t below.
1134
+ const newMetallic = await ExtractMaxChannelAsync("metallicTexture (" + this._material.name + ")", CreateTextureWithFactorOperand(this.specularColorTexture, this.specularColor.toColor4(), TextureChannel.RGBA, TextureColorSpace.Linear), this._material.getScene(), false, TextureColorSpace.SRGB, ChannelMask.RGB);
1135
+ if (signal.aborted) {
1136
+ newMetallic.texture?.dispose();
1137
+ return;
1138
+ }
1139
+ this.baseMetalnessTexture = newMetallic.texture;
1140
+ this.baseMetalness = newMetallic.factor ? newMetallic.factor.r : 1.0;
1141
+ // base_color = lerp(diffuse, specular, metallic).
1142
+ // Strip dispose before passing newMetallic as t — its texture is already owned by the
1143
+ // material (baseMetalnessTexture) and must not be released after the lerp pass.
1144
+ const newBaseColor = await LerpTexturesAsync("newBaseColor (" + this._material.name + ")", CreateTextureWithFactorOperand(this.baseColorTexture, this.baseColor.toColor4(), TextureChannel.RGBA, TextureColorSpace.Linear), CreateTextureWithFactorOperand(this.specularColorTexture, this.specularColor.toColor4(), TextureChannel.RGBA, TextureColorSpace.Linear), { ...newMetallic, dispose: undefined, colorSpace: TextureColorSpace.Linear }, this._material.getScene(), TextureColorSpace.SRGB, ChannelMask.RGB);
1145
+ if (signal.aborted) {
1146
+ newBaseColor.texture?.dispose();
1147
+ return;
1148
+ }
1149
+ const oldBaseColorTexture = this.baseColorTexture;
1150
+ oldBaseColorTexture?.dispose();
1151
+ this.baseColorTexture = newBaseColor.texture;
1152
+ this.baseColor = newBaseColor.factor ? new Color3(newBaseColor.factor.r, newBaseColor.factor.g, newBaseColor.factor.b) : Color3.White();
1153
+ const oldSpecularColorTexture = this.specularColorTexture;
1154
+ oldSpecularColorTexture?.dispose();
1155
+ this.specularColorTexture = null;
1156
+ }
1157
+ }
1158
+ async copySurfaceToCoatAsync(weight, weightTexture, weightTextureChannel, color, colorTexture, diffuseTransmission = false, signal = new AbortController().signal) {
1159
+ // Blend coat properties using:
1160
+ // New coat will cover all areas that previously had coat or transmission.
1161
+ // new_coat_weight = max(weight, existing_coat_weight)
1162
+ // New coat color is the multiplication of the base color tint and the existing coat tint, each blended by their respective weights:
1163
+ // new_coat_color = lerp(white, existing_coat_color, existing_coat_weight)
1164
+ // * lerp(white, color, weight)
1165
+ // Snapshot the original coat properties before mutating them, so both lerps
1166
+ // use the pre-merge values (the first lerp blends the *existing* coat color
1167
+ // by the *existing* coat weight; we must not use the merged weight here).
1168
+ const origCoatWeight = this._material.coatWeight;
1169
+ const origCoatWeightTexture = this._material.coatWeightTexture;
1170
+ const origCoatColor = this._material.coatColor.clone();
1171
+ const origCoatColorTexture = this._material.coatColorTexture;
1172
+ const origCoatNormalTexture = this._material.geometryCoatNormalTexture;
1173
+ const origCoatWeightCol4 = new Color4(origCoatWeight, origCoatWeight, origCoatWeight, origCoatWeight);
1174
+ const weightCol4 = new Color4(weight, weight, weight, weight);
1175
+ this.coatWeightTexture = null;
1176
+ this.coatWeight = 1.0;
1177
+ const results = await Promise.allSettled([
1178
+ LerpTexturesAsync("lerpExistingCoat", CreateTextureWithFactorOperand(null, new Color4(1, 1, 1, 1)), CreateTextureWithFactorOperand(origCoatColorTexture, origCoatColor.toColor4(), TextureChannel.RGBA, TextureColorSpace.SRGB), CreateTextureWithFactorOperand(origCoatWeightTexture, origCoatWeightCol4, TextureChannel.R), this._material.getScene(), TextureColorSpace.SRGB),
1179
+ LerpTexturesAsync("lerpSurfaceColor", CreateTextureWithFactorOperand(null, new Color4(1, 1, 1, 1)), CreateTextureWithFactorOperand(colorTexture, color.toColor4(), TextureChannel.RGBA, TextureColorSpace.SRGB), CreateTextureWithFactorOperand(weightTexture, weightCol4, weightTextureChannel), this._material.getScene(), TextureColorSpace.SRGB),
1180
+ ]);
1181
+ const rejected = results.find((r) => r.status === "rejected");
1182
+ if (rejected) {
1183
+ for (const r of results) {
1184
+ if (r.status === "fulfilled") {
1185
+ r.value.texture?.dispose();
1186
+ }
1187
+ }
1188
+ throw rejected.reason;
1189
+ }
1190
+ const [lerpCoatColor, lerpSurfaceColor] = results.map((r) => r.value);
1191
+ if (signal.aborted) {
1192
+ lerpCoatColor.texture?.dispose();
1193
+ lerpSurfaceColor.texture?.dispose();
1194
+ return;
1195
+ }
1196
+ const newCoatColor = await MultiplyTexturesAsync("newCoatColor (" + this._material.name + ")", lerpCoatColor, lerpSurfaceColor, this._material.getScene(), TextureColorSpace.SRGB);
1197
+ if (signal.aborted) {
1198
+ newCoatColor.texture?.dispose();
1199
+ return;
1200
+ }
1201
+ if (newCoatColor.texture) {
1202
+ this.coatColorTexture = newCoatColor.texture;
1203
+ this.coatColor = Color3.White();
1204
+ }
1205
+ else if (newCoatColor.factor) {
1206
+ this.coatColorTexture = null;
1207
+ this.coatColor.fromArray([newCoatColor.factor.r, newCoatColor.factor.g, newCoatColor.factor.b]);
1208
+ }
1209
+ const newCoatIor = await LerpTexturesAsync("newCoatIor (" + this._material.name + ")", CreateTextureWithFactorOperand(null, new Color4(this._material.specularIor, this._material.specularIor, this._material.specularIor, 1.0), TextureChannel.R), CreateTextureWithFactorOperand(null, new Color4(this.coatIor, this.coatIor, this.coatIor, 1.0), TextureChannel.R), CreateTextureWithFactorOperand(origCoatWeightTexture, origCoatWeightCol4, TextureChannel.R), this._material.getScene());
1210
+ if (signal.aborted) {
1211
+ newCoatIor.texture?.dispose();
1212
+ return;
1213
+ }
1214
+ this.coatIor = newCoatIor.factor ? newCoatIor.factor.r : this.coatIor;
1215
+ const newCoatRoughness = await LerpTexturesAsync("newCoatRoughness (" + this._material.name + ")", CreateTextureWithFactorOperand(this.specularRoughnessTexture, new Color4(this.specularRoughness, this.specularRoughness, this.specularRoughness, 1.0), TextureChannel.G), CreateTextureWithFactorOperand(this.coatRoughnessTexture, new Color4(this.coatRoughness, this.coatRoughness, this.coatRoughness, 1.0), TextureChannel.G), CreateTextureWithFactorOperand(origCoatWeightTexture, origCoatWeightCol4, TextureChannel.R), this._material.getScene());
1216
+ if (signal.aborted) {
1217
+ newCoatRoughness.texture?.dispose();
1218
+ return;
1219
+ }
1220
+ this.coatRoughness = newCoatRoughness.factor ? newCoatRoughness.factor.r : 1.0;
1221
+ this.coatRoughnessTexture = newCoatRoughness.texture;
1222
+ const newCoatDarkening = await LerpTexturesAsync("newCoatDarkening (" + this._material.name + ")", CreateTextureWithFactorOperand(null, new Color4(0, 0, 0, 1.0), TextureChannel.R), CreateTextureWithFactorOperand(null, new Color4(this.coatDarkening, this.coatDarkening, this.coatDarkening, 1.0), TextureChannel.R), CreateTextureWithFactorOperand(origCoatWeightTexture, origCoatWeightCol4, TextureChannel.R), this._material.getScene());
1223
+ if (signal.aborted) {
1224
+ newCoatDarkening.texture?.dispose();
1225
+ return;
1226
+ }
1227
+ this.coatDarkening = newCoatDarkening.factor ? newCoatDarkening.factor.r : this.coatDarkening;
1228
+ if (diffuseTransmission) {
1229
+ const newSpecularRoughness = await LerpTexturesAsync("newSpecularRoughness (" + this._material.name + ")", CreateTextureWithFactorOperand(this.specularRoughnessTexture, new Color4(this._material.specularRoughness, this._material.specularRoughness, this._material.specularRoughness, 1.0), TextureChannel.G), CreateTextureWithFactorOperand(null, new Color4(1, 1, 1, 1.0), TextureChannel.R), CreateTextureWithFactorOperand(weightTexture, weightCol4, weightTextureChannel), this._material.getScene());
1230
+ if (signal.aborted) {
1231
+ newSpecularRoughness.texture?.dispose();
1232
+ return;
1233
+ }
1234
+ this.specularRoughness = newSpecularRoughness.factor ? newSpecularRoughness.factor.r : 1.0;
1235
+ this.specularRoughnessTexture = newSpecularRoughness.texture;
1236
+ }
1237
+ if (origCoatNormalTexture || this.geometryNormalTexture) {
1238
+ const newCoatNormal = await LerpTexturesAsync("newCoatNormal (" + this._material.name + ")", CreateTextureWithFactorOperand(this.geometryNormalTexture, this.geometryNormalTexture ? new Color4(1, 1, 1, 1) : new Color4(0.5, 0.5, 1.0, 1.0), TextureChannel.RGBA), CreateTextureWithFactorOperand(origCoatNormalTexture, origCoatNormalTexture ? new Color4(1, 1, 1, 1) : new Color4(0.5, 0.5, 1.0, 1.0), TextureChannel.RGBA), CreateTextureWithFactorOperand(origCoatWeightTexture, origCoatWeightCol4, TextureChannel.R), this._material.getScene());
1239
+ if (signal.aborted) {
1240
+ newCoatNormal.texture?.dispose();
1241
+ return;
1242
+ }
1243
+ if (newCoatNormal.texture) {
1244
+ this.geometryCoatNormalTexture = newCoatNormal.texture;
1092
1245
  }
1093
1246
  }
1094
1247
  }